*DO NOT USE* High precision clock syncing tech between clients and server with accuracy of <1ms

Line 95 should subtract self.ReceiveTick not currentTick. It’s also slightly more accurate to calculate tick() directly in the remote event call. You can observe the former (and have some trouble observing the latter because Luau is so fast :heart_eyes: ) by seeing on the client in Studio Play mode that math.abs(module:GetTime()-tick()) is smaller. The difference with the line 95 bug is especially noticeable if you stably artificially lower the frame rate:

local targ=10
local t0=0
_G'bindtorenderstep'(-2^32,function()
	t0=os.clock()
end)
_G.stepped:bind(function()--do it on stepped not heartbeat so no race condition with module:Heartbeat
	repeat until os.clock()-t0>1/targ
end)

Also, tick() is going to be deprecated, and the equivalent is os.clock(), so should probably switch to that.


Have you ever run into issues with the time being able to decrease (due to resyncing)?—seems like this might have sneaky bugs. Why did you decide not to eventually stop resyncing (to solve the previous question’s problem)?

Also, do you get <1ms in your games? Maybe my networking just sucks XD

This module is really awesome

For anyone lately interested in a formal comparison of where this should be used, I simulated two five-amperage sin function platforms with TimeSync and this, clear and opaque studded platform respectively:

Edit I: Clarification: The far platforms are default replication. Note the clock models “lead” because lack passive replication delay.

Video:


(Note the glass platform actually often leading in this case; Quenty’s is slightly overshooting here, which is counter-intuitive.)


Measurements:


TimeSync:
Send 0.7kb/s
Receive 0kb/s


Fluffmiceter’s:
Send 2.1kb/s
Receive 2.0kb/s


(this is over the receive .1kb/s background radiation)


Heed:

Personally, I do not believe you should be concerned about this. When a popular game like Natural Disaster Survival can average 70kb/s send and 140kb/s receive, the in-topic discussions concerning large playercounts making this inapplicable is wrong from my understanding. The old 50kb/s recommendation was per player, and has far been exceeded in just a few years. I take advantage of this in my own games, smoothly running 100kb/s receive and near equal send with all device support.

tl;dr: they are useful and support diverse usecases, but with one Fluff clock you can have slow platforms but also superior visualization of exceptionally fast bullet replication, beyond the scope of TimeSync which AFAIK is the runner up.

4 Likes

I needed some high precision clock syncing between every client and the server, and this is perfect!
It requires close to no setup and is pretty much a drop-in replacement for os.clock() or tick().

Can highly recommend!
Thank you for releasing this great module for free!

2 Likes

Thank you so much! I initially wanted to use Quenty’s module, but I did not want to import the entire Nevermore framework to only use one module. This is all I wanted. By the way, I gave you a star on GitHub to support your work.

2 Likes

Exactly how I intend people to use it! Most of my logic is timed based off of tick(), so I intentionally wrote this so it can be a simple replacement, no additional logic needed.

1 Like

I’m confused as to what is going on in your visualization. The whole point of time syncing is to synchronize an event or movement on multiple clients and the server, but your demonstration is only showing what one client sees.

1 Like

Instead of calculating how many things are added to workspace every frame you can use Stats to check the Physics and game Data receive and send rate in kbps: Stats | Roblox Creator Documentation

4 Likes

I was not aware of that. That is really helpful!

Works awesome for projectiles! Thanks so much!

Some people, including me, are asking for a license, for legal reasons. Could you please add one to the GitHub?

This is a really useful module (and very clever implementation), but I think it’s time for it go soon with the addition of workspace:GetServerTimeNow() (coming soon based on the release notes).

4 Likes

Wow, that is awesome! It is flattering to think that Roblox recognizes the same problem that I saw and sought to provide an in-engine solution to it. As said in that post’s replies, the naive approach of taking round trip time of a remote and dividing by two is highly inaccurate because of the behavior of the packet buffer as it processes outgoing and incoming remotes. This is the exact thing that my module tries to account for, meaning that if Roblox engineers acknowledge this same issue, then it is very likely that their solution has a high level of accuracy :open_mouth:

6 Likes

I am late here but just so I understand correctly. You are syncing the client and server clock and you are able to estimate a replication delay with some calculations. With this delay you can offset the server part (or if you trust the server, interpolate the client back). What I am interested to know is how ‘getservertimenow()‘ will substitute your module. Is it because the time elapse is in milliseconds instead of seconds as in tick()

That documentation is incorrect. The function is, as far as I’m concerned, supposed to return seconds.

How will the new function be any better than tick() or os.time(). They both return seconds and asynchronized also I believe meaning that server and client wont be synched.

1 Like

GetServerTimeNow is designed to solve the exact same problem that my module solves. The function, when called at the exact same instant on the client and server, should in theory return the same number (in seconds). I have no clue what you are asking.

1 Like

My game just periodically checks the round trip time (with an increasing delay between checks), and uses the new result if it had faster ping than the current result. Is there any reason to use an average?

I assume you looked into my code and saw the averaging step. I put that there because the offset between the client tick() and server tick() should be a fixed unknown. The goal of the module is to do as best of a guess at this value as possible, so sudden movements in the value are highly undesirable.

Anyways, Roblox is thankfully releasing a much better in-engine solution to this problem so I personally will be moving my projects to that once it is out, and closing down this post.

1 Like

Hey @Fluffmiceter! I’m still unsure on whether I should continue using this module, or Roblox’s new solution. Have you ran any benchmarks to see the difference in accuracy for both the solutions?

1 Like

I did some benchmarking and the new Roblox API was surprisingly unremarkable. Its performance was comparable to the Quenty clock. Because the in-engine solution is likely to be reliable for many years, I still recommend you to use that, but for my own projects, I still use my own module due to its much better precision.

2 Likes