How would I approach checking to make sure there is no parts between killer/victim for a gun to do dmg

Hey there! I recently implemented some new guns - our previous two systems had a security check for this exploit, however with no longer having the same developers I had when those guns were implemented. I’m seeking help from the lovely devforum community to help me fix this exploit ASAP.

Essentially (as seen in images) - an exploiter is able to fire the remoteevent and kill every player in the server - even if there are parts in between them

I’m currently working on a kill log system as we speak for my staff team (seeing they are online 24/7)

Serverside code that handles remote event

local FireEvent = Instance.new("RemoteEvent",game.ReplicatedStorage)
FireEvent.Name = "GunEvent"
local SprintEvent = Instance.new("RemoteEvent",game.ReplicatedStorage)
SprintEvent.Name = "SprintEvent"
local BulletEvent = Instance.new("RemoteEvent",game.ReplicatedStorage)
BulletEvent.Name = "BulletEvent"

local bulletHolder = Instance.new("Folder")
bulletHolder.Name = "Bullets"
bulletHolder.Parent = workspace

local killer

local debris = game:GetService("Debris")

function tagHumanoid(humanoid)
	local creator_tag=Instance.new("ObjectValue")
	creator_tag.Value=killer
	creator_tag.Name="creator"
	debris:AddItem(creator_tag,3)
	creator_tag.Parent=humanoid
end

SprintEvent.OnServerEvent:Connect(function(client, speed)
	if client.Character:FindFirstChildOfClass("Tool") then
		client.Character.Humanoid.WalkSpeed = speed
	end
end)

BulletEvent.OnServerEvent:Connect(function(client, position, partHit, surfaceDirection)

	local Cross = Vector3.new(0, 1, 0):Cross(position)
	local Thing = math.asin(Cross.magnitude) -- division by 1 is redundant
	
	local bulletHole = Instance.new("Part")
	bulletHole.Size = Vector3.new(0.2,0.2,0.2)
	bulletHole.Position = position
	bulletHole.BrickColor = BrickColor.new("Really black")
	bulletHole.Anchored = true
	bulletHole.CanCollide = false
	bulletHole.Parent = bulletHolder

	local bulletSound = game.ReplicatedStorage.GunStorage.Impact:Clone()
	bulletSound.Parent = bulletHole
	bulletSound.PlayOnRemove = true
	game:GetService("Debris"):AddItem(bulletHole, 0.05)
	
end)

FireEvent.OnServerEvent:Connect(function(client, humanoid, damage)
	if humanoid and humanoid.Parent and game.Players:GetPlayerFromCharacter(humanoid.Parent) then
		--print(client, humanoid.Parent, damage)
		humanoid.Health = humanoid.Health - damage
		killer = client
		tagHumanoid(humanoid)
		local killerlog = killer.Name
		local victim = humanoid.Parent
		local victimlog = victim.Name
		print (killerlog)
		game.StarterGui.Kills.Enabled = true
		game.StarterGui.Kills.Frame.Killer.Text = killerlog
		game.StarterGui.Kills.Frame.Victim.Text = victimlog
		wait (5)
		game.StarterGui.Kills.Enabled = false
		local hitSound = Instance.new("Sound")
		hitSound.SoundId = "rbxassetid://3261922787"
		hitSound.Parent = humanoid.Parent.Head
		hitSound:Play()
		game:GetService("Debris"):AddItem(hitSound, hitSound.TimeLength)
	end
end)

Goal: Secure the remote event properly in order to prevent exploiters from abusing it.

Note: I haven’t actually fixed the equipped part yet - but am working on that as we speak, was a bit busy creating the log system (which is faulty as it collects the username per/bullet)

1 Like

Just realized I should have attached the local script

------------------------------------------Gun info
wait(1)
ToolName=script.Parent.Name
damage=16.5
ClipSize=30
ReloadTime=0
Firerate= 0
MinSpread=0.001
MaxSpread=0.0015
SpreadRate=0
Bulletdrop = 0.00001
automatic = true
burst = false
shot = false
patrolling = false
Tool = script.Parent
enabled = true 
local arms = nil
local torso = nil
local weld33 = nil -- right arm
local weld55 = nil -- left arm
local welds = {}

BarrlePos=Vector3.new(0,0,0)
Cursors={"http://www.roblox.com/asset/?id=47894837","rbxassetid://176067512"}
ReloadCursor="rbxasset://textures\\GunWaitCursor.png"

