So, I've been trying to track down a tiny desync issue between my client and server for a long time now, and I think I finally confirmed it. I just want to bounce my thoughts off the forum and see if it all makes sense.
The issue was manifesting as a drift at a rate of ~50ms per 10min. It wasn't consistent though, and seemed to change depending on what machines I used and what the network conditions were. The only times I would have 0 drift was in testing on localhost, and testing against 1 particular friend's machine (same gen cpu as mine).
I knew that I was well within the realm of cpu variance, but I had a blind spot in my thinking because “I'm dividing the high resolution timer count by the reported frequency, surely it's fine”. Thus, I spent a long time doing all sorts of tweaks to my netcode and testing in various conditions.
Finally, I made two tiny test apps. One connects to the other, then sends a start byte and starts a timer. After X seconds, it sends an ends byte. The other side runs a timer during this period, and both sides report the measured time.
Clock test results
Local:
60s:
Client: 60.00091s
Server: 60.00090s
600s:
Client: 600.00012s
Server: 600.00011s
Local client, remote server:
10s:
Client: 10.00171s
Server: 10.00149s
60s:
Client: 60.00016s
Server: 60.00595s
600s:
Client: 600.00153s
Server: 600.05837s
1200s:
Client: 1200.00054s
Server: 1200.11834s
As you can see, it doesn't occur when ran on the same machine, and it scales pretty linearly when ran against the remote, so it is seems fair to say that it isn't due to network effects.
Q1: Is it fair to say that my issues come from variance in reported time between machines?
If so, instead of letting my catch-up algorithm detect that the client is 2 ticks behind and jumping it back forward every 15min, I'd like to have the client move into line with the server's clock rate.
Q2: How can I best do this? Should I just measure the time between received messages, compare it to the server's network tick rate, and adjust the client tick rate using a leaky integrator? Or should I do something more sophisticated?