Skip to content

Commit 870452b

Browse files
fix: more accurate local time sync with server time (up-port) (#3212)
* get a more accurate local time by using half the RTT. * test Adjusting ClientNetworkTimeSystemTests to account for half RTT adjustment applied in this PR. * style Adding a comment about the change * update Adding changelog entry * style removing white space after comment --------- Co-authored-by: CTHULHU\Ben <[email protected]>
1 parent 1249843 commit 870452b

File tree

3 files changed

+35
-25
lines changed

3 files changed

+35
-25
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1212

1313
### Fixed
1414

15+
- Changed the `NetworkTimeSystem.Sync` method to use half RTT to calculate the desired local time offset as opposed to the full RTT. (#3212)
1516
- Fixed issue where a spawned `NetworkObject` that was registered with a prefab handler and owned by a client would invoke destroy more than once on the host-server side if the client disconnected while the `NetworkObject` was still spawned. (#3200)
1617

1718
### Changed

com.unity.netcode.gameobjects/Runtime/Timing/NetworkTimeSystem.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ public void Sync(double serverTimeSec, double rttSec)
248248
var timeDif = serverTimeSec - m_TimeSec;
249249

250250
m_DesiredServerTimeOffset = timeDif - ServerBufferSec;
251-
m_DesiredLocalTimeOffset = timeDif + rttSec + LocalBufferSec;
251+
// We adjust our desired local time offset to be half RTT since the delivery of
252+
// the TimeSyncMessage should only take half of the RTT time (legacy was using 1 full RTT)
253+
m_DesiredLocalTimeOffset = timeDif + (rttSec * 0.5d) + LocalBufferSec;
252254
}
253255
}
254256
}

com.unity.netcode.gameobjects/Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs

+31-24
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@ internal class ClientNetworkTimeSystemTests
1818
public void StableRttTest()
1919
{
2020
double receivedServerTime = 2;
21-
22-
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, 0.1d);
21+
var baseRtt = 0.1f;
22+
var halfRtt = 0.05f;
23+
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, baseRtt);
2324
timeSystem.Reset(receivedServerTime, 0.15);
2425
var tickSystem = new NetworkTickSystem(60, timeSystem.LocalTime, timeSystem.ServerTime);
2526

2627
Assert.True(timeSystem.LocalTime > 2);
2728

28-
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
29-
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, 0.095f, 0.105f, 42); // 10ms jitter
29+
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, baseRtt, 42);
30+
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, baseRtt - 0.05f, baseRtt + 0.05f, 42); // 10ms jitter
3031

3132
// run for a while so that we reach regular RTT offset
3233
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
@@ -37,10 +38,11 @@ public void StableRttTest()
3738
});
3839

3940
// check how we close we are to target time.
40-
var expectedRtt = 0.1d;
41-
var offsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
41+
var offsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - halfRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
4242
Debug.Log($"offset to target time after running for a while: {offsetToTarget}");
43-
Assert.IsTrue(Math.Abs(offsetToTarget) < k_AcceptableRttOffset);
43+
44+
// server speedup/slowdowns should not be affected by RTT
45+
Assert.True(Math.Abs(offsetToTarget) < k_AcceptableRttOffset, $"Expected offset time to be less than {k_AcceptableRttOffset}ms but it was {offsetToTarget}!");
4446

4547
// run again, test that we never need to speed up or slow down under stable RTT
4648
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
@@ -51,9 +53,10 @@ public void StableRttTest()
5153
});
5254

5355
// check again to ensure we are still close to the target
54-
var newOffsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
56+
var newOffsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - halfRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
5557
Debug.Log($"offset to target time after running longer: {newOffsetToTarget}");
56-
Assert.IsTrue(Math.Abs(newOffsetToTarget) < k_AcceptableRttOffset);
58+
// server speedup/slowdowns should not be affected by RTT
59+
Assert.True(Math.Abs(offsetToTarget) < k_AcceptableRttOffset, $"Expected offset time to be less than {k_AcceptableRttOffset}ms but it was {offsetToTarget}!");
5760

