My weapons use client-sided hit detection. How should I go about securing them on the server?

I’ll begin by explaining why I’m using client-sided hit detection: Because latency causes the player’s world state to be slightly behind the server’s world state, server-sided hit detection can feel clunky and unresponsive, especially on high ping. Client-sided hit detection allows for hits to be accurate based on what the player sees, that way hits don’t seem like they’re phasing through other players.

Now, on to my issue. With my weapon’s server script, I’m trying to protect against cooldown bypass exploits, but I’m having a nightmare of a time trying to figure out how to make it work around the challenges presented by latency.

Small note: My weapons use RaycastHitbox. For those of you who are unfamiliar with it, Hitbox.OnHit is basically a .Touched event that can only fire when the hitbox is active, Hitbox:HitStart() activates the hitbox, and Hitbox:HitStop() disables the hitbox.

Client script:

Hitbox.OnHit:Connect(function(p,Humanoid)
	if WeaponFunctions.HitCheck(Main,p,Humanoid) == false then return end --// Just checking if what we hit was a valid target 
	Hitbox:HitStop()
	Main.SignalServer:FireServer("Hit",p)
end)

Main.Activated:Connect(function()
	--// Checking and starting the cooldown (works as the debounce)
	if CooldownManager.GetIsActive:Invoke() == true then return end
	CooldownManager.Register:Fire(CooldownTime)
	wait(0.2)
	Main.SignalServer:FireServer("Activated")
	Hitbox:HitStart()
	wait(0.4)
	Hitbox:HitStop()
end)

Server script:

Main.SignalServer.OnServerEvent:Connect(function(plr,Type,HitPart)
	if Type == "Activated" then
		CanDamage = true
		wait(ToolSettings.Cooldown) --// Waiting the length of the tool's cooldown (1.7 seconds) despite the hitbox only being active for 0.4 seconds; I don't remember why I set it up this way
		CanDamage = false
	elseif Type == "Hit" then

		--// General checks here
		
		if CanDamage == false then
			warn("CanDamage does not equal true")
			return
		end
		CanDamage = false
		
		--// Even more checks and eventually damage infliction here

	end
end)

As seen in the server script, my current solution to cooldown bypasses is the CanDamage boolean, but it isn’t great. CanDamage is sometimes false when the server receives the “Hit” signal , and I have absolutely no idea how exactly to manage the timing in the if Type == "Activated" section of the code. I thought about completely removing CanDamage and hoping my game doesn’t have an exploiter epidemic, but I’m sure it’s obvious why that seems like a bad idea. So yea, I’m pretty lost.

Anyone have any advice and/or ideas on what to do?

PS: No, I’m not going to just rely on Byfron.

3 Likes

Consider running the raycast on the server it will result in terrible hit reg but at least it’ll be more secure

2 Likes

I recommend just not using client in the first place, it’s even worse than server and people will complain about it being broken way more than ServerSided HitReg.

Never, and I mean NEVER use HitReg from clients unless you absolutely have to.

(I speak from experience, don’t ever do this unless its single-player, this mistake ruined a whole gun system and an entire weapon system)

2 Likes

Indeed. Any exploiter can just teleport another’s character (or their heads) cliently and get multiple headshot results.

2 Likes

I’ve seen a few approaches to this problem. One that stuck out to me was simply reducing the cooldown on the server by a few seconds (or milliseconds depending on the value) to compensate for that possible latency. Exploiters will still be able to spam the RemoteEvent faster than an innocent player can but it’s much better than being able to spam it with no cooldown.

2 Likes

In case this is still an issue (or someone else is reading this) and you must have client hit registration you could do a line of sight check (and on limited range weapons a distance check) where you do a raycast from the supposed hit location to the player shooting to make sure they can actually see the player
You can also have the client send the origin point to raycast towards and do a distance check to make sure it’s within 1-2 studs of where the server thinks the origin point is