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
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???
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
this makes 0 sense
3 :GetNetworkPing() itself is inacurrate
Here we can see the request process
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.
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.
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).