Laggy players can't register weapon hits, best way to get around without "trusting the client"

My weapons rely mostly on the server, using client for hit detection. However if a player has say 250+ ms ping, then there is a good chance that the server won’t be able to validate the hit because:

Pseudocode for the tool would sort of like this:

Swing Function:

CanSwing = true
RemoteEvent:FireClient(Player,"Slash")
wait(1)
CanSwing = false

Hit Function:

if CanSwing then
hitPerson:TakeDamage(whatever)
CanSwing = false

Recieve:

RemoteEvent.OnServerEvent:Connect(function(Player)
if not canDo() then return end
if wants to to swing then
Swing Function
if wants to hit then
Hit Function

If the player is laggy, then they won’t be able to hit others because the CanSwing has already been set to false in the time they lagged, even if they’re sure they hit someone on their screen.

What is the best way to get around this without trusting the client enough for an exploiter or a lag switcher to cause problems, or in general someone really laggy?

2 Likes

You might want to check out this raycast module its really good for scripting weapons:

It looks like you are doing hit detection on the server then firing the client who was hit? I don’t think I’m understanding your method correctly. Regardless, here’s how I would do it:

  • register all hits on the client who is swinging the melee
  • once player hits someone (on their client,) send only the player who you hit to the server.
  • server receives the hit information, check if (p1.Position - victim.Position).Magnitude is within the (weapon range + margin of error to account for lag). If the hit request is within distance, the server deals out the damage.

The perk of client hit detection is:

  • client can simulate instant hit feedback to hide the actual client>server lag
  • since the server only verifies the distance, the player can hit someone on their client regardless of whether the hit was legitemate on the server; as long as the hit is within distance to be believeable then the server deals out the damage anyways and nobody is the wiser.
  • legitemate hit requests from non-laggy players will be within the margin of error, non legitemate requests can only exploit the small margin of error (maybe 4 studs) which isn’t very powerful or game changing.
  • makes laggy players feel less laggy

Cons:

  • one player may see the swing totally miss them while the one who swung it saw it as a perfect hit. (this wont be too often or too large of a distance)

Your server based cooldown isn’t a good idea in my opinion (if used for security purposes). There will always be lag; a server based cooldown system doesn’t account for this whatsoever. Ultimately it will ruin the game experience for laggy players more than it will stop exploiters from ruining the game. Even if they do spam your remote, they can only do so within the bounds of your weapon’s range which, when compared to ruining the laggy player’s experience, isn’t a good tradeoff.

8 Likes

There is not an easy solution to this problem and there are multiple solutions that have different results. Accounting for ping is dangerous because players can spoof ping and get hits by reducing their ping artificially. The way I would solve this issue is by first trying to reduce network usage. Roblox can communicate with the client at 50 kbps. Any data over this gets queued. That’s roughly ~853 bytes per network frame (tied to fps). Sending more than 50 kbps (not including physics) of data will cause the player’s ping to linearly increase over time. Sending more than 50 kbps for long periods of time will result in the player’s ping getting up to several full seconds.

Next I would probably take a range of hit checks based on the player’s previous positions. 0.25 seconds is probably plenty to account for ping which is exactly 15 frames. So I would do hit detection for the previous 15 Heartbeats (or less) and based on the player’s ping reduce this amount.

2 Likes

Best method is to just do client-hit detection for UI updates, and then have the server fully check for hit damage. Assuming this is a sword, just use .Touched on the server. For ROBLOX stock player movement (and using simple swords), you can just rely on their own latency compensation system.

I did say at the start I am using client for hit detection. You’re not understanding my problem. My problem is that laggy players cannot get hits at all, because of the server cooldown window being closed by the time it receives the event. What is the best way to get around this?

I have already transfered my melee system to using raycasting. The average ping with about 20 players is roughtly like 200.

A server-based cooldown system will never be able to account for lag unless the cooldown is based on the player’s ping which is not a brilliant idea anyway. Based on the current system, at least from what has been shown, the hit event isn’t secure without checking the distance between the player’s character and the player who the character is claiming to hit. Meaning you can essentially slash the air in front of you and kill everybody in the server.

The way I would go about it, is using a ping function to calculate the individual player’s ping, and store a cache of every player character position on the server for the last second, then when you want to validate a hit, you look back in the position cache based on the player’s ping and work out the distance and validate it. Player’s > 1000ms ping are not going to have the greatest experience on any game, and for a variety of reasons, validation included, is why other games don’t allow for such a high ping.

If you don’t want people spamming your remotes, then based on the attack rate of the weapon, implement a validation check the other way around; Assuming you store a timestamp of when they last attacked using tick() compare the difference. Assuming you store a timestamp (using tick()) of when they last attacked, compare that value to the time now (lastHit - tick()) and check if that exceeds your attack rate. You should implement a margin of error in this to account for lag, or using the Ping function if you use the idea above, offset the current time by their ping (tick() + playerPing)

If you want people with a ping > 1000ms to play, increase the cache, but visually for the player being hit, this will look strange.

2 Likes