barrel_1  = script.Parent.FirePart

double = false	--Double Wielded 
doublemode = 1 -- 1 is alternating, 2 is both

-------------------------------------
Tool = script.Parent

repeat wait() until Tool.Parent:FindFirstChild("Humanoid")

local toPreload = {}

for _,child in next, Tool:GetChildren() do
	if child:IsA("Animation") then
		table.insert(toPreload, child)
	end
end

for _,child in next, game.ReplicatedStorage.GunStorage:GetChildren() do
	if child:IsA("Animation") then
		table.insert(toPreload, child)
	end
end

local toIgnore = {
	Tool.Parent,
	workspace.Bullets,
}

p = Instance.new("Part")
p.Parent = game.Lighting
p.Name = "BulletTexture"
p.CanCollide = false
p.formFactor = "Custom"
p.Size = Vector3.new(1,0.1,1)
p.Transparency = 1
g = Instance.new("SpecialMesh")
g.Parent = p

run = 0 
equipped=false
dw = false
sp=script.Parent
RayLength=1000
Spread=0.0001
enabled=true
reloading=false
down=false
r=game:service("RunService")
last=0
last2=0
last3=0
last4=0
last5=0
last6=0
UseDouble = false
fireRate = 60/750

function check()
	sp.Name = ToolName
end

function computeDirection(vec)
	return vec.unit
end

-----------------------------------------------------Raycasting functions
raycount = 0

function raycursive(start,dir,ignore)
	raycount = raycount + 1
	if raycount >= 10 then return end
	local random = Vector3.new(math.random(-Tool.Accuracy.Value, Tool.Accuracy.Value),math.random(-Tool.Accuracy.Value, Tool.Accuracy.Value),math.random(-Tool.Accuracy.Value, Tool.Accuracy.Value))
	local newdir = (start+dir)-start-random
	local hitPart,intersectingPoint = workspace:FindPartOnRay(Ray.new(start,newdir.unit*999.999),ignore)
		
	if not intersectingPoint then return end
	if hitPart and not hitPart.CanCollide and (hitPart.Name ~= "Left Arm" and hitPart.Name ~= "Left Leg" and hitPart.Name ~= "Right Arm" and hitPart.Name ~= "Right Leg") then
		return raycursive(intersectingPoint,dir,hitPart)
	else
		return hitPart,intersectingPoint
	end
end

-------------------------------------
local legs = nil
local torso2 = nil
local welds2 = {}
local bodyforce = nil
sprinting = false

function reload(mouse)
	if sprinting == true then return end
	reloading=true
	mouse.Icon=ReloadCursor
	wait(3)
	while sp.Ammo.Value<ClipSize and reloading and enabled do
		wait()
		if reloading then
			sp.Ammo.Value= 30
			local ui = game.Players.LocalPlayer.PlayerGui.GameGui
			ui.GameGui.AmmoFrame.Ammo.Text = sp.Ammo.Value
			check()
		else
			break
		end
	end
	check()
	mouse.Icon=Cursors[1]
	reloading=false
end

------ BEGINNING OF RELOAD_MOB ---------
function reload_Mob()
	if sprinting == true then return end
	reloading=true
	wait(3)
	while sp.Ammo.Value<ClipSize and reloading and enabled do
		wait()
		if reloading then
			sp.Ammo.Value= 30
			local ui = game.Players.LocalPlayer.PlayerGui.GameGui
			ui.GameGui.AmmoFrame.Ammo.Text = sp.Ammo.Value
			check()
		else
			break
		end
	end
	check()
	reloading=false
end

-------- END OF RELOAD_MOB -------------

PatrolAnim = Tool.Parent.Humanoid:LoadAnimation(game.ReplicatedStorage.GunStorage.PatrolAnim)
PatrolAnim.Priority = Enum.AnimationPriority.Action
ReloadAnimation = Tool.Parent.Humanoid:LoadAnimation(script.Parent.ReloadAnim)
ReloadAnimation.Priority = Enum.AnimationPriority.Action

