Need help combatting client-server delay for an anti-cheat!

So, I’m making an anti-cheat to prevent hitbox extenders for a soccer game I’m making, and since I’m using client hit detection and sending the info about the hit to the server, I noticed that there is a significant delay, for example, on my client it appears that the ball would roughly be like 2 studs away from my character, meanwhile on the server when I check it can get up to 16 studs away !!

This is a big problem because it means that exploiters would be able to have 16 studs of reach, obviously I have thought about ways to get around this but a lot of them are very complicated. So is there any way to combat this delay? like a velocity prediction for the ball of some sort? I just need some help on where to get started,

1 Like

I think I may have found a solution to this, using a post I found that talks about predicting a part’s velocity using newton’s law, I found this comment:

This actually gives me very accurate results, only 1-5 studs away from the client’s position which is SO much better.

You could try recording “old” cframes of the soccer ball at a rate of 30 to 60 Hz. Then the cframe the player should be reacting to is their ping time old (Player:GetNetworkPing()). Since the player is also sending their own character cframe, the timing should be ping time old soccer ball and current time character.

I assume you are using an Unrel for the reaction signal.

1 Like

Could you share like a more formatted version of this equation like an example code block If possible? Thanks

local Players = game:GetService("Players")
local RS = game:GetService("RunService")

local SoccerBall = workspace.SoccerBall

local SoccerBallCFrames = {}
local MaxAge = 12 -- 6 frames per 100ms
for i=1,MaxAge do
	SoccerBallCFrames[i] = CFrame.identity
end
RS.Heartbeat:Connect(function()
	-- heartbeat should be final render of the soccer ball's cframe
	-- , which is likely replicated afterwards
	
	-- remove oldest cframe
	table.remove(SoccerBallCFrames, MaxAge)
	
	-- insert at position 1
	table.insert(SoccerBallCFrames, 1, SoccerBall.CFrame)
end)
local function GetSoccerBallCFrame(Player)
	-- ping / 0.2 * 12 + 1
	-- = ping * 60 + 1
	local pos = math.round(Player:GetNetworkPing() * 60 + 1)
	return SoccerBallCFrames[ math.clamp(pos,1,MaxAge) ]
end

-- when you get a reaction signal from a
-- UnreliableRemoteEvent or RemoteEvent(slow)
-- then you check their character cframe and GetSoccerBallCFrame(Player)
1 Like


Thanks, but this doesn’t exactly provide me with the most accurate results, I would consider this to be too large of a distance to be validated as a hit.

Server = green
Client = blue

However, I will say that this is actually really accurate on high pings compared to other solutions Ive tried, unfortunately I’ve tried adjusting the settings but I believe that the gap is just too big when hitting it normally

For some reason, it is more accurate when my ping is higher? (When I tab my game for higher ping, it predicts better?)

How is the reaction signal being sent? Is it an UnreliableRemoteEvent, RemoteEvent, or something else?

1 Like

normal RemoteEvent (charsssssss)

Well my theory only works with UnreliableRemoteEvents. Unless you can somehow figure the delay (which will be higher) from using a normal RemoteEvent.

1 Like


I have converted the class to an unreliable remote event, still brings mostly the same results.

I even tried playing around with some of the settings in the example script you gave me, I can’t get anything better than this unfortunately.

The image above is the results on low ping btw in studio (which is only like 10-20ms)

Like I said, the same thing, on higher ping (when I tab myself and freeze game to simulate high lag) the results are better, its so weird?

1 Like

I want to say that studio isn’t an accurate test.
In Play mode, you get implied character lag I think.


I don’t know about test mode with the seperate server and players windows.

1 Like

Ah, sorry, hold on, let me test in-game :sweat_smile: :sweat_smile:

1 Like

Yeah, I tested in-game, still the same results, nothing interesting that happened.

Overall, I’d agree your system is more precise but it is less accurate than my old solution. I’ll keep trying to adjust any values if it helps, I’m just not sure what to change.

It’s for sure not a bad system, like I said, it is precise and there are not any visuals that appear to be super off

If you want I could privately send you some parts of the scripts in the game.

Yeah it’s hard to tell. If your ping is steady, the theory should work.

Server sends soccer ball cframe → player reacts to the ball → server recieves character cframe and react signal
The cframe the character reacted to is ping time old.

1 Like

Oh, the way my game system works is completely different.

Client detects hit → Client sends the ball instance to server → Server gives network ownership → Client reacts to the ball and applies velocities ect

(I’m not the best with these types of things, so forgive me If I didn’t understand everything completely)