How do I accurately measure ping?

Hello,
I was wondering if anybody here knew how to measure a player’s ping accurately. All help would be appreciated!

EDIT: The actual script is in Reply #1, but I made a simple order of operations error which was solved in Reply #14

An easy way to do this is to set up a RemoteFunction that just returns immediately. You then measure the time it took to get a response:

-- Server:
local rf = Instance.new("RemoteFunction")
rf.Name = "Ping"
rf.Parent = game:GetService("ReplicatedStorage")
rf.OnServerInvoke = function() end
-- Client:
local pingRf = game:GetService("ReplicatedStorage"):WaitForChild("Ping")
local start = time()
pingRf:InvokeServer()
local ping = (time() - start)
-- 'ping' is in seconds. Multiply by 1000 if you want milliseconds.

If you need the server to track player ping, don’t do this in reverse using InvokeClient (InvokeClient is evil). Instead, have the client fire a RemoteEvent with the ping. The server can listen to that RemoteEvent and store the player’s ping somewhere.


Some other tips:

  • Wrap all of that in a function on the client and call it every second or so (doesn’t have to be too often)
  • If you want to calculate the time it takes to go from ClientA → Server → ClientB, simply add up the ping of both ClientA and ClientB and divide by 2.
6 Likes

Thanks! I’ll check it out. (Also, hi sleitnick!)

@sleitnick I’m not as familiar with the time() function. Does it return as accurate a time as tick()? I know tick() measures a very accurate time (within thousandths of a second) . Although these times can differ between server and client, this is not a problem in this case.

Also, @BasicBan, you would probably want to evaluate some sort of average for a more accurate idea of what the ping is like for a specific client.

tick() returns the amount of time in seconds since the UNIX epoch. time() returns the amount of time the current Roblox session has been running. (server or client depending on who calls the function)

2 Likes

time() is basically tick() offset from the time the server started. Considering that tick() may be deprecated in the near future, time() is preferred. You could also use os.clock(), but that’s better for benchmarking.

1 Like

does tick() return the same value as time() on server?

When i multiply it my 1000, it just turns into like 7859.48578297923748 and if I use math.floor() it just turns into 7859 and increases by my actual amount of ping (which is 2000, don’t question it lol). (I know it is inaccurate because i checked the average ping in the f9 console and it was nothing even close to that.)

i think i know the issue, its because you only run it once when the player joins, and i think there is some lag when the player just joins, try adding a wait before it or insert it into a loop

It was already in a while wait(1) loop

Can I see the full local script?

wait(5)
while wait(1) do
local start = time()
script.Ping:InvokeServer()
local ping = (time() - start*1000)
	script.Parent.Text = "Ping: "..math.floor(ping).. "ms"
end
1 Like

Looks like an order of operations issue.

wait(5)
while wait(1) do
local start = time()
script.Ping:InvokeServer()
local ping = ((time() - start)*1000)
	script.Parent.Text = "Ping: "..math.floor(ping).. "ms"
end
8 Likes

Thank you! I didn’t notice that, you are a real lifesaver!

Why is InvokeClient evil? Bad paradigm or bad technically?

1 Like

Its cause in general you want to follow a server side authentication model, and invoke client kinda defeats the point

If a player disconnects in the middle of an InvokeClient call, the server script that called it will hang because there’s no longer a client to send the response.

3 Likes