function onKeyDown(key,mouse)
	key=key:lower()
	if key=="r" and not reloading and not sprinting then
		ReloadAnimation:Play()
		ReloadAnimation:GetMarkerReachedSignal("MagOut"):Connect(function()
			script.Parent.Handle.MagOut:Play()
		end)
		ReloadAnimation:GetMarkerReachedSignal("MagIn"):Connect(function()
			script.Parent.Handle.MagIn:Play()
		end)
		ReloadAnimation:GetMarkerReachedSignal("BoltForward"):Connect(function()
			script.Parent.Handle.BoltForward:Play()
		end)
		reload(mouse)
	elseif key == "p" and not reloading then
		if patrolling == false then
			patrolling = true
			enabled = false
			PatrolAnim:Play()
			IdleAnimation:Stop()
		elseif patrolling == true then	
			patrolling = false
			PatrolAnim:Stop()
			enabled = true
			IdleAnimation:Play()		
		end
	end
end

---------------- onButtonPress --------------------------
function onButtonPress(key,mouse)
	key=key:lower()
	if script.Parent.Ammo.Value < 30 then
		wait(0.1) 
		if not reloading and not sprinting then
			ReloadAnimation:Play()
			script.Parent.Handle.Reload:Play()
			reload_Mob()
		end
	end
end

local ContextActionService = game:GetService("ContextActionService")


---------------------- TOTAL END  -------------------
local UIS = game:GetService("UserInputService")

SprintAnim = Tool.Parent.Humanoid:LoadAnimation(game.ReplicatedStorage.GunStorage.SprintAnim)
SprintAnim.Priority = Enum.AnimationPriority.Action

UIS.InputBegan:Connect(function(input, gpe)
	if gpe then return end
	if input.KeyCode == Enum.KeyCode.LeftShift and equipped and not reloading then
		if sprinting == false then
			sprinting = true

			SprintAnim:Play()
			game.ReplicatedStorage.SprintEvent:FireServer(32)
		end
	end
end)

UIS.InputEnded:Connect(function(input,gpe)
	if gpe then return end
	if input.KeyCode == Enum.KeyCode.LeftShift  and equipped and not reloading then
		if sprinting == true then
			sprinting = false
			SprintAnim:Stop()
			game.ReplicatedStorage.SprintEvent:FireServer(16)
		end
	end
end)

function movecframe(p,pos)
	p.Parent=game.Lighting
	p.Position=pos
	p.Parent=game.Workspace
end
fireAnimation = Tool.Parent.Humanoid:LoadAnimation(script.Parent.FiringAnim)
fireAnimation.Priority = Enum.AnimationPriority.Movement


function fire(aim, mouse)
	
	if sprinting then return end
	
	script.Parent.FireFX:FireServer(fireRate)

	t=r.Stepped:wait()

	local startpoint = Tool.FirePart
	
	local totalDist  = 0
	local startpoint = barrel_1.CFrame.p

	local dir=(aim)-startpoint
	dir=dir.unit
	
	local cfrm=CFrame.new(startpoint, dir+startpoint)
	raycount = 0
	local part,position=raycursive(startpoint, cfrm.lookVector * 999)
	
	if part~=nil then
		
		if part.Parent:FindFirstChild("Middle") then
			part = part.Parent	
		elseif part.Parent.className == "Hat" then
			part = part.Parent
		elseif part.Parent.className == "Tool" then
			part = part.Parent
		end
		
		local humanoid= part.Parent:FindFirstChild("Humanoid")
		
		if not humanoid then
			game.ReplicatedStorage.BulletEvent:FireServer(position, part, mouse.TargetSurface)
		end

		if humanoid and part.Parent ~= Tool.Parent and Tool.Equipped == true then
			if part.Name == "Head" and not part.Parent:FindFirstChild("Middle") then
				mouse.Icon = Cursors[2]
				local hitmarkerSound = game.ReplicatedStorage.GunStorage.Hitmarker:Clone()
				hitmarkerSound.Parent = workspace.CurrentCamera
				hitmarkerSound:Play()
				game.ReplicatedStorage.GunEvent:FireServer(humanoid,damage*2)
			elseif part.Name ~= "Head" and not part.Parent:FindFirstChild("Middle") then
				mouse.Icon = Cursors[2]
				local hitmarkerSound = game.ReplicatedStorage.GunStorage.Hitmarker:Clone()
				hitmarkerSound.Parent = workspace.CurrentCamera
				hitmarkerSound:Play()
				game.ReplicatedStorage.GunEvent:FireServer(humanoid,damage)
			elseif part.Parent:FindFirstChild("Middle") and part.Name ~= "Head" then
				mouse.Icon = Cursors[2]
				local hitmarkerSound = game.ReplicatedStorage.GunStorage.Hitmarker:Clone()
				hitmarkerSound.Parent = workspace.CurrentCamera
				hitmarkerSound:Play()
				game.ReplicatedStorage.GunEvent:FireServer(humanoid,damage/2)			
			end
		end
	end	

	if not fireAnimation.IsPlaying == true then
		fireAnimation:Play()
	end

	local deb = game:GetService("Debris")
	check()
	wait(fireRate)
	mouse.Icon = Cursors[1]
