This is not how you get ping.
You get ping by getting the local time, asking the client to respond, then checking the difference between the new local time and the saved local time:
local start = tick()
script.PingRemoteFunction:InvokeClient()
local ping = tick() - start
-- you should actually use RemoteEvents instead, but that's too long for an example
There is no way to guarantee that the server and client’s clocks are synced up enough to tell differences in milliseconds. In fact, it’s very likely that the server, client, and all other clients have clock differences of multiple milliseconds, maybe tens of milliseconds, or multiple seconds! It’s not possible to 100% accurately measure the single-trip time.
This is also called round-trip time, because it’s the time it takes for a message to go to and back i.e. a round-trip.
You can’t very accurately change the allowed player velocity according to ping. The most you can do is say “the player could have been moving for as long as their ping time without the server knowing”.
Instead, you should have higher thresholds than the actual speed and up those thresholds some for high ping. For example, have a normal limit/threshold of 20 studs/per second, but with a 1 second ping you up it to 30 per second.
If it’s not clear, you should not have a threshold/limit of 16 studs per second/walkspeed. I noticed in one of your previous posts that you had your threshold set that low. That’s way too close! It’s expected that some exploiters can barely get through with a slight advantage. There will always be an overlap between network latency, player skill, and exploiters. To catch all exploiters, you would also have to catch all high-ping players and high-skill players, which would not be a good thing.
Edit: Example using RemoteEvents
-- server
local pings = {}
game.ReplicatedStorage.PingRemoteEvent.OnServerEvent:Connect(function(player)
local pingInfo = pings[player]
if pingInfo and pingInfo.sent then
pingInfo.received = tick()
pingInfo.ping = math.clamp(pingInfo.received - pingInfo.sent, 0, 5)
pingInfo.sent = nil
end
end)
local function playerAdded(player)
pings[player] = {
ping = 1
}
end
game.Players.PlayerAdded:Connect(playerAdded)
for _, player in next, game.Players:GetPlayers() do
playerAdded(player)
end
game.Players.PlayerRemoving:Connect(function(player)
pings[player] = nil
end)
spawn(function()
while true do
for player, pingInfo in next, pings do
pingInfo.sent = tick()
game.ReplicatedStorage.PingRemoteEvent:FireClient(player)
end
wait(5)
end
end)
local function getPing(player)
return pings[player] and pings[player].ping or 1
end
-- client
game.ReplicatedStorage.PingRemoteEvent.OnClientEvent:Connect(function(player)
game.ReplicatedStorage.PingRemoteEvent:FireServer()
end)