Dramatically improve accuracy of network time

This commit is contained in:
Paul Pacheco 2018-12-27 01:05:03 -06:00
parent 85c7d80099
commit 5c0670dc6a

View File

@ -21,6 +21,10 @@ public static class NetworkTime
static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(10); static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(10);
static ExponentialMovingAverage _offset = new ExponentialMovingAverage(10); static ExponentialMovingAverage _offset = new ExponentialMovingAverage(10);
// the true offset guaranteed to be in this range
private static double offsetMin = Double.MinValue;
private static double offsetMax = Double.MaxValue;
// returns the clock time _in this system_ // returns the clock time _in this system_
static double LocalTime() static double LocalTime()
{ {
@ -73,16 +77,33 @@ internal static void OnServerPing(NetworkMessage netMsg)
internal static void OnClientPong(NetworkMessage netMsg) internal static void OnClientPong(NetworkMessage netMsg)
{ {
NetworkPongMessage pongMsg = netMsg.ReadMessage<NetworkPongMessage>(); NetworkPongMessage pongMsg = netMsg.ReadMessage<NetworkPongMessage>();
double now = LocalTime();
// how long did this message take to come back // how long did this message take to come back
double rtt = LocalTime() - pongMsg.clientTime; double rtt = now - pongMsg.clientTime;
_rtt.Add(rtt);
// the difference in time between the client and the server // the difference in time between the client and the server
// but subtract half of the rtt to compensate for latency // but subtract half of the rtt to compensate for latency
// half of rtt is the best approximation we have // half of rtt is the best approximation we have
double offset = LocalTime() - rtt * 0.5f - pongMsg.serverTime; double offset = now - rtt * 0.5f - pongMsg.serverTime;
_rtt.Add(rtt); double newOffsetMin = now - rtt - pongMsg.serverTime;
_offset.Add(offset); double newOffsetMax = now - pongMsg.serverTime;
offsetMin = Math.Max(offsetMin, newOffsetMin);
offsetMax = Math.Min(offsetMax, newOffsetMax);
if (_offset.Value < offsetMin || _offset.Value > offsetMax)
{
// the old offset was offrange, throw it away and use new one
_offset = new ExponentialMovingAverage(PingWindowSize);
_offset.Add(offset);
}
else if (offset >= offsetMin || offset <= offsetMax)
{
// new offset looks reasonable, add to the average
_offset.Add(offset);
}
} }
// returns the same time in both client and server // returns the same time in both client and server