end

function onButton1Up(mouse)
	down=false
end

function onButton1Down(mouse)
	
	h=sp.Parent:FindFirstChild("Humanoid")
	if not enabled or reloading or down or h==nil then
		return
	end
	if sp.Ammo.Value>0 and h.Health>0 and h.Jump == false then
		down=true
		enabled=false

		while down and h.Jump == false and h.Health>0 do
			if sp.Ammo.Value<=0 then
				break
			end
			
			Tool.Accuracy.Value = 0.01
	
			automatic = true
					
			mouse.TargetFilter = game.Players.LocalPlayer.Character
	
			sp.Ammo.Value=sp.Ammo.Value-1
			local ui = game.Players.LocalPlayer.PlayerGui.GameGui
			ui.GameGui.AmmoFrame.Ammo.Text = sp.Ammo.Value
			local startpoint=barrel_1.Position
			local mag=(mouse.hit.p-startpoint).magnitude
			local rndm=Vector3.new(math.random(-Tool.Accuracy.Value,Tool.Accuracy.Value), math.random(-Tool.Accuracy.Value,Tool.Accuracy.Value ),math.random(-Tool.Accuracy.Value,Tool.Accuracy.Value))
			fire(mouse.hit.p+rndm, mouse)
			
		wait(Firerate)
	end	
		
		enabled=true
		
	else
		
		wait()
		
	end
end

local aiming = false


IdleAnimation = Tool.Parent.Humanoid:LoadAnimation(script.Parent.IdleAnim)
IdleAnimation.Priority = Enum.AnimationPriority.Movement

function onEquippedLocal(mouse)

if Tool.Parent.Humanoid.SeatPart ~= nil then
	Tool.Parent.Humanoid:UnequipTools()
end

script.Parent.Motor:FireServer("Make")

	enabled = true
	
	local mobilebutton = ContextActionService:BindAction("ReloadButton",onButtonPress,true,"r") 
	ContextActionService:SetPosition("ReloadButton",UDim2.new(0.72,-25,0.20,-25))
	ContextActionService:SetImage("ReloadButton","rbxassetid://3646724203")

IdleAnimation:Play()

local ui = script.GameGui:Clone()
ui.Parent = game.Players.LocalPlayer.PlayerGui
ui.GameGui.AmmoFrame.Title.Text = Tool.Name
	
arms = {Tool.Parent:FindFirstChild("Left Arm"), Tool.Parent:FindFirstChild("Right Arm")}
torso = Tool.Parent:FindFirstChild("Torso")
	if mouse==nil then
		print("Mouse not found")
		return 
	end
	Mouse = mouse
	mouse.Icon=Cursors[1]
	mouse.KeyDown:connect(function(key) onKeyDown(key,mouse) end)
	mouse.Button1Down:connect(function() onButton1Down(mouse) end)
	mouse.Button1Up:connect(function() onButton1Up(mouse) end)
	check()
	equipped=true
	if #Cursors>1 then
		while equipped do
			t=r.Stepped:wait()
			
			wait(Firerate*.9)
		end
	end
end
function onUnequippedLocal(mouse)
	ContextActionService:UnbindAction("ReloadButton")
	if game.Players.LocalPlayer.PlayerGui:FindFirstChild("GameGui") then
		game.Players.LocalPlayer.PlayerGui:FindFirstChild("GameGui"):Destroy()
	end
	IdleAnimation:Stop()
	if PatrolAnim then
		PatrolAnim:Stop()
	end
	if SprintAnim then
		SprintAnim:Stop()
	end
	equipped=false
	reloading=false
end

sp.Equipped:connect(onEquippedLocal)
sp.Unequipped:connect(onUnequippedLocal)
check()

(( yes I realize damage can easily be changed from client - and I can fix that. Just no clue how to fix the current exploit))

1 Like

Main issue here is how the client isable to manipulate the remote by bypassing the entire raycasting and firing the remotes with ridiculous values. It should not be handled this way. In order to mitigate this, you need to handle the entire part of raycasting on server to assure that the exploiter is not firing through impossible places.