5861
// difference between first and second offset should be minimal
5962
var dif = offsetToTarget - newOffsetToTarget;
@@ -67,13 +70,14 @@ public void StableRttTest()
6770
public void RttCatchupSlowdownTest()
6871
{
6972
double receivedServerTime = 2;
70-
71-
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, 0.1d);
73+
var baseRtt = 0.1f;
74+
var halfRtt = 0.05f;
75+
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, baseRtt);
7276
timeSystem.Reset(receivedServerTime, 0.15);
7377
var tickSystem = new NetworkTickSystem(60, timeSystem.LocalTime, timeSystem.ServerTime);
7478

75-
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
76-
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, 0.095f, 0.105f, 42); // 10ms jitter
79+
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, baseRtt, 42);
80+
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, baseRtt - 0.05f, baseRtt + 0.05f, 42); // 10ms jitter
7781

7882
// run for a while so that we reach regular RTT offset
7983
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
@@ -102,11 +106,14 @@ public void RttCatchupSlowdownTest()
102106

103107
// speed up of 0.1f expected
104108
Debug.Log($"Total local speed up time catch up: {totalLocalSpeedUpTime}");
105-
Assert.True(Math.Abs(totalLocalSpeedUpTime - 0.1) < k_AcceptableRttOffset);
106-
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset); // server speedup/slowdowns should not be affected by RTT
109+
var expectedSpeedUpTime = Math.Abs(totalLocalSpeedUpTime - halfRtt);
110+
var expectedServerSpeedUpTime = Math.Abs(totalServerSpeedUpTime);
111+
Assert.True(expectedSpeedUpTime < k_AcceptableRttOffset, $"Expected local speed up time to be less than {k_AcceptableRttOffset}ms but it was {expectedSpeedUpTime}!");
112+
// server speedup/slowdowns should not be affected by RTT
113+
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset, $"Expected server speed up time to be less than {k_AcceptableRttOffset}ms but it was {expectedServerSpeedUpTime}!");
107114

108115

109-
// run again with RTT ~100ms and see whether we slow down by -0.1f
116+
// run again with RTT ~100ms and see whether we slow down by -halfRtt
110117
unscaledLocalTime = timeSystem.LocalTime;
111118
unscaledServerTime = timeSystem.ServerTime;
112119

@@ -121,13 +128,13 @@ public void RttCatchupSlowdownTest()
121128

122129
totalLocalSpeedUpTime = timeSystem.LocalTime - unscaledLocalTime;
123130
totalServerSpeedUpTime = timeSystem.ServerTime - unscaledServerTime;
124-
125-
// slow down of 0.1f expected
131+
// slow down of half halfRtt expected
126132
Debug.Log($"Total local speed up time slow down: {totalLocalSpeedUpTime}");
127-
Assert.True(Math.Abs(totalLocalSpeedUpTime + 0.1) < k_AcceptableRttOffset);
128-
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset); // server speedup/slowdowns should not be affected by RTT
129-
130-
133+
expectedSpeedUpTime = Math.Abs(totalLocalSpeedUpTime + halfRtt);
134+
expectedServerSpeedUpTime = Math.Abs(totalServerSpeedUpTime);
135+
Assert.True(expectedSpeedUpTime < k_AcceptableRttOffset, $"Expected local speed up time to be less than {k_AcceptableRttOffset}ms but it was {expectedSpeedUpTime}!");
136+
// server speedup/slowdowns should not be affected by RTT
137+
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset, $"Expected server speed up time to be less than {k_AcceptableRttOffset}ms but it was {expectedServerSpeedUpTime}!");
131138
}
132139

133140
/// <summary>
@@ -172,8 +179,8 @@ public void ResetTest()
172179
receivedServerTime += steps[step];
173180
timeSystem.Sync(receivedServerTime, rttSteps2[step]);
174181

175-
// after hard reset time should stay close to rtt
176-
var expectedRtt = 0.5d;
182+
// after hard reset time should stay close to half rtt
183+
var expectedRtt = 0.25d;
177184
Assert.IsTrue(Math.Abs((timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec) < k_AcceptableRttOffset);
178185

179186
});

0 commit comments

Comments
 (0)