:GetNetworkPing() being inconsistent, and what formula should I use for compensating lag?

Basically I am writing a lag compensator for server sided hitboxes, I have written the code that logs every server tick the position of all players inside a dictionary and then the server can be asked to render the positions and raycast with a whitelist including the game world and the rewound positions.

So a thing I need to do for this to work is calculating when was the original request fired from the client’s perspective, so for this we can use ping for calculating this but theres a few issues im having

1 :GetNetworkPing() always returns the same
to test my system i used a system where you press E, and uses time() to log the time where you pressed E then when you press E it fires up the server and logs the time the request got to the server, then the server runs this function

function LagCompensator.CompensateRequestTime(Player)
	local CurrentTime = time()
	
	local CurrentPing = Player:GetNetworkPing()
	print("Player's Ping", CurrentPing *1000, "ms")
	
	local OriginalRequestTime = CurrentTime - (CurrentPing * 2)
	
	return OriginalRequestTime
end

then returns the stats in a table for the client and displays them in a GUI
image

also the server displays the ping but heres where the issue is
I fired the thing various times and you can see how the ping is always the same???
image
this makes no sense considering on studio i can see the ping always changing since ping is never consistent, I get that these are different pings one is trip from client to server to client, but one is server to client to server but these still should not stay the same.

2 Ping is making 0 sense
My ping currently is under 100 ms meaning logically a request should take less than 0.1 seconds to arrive to the server via a remote event. yet theres times where somehow it takes almost 2 seconds to arrive
image
this makes 0 sense

3 :GetNetworkPing() itself is inacurrate
Here we can see the request process
image
but if my ping is 57 how is it taking 0.6 seconds for my request to get to the server, it should take arround 0.05 seconds.

If anyone can explain to me why most of these things are happening it would be appreciated.
Also these tests were not ran in studio, they were done in game

1 Your method uses a custom way to messure ping which could be unsafe
Now the reason why I decided to use :GetNetworkPing() is because im assuming it is not easy to exploit considering it must be messuring ping itself in the way roblox sends and recieves packets in its core code

Its not hard for an exploiter to spoof the function so it takes longer to arrive and fake higher ping, while moving and having a smooth network.

2 math.floor() will round things which we dont want to when being accurrate
3 This isnt an order of operations issue

function LagCompensator.CompensateRequestTime(Player)
	local CurrentTime = time()
	
	local CurrentPing = Player:GetNetworkPing()
	print("Player's Ping", CurrentPing *1000, "ms")
	
	local OriginalRequestTime = CurrentTime - CurrentPing
	
	return OriginalRequestTime
end

the reason why I dont divide ping 1k times is because the time() function works in seconds and not miliseconds and roblox states :GetNetworkPing() messures it in seconds.

You’re gonna have to trust the client and let them send :GetServerTimeNow() to get an accurate time, and then just clamp the difference (ping) to not be above say 1 second.

A client can always lag switch by simply refusing to send signals to a server for a period of time. You will need to trust the client at some point…

I am aware, thats why I discovered ping is actually unreliable for these systems you instead use the server time by sending every tick to all clients, I think roblox already does this with :GetServerTime() and you use a whole lot of other things

My solution was chickynoid it has a module inside called antilag which solves lag compensation issues

Also lag compensation is not possible with roblox’s replication due to their huge annoying buffer, you must use custom replication which can be done by very hacky methods, but I just ended up using chickynoid.

Fast replicator in tc2 (for :nerd_face: only lol idk) - YouTube

1 Like

Hello.

Most of the lag-compensation algorithms out there are really bad. Invoking a RemoteFunction is something that you should always avoid. Use a RemoteEvent to send a signal to the player and once the player receives it, send it back to the server with the information that was passed.

-- Server Code
local pings = {}
local deltas = {}

local pingRate = 0.1 -- Chose whatever, but 100ms is already a good way to approximate.
local nextPing = tick()

RemoteEvent.OnServerEvent:Connect(function(player, sentTick, clientTick)
    local averageTripTime = (tick() - sentTick)/2
    local estimatedArrivalTick = sentTick + averageTripTime
    pings[player] = averageTripTime
    deltas[player] = clientTick - estimatedArrivalTick
end)

PlayerService.PlayerRemoving:Connect(function(player)
    pings[player] = nil
    deltas[player] = nil
end)

RunService.Stepped:Connect(function()
    local time = tick()
    if nextPing < time then
        nextPing = time + pingRate
        RemoteEvent:FireAllClients(time)
    end
end)

-- Client Code
RemoteEvent.OnClientEvent:Connect(function(sentTick)
    RemoteEvent:FireServer(sentTick, tick())
end)

If you now want to compensate for the lag, the player’s delta will tell you how far from the server’s clock the player is. To figure out the tick on the client, you can simply add the delta to the server’s current timestamp:

-- Server Code
local function getPlayerTick(player, time)
    return time + (deltas[player] or 0)
end

If something happens at a time t in the server, it will happen simultaneously on a client p at getPlayerTick(p, t).

Best regards,
Octonions

5 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.