Skip to content

Commit 4bce448

Browse files
jeffreyrainyPitouGamesShadauxCat
authored
fix: Use Time.unscaledDeltaTime instead of Time.deltaTime as time step (#2187)
* fix: Use Time.unscaledDeltaTime instead of Time.deltaTime as time step (#2171) This fixes the case of Time.timeScale = 0 stopping the NetworkManager to update. This as no influence on all projects that always have Time.timeScale = 1. + Add tests + Change existing test using Assert.Equal(boolExpr) to the correct Assert function to display real values expected instead of just "true" or "false" * style: removing unrelated stylistic differences. Fixing brackets placement (netcode.standards) * test: test adjustments * test: test adjustments * test: Applying PR review suggestion of saving the time scale * test: Applying PR review suggestion of saving the time scale, second location * Reverted changes to AddNetworkPrefabTests and fixed instabilities caused by NetworkManager.Singleton (can we get rid of that completely soon?) * reverting unwanted whitespace change * reducing the test cases to 0.0f, 1.0f and 2.0f timescales * Revert "Reverted changes to AddNetworkPrefabTests and fixed instabilities caused by NetworkManager.Singleton (can we get rid of that completely soon?)" This reverts commit 02a222e. Co-authored-by: PitouGames <pitou.games@gmail.com> Co-authored-by: Kitty Draper <kitty.draper@unity3d.com>
1 parent ce6e921 commit 4bce448

8 files changed

Lines changed: 137 additions & 42 deletions

File tree

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2121
- Fixed ClientRpcs always reporting in the profiler view as going to all clients, even when limited to a subset of clients by `ClientRpcParams`. (#2144)
2222
- Fixed RPC codegen failing to choose the correct extension methods for `FastBufferReader` and `FastBufferWriter` when the parameters were a generic type (i.e., List<int>) and extensions for multiple instantiations of that type have been defined (i.e., List<int> and List<string>) (#2142)
2323
- Fixed throwing an exception in `OnNetworkUpdate` causing other `OnNetworkUpdate` calls to not be executed. (#1739)
24+
- Fixed synchronisation when Time.timeScale is set to 0. This changes timing update to use unscaled deltatime. Now network updates rate are independant from the local time scale. (#2171)
2425

2526
## [1.0.1] - 2022-08-23
2627

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ private void OnNetworkPreUpdate()
15601560
}
15611561

15621562
// Only update RTT here, server time is updated by time sync messages
1563-
var reset = NetworkTimeSystem.Advance(Time.deltaTime);
1563+
var reset = NetworkTimeSystem.Advance(Time.unscaledDeltaTime);
15641564
if (reset)
15651565
{
15661566
NetworkTickSystem.Reset(NetworkTimeSystem.LocalTime, NetworkTimeSystem.ServerTime);
@@ -1569,7 +1569,7 @@ private void OnNetworkPreUpdate()
15691569

15701570
if (IsServer == false)
15711571
{
1572-
NetworkTimeSystem.Sync(NetworkTimeSystem.LastSyncedServerTimeSec + Time.deltaTime, NetworkConfig.NetworkTransport.GetCurrentRtt(ServerClientId) / 1000d);
1572+
NetworkTimeSystem.Sync(NetworkTimeSystem.LastSyncedServerTimeSec + Time.unscaledDeltaTime, NetworkConfig.NetworkTransport.GetCurrentRtt(ServerClientId) / 1000d);
15731573
}
15741574
}
15751575

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct NetworkTime
2525
public double TickOffset => m_CachedTickOffset;
2626

2727
/// <summary>
28-
/// Gets the current time. This is a non fixed time value and similar to <see cref="Time.time"/>
28+
/// Gets the current time. This is a non fixed time value and similar to <see cref="Time.time"/>.
2929
/// </summary>
3030
public double Time => m_TimeSec;
3131

@@ -35,13 +35,13 @@ public struct NetworkTime
3535
public float TimeAsFloat => (float)m_TimeSec;
3636

3737
/// <summary>
38-
/// Gets he current fixed network time. This is the time value of the last network tick. Similar to <see cref="Time.fixedTime"/>
38+
/// Gets he current fixed network time. This is the time value of the last network tick. Similar to <see cref="Time.fixedUnscaledTime"/>.
3939
/// </summary>
4040
public double FixedTime => m_CachedTick * m_TickInterval;
4141

4242
/// <summary>
4343
/// Gets the fixed delta time. This value is based on the <see cref="TickRate"/> and stays constant.
44-
/// Similar to <see cref="Time.fixedDeltaTime"/> There is no equivalent to <see cref="Time.deltaTime"/>
44+
/// Similar to <see cref="Time.fixedUnscaledTime"/> There is no equivalent to <see cref="Time.deltaTime"/>.
4545
/// </summary>
4646
public float FixedDeltaTime => (float)m_TickInterval;
4747

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static NetworkTimeSystem ServerTimeSystem()
7676
}
7777

7878
/// <summary>
79-
/// Advances the time system by a certain amount of time. Should be called once per frame with Time.deltaTime or similar.
79+
/// Advances the time system by a certain amount of time. Should be called once per frame with Time.unscaledDeltaTime or similar.
8080
/// </summary>
8181
/// <param name="deltaTimeSec">The amount of time to advance. The delta time which passed since Advance was last called.</param>
8282
/// <returns></returns>

com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public abstract class NetcodeIntegrationTest
2323
/// </summary>
2424
internal static bool IsRunning { get; private set; }
2525
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(8.0f);
26-
protected static WaitForSeconds s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
26+
protected static WaitForSecondsRealtime s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / k_DefaultTickRate);
2727

2828
public NetcodeLogAssert NetcodeLogAssert;
2929

@@ -339,7 +339,7 @@ protected void CreateServerAndClients(int numberOfClients)
339339

340340
if (m_ServerNetworkManager != null)
341341
{
342-
s_DefaultWaitForTick = new WaitForSeconds(1.0f / m_ServerNetworkManager.NetworkConfig.TickRate);
342+
s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / m_ServerNetworkManager.NetworkConfig.TickRate);
343343
}
344344

345345
// Set the player prefab for the server and clients
@@ -574,7 +574,7 @@ protected void ShutdownAndCleanUp()
574574
UnloadRemainingScenes();
575575

576576
// reset the m_ServerWaitForTick for the next test to initialize
577-
s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
577+
s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / k_DefaultTickRate);
578578
VerboseDebug($"Exiting {nameof(ShutdownAndCleanUp)}");
579579
}
580580

com.unity.netcode.gameobjects/Tests/Runtime/AddNetworkPrefabTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@ protected override IEnumerator OnSetup()
2222
// Host is irrelevant, messages don't get sent to the host "client"
2323
m_UseHost = false;
2424

25+
yield return null;
26+
}
27+
28+
protected override void OnServerAndClientsCreated()
29+
{
2530
m_Prefab = new GameObject("Object");
2631
var networkObject = m_Prefab.AddComponent<NetworkObject>();
2732
m_Prefab.AddComponent<EmptyComponent>();
2833

2934
// Make it a prefab
3035
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
31-
yield return null;
32-
}
3336

34-
protected override void OnServerAndClientsCreated()
35-
{
3637
m_ServerNetworkManager.NetworkConfig.SpawnTimeout = 0;
3738
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
3839
foreach (var client in m_ClientNetworkManagers)

com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariableTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,23 @@ public IEnumerator ClientWritePermissionTest([Values(true, false)] bool useHost)
536536
Assert.Throws<InvalidOperationException>(() => m_Player1OnClient1.TheScalar.Value = k_TestVal1);
537537
}
538538

539+
/// <summary>
540+
/// Runs tests that network variables sync on client whatever the local value of <see cref="Time.timeScale"/>.
541+
/// </summary>
542+
[UnityTest]
543+
public IEnumerator NetworkVariableSync_WithDifferentTimeScale([Values(true, false)] bool useHost, [Values(0.0f, 1.0f, 2.0f)] float timeScale)
544+
{
545+
Time.timeScale = timeScale;
546+
547+
yield return InitializeServerAndClients(useHost);
548+
549+
m_Player1OnServer.TheScalar.Value = k_TestVal1;
550+
551+
// Now wait for the client side version to be updated to k_TestVal1
552+
yield return WaitForConditionOrTimeOut(() => m_Player1OnClient1.TheScalar.Value == k_TestVal1);
553+
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client-side NetworkVariable to update!");
554+
}
555+
539556
[UnityTest]
540557
public IEnumerator FixedString32Test([Values(true, false)] bool useHost)
541558
{
@@ -758,9 +775,18 @@ public IEnumerator NetworkListIEnumerator([Values(true, false)] bool useHost)
758775
}
759776
#endregion
760777

778+
private float m_OriginalTimeScale = 1.0f;
779+
780+
protected override IEnumerator OnSetup()
781+
{
782+
m_OriginalTimeScale = Time.timeScale;
783+
yield return null;
784+
}
761785

762786
protected override IEnumerator OnTearDown()
763787
{
788+
Time.timeScale = m_OriginalTimeScale;
789+
764790
m_NetworkListPredicateHandler = null;
765791
yield return base.OnTearDown();
766792
}

com.unity.netcode.gameobjects/Tests/Runtime/Timing/NetworkTimeSystemTests.cs

Lines changed: 96 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections;
22
using NUnit.Framework;
33
using UnityEngine;
4+
using UnityEngine.Assertions.Comparers;
45
using UnityEngine.TestTools;
56
using Unity.Netcode.TestHelpers.Runtime;
67

@@ -11,25 +12,45 @@ namespace Unity.Netcode.RuntimeTests
1112
/// </summary>
1213
public class NetworkTimeSystemTests
1314
{
14-
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_MonoBehaviourTest; // cache for teardown
15+
private MonoBehaviourTest<PlayerLoopFixedTimeTestComponent> m_PlayerLoopFixedTimeTestComponent; // cache for teardown
16+
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_PlayerLoopTimeTestComponent; // cache for teardown
17+
18+
private float m_OriginalTimeScale = 1.0f;
1519

1620
[SetUp]
1721
public void Setup()
1822
{
23+
m_OriginalTimeScale = Time.timeScale;
24+
1925
// Create, instantiate, and host
2026
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out _));
2127
}
2228

2329
/// <summary>
2430
/// Tests whether time is accessible and has correct values inside Update/FixedUpdate.
31+
/// This test applies only when <see cref="Time.timeScale"> is 1.
32+
/// </summary>
33+
/// <returns></returns>
34+
[UnityTest]
35+
public IEnumerator PlayerLoopFixedTimeTest()
36+
{
37+
m_PlayerLoopFixedTimeTestComponent = new MonoBehaviourTest<PlayerLoopFixedTimeTestComponent>();
38+
39+
yield return m_PlayerLoopFixedTimeTestComponent;
40+
}
41+
42+
/// <summary>
43+
/// Tests whether time is accessible and has correct values inside Update, for multiples <see cref="Time.timeScale"/> values.
2544
/// </summary>
2645
/// <returns></returns>
2746
[UnityTest]
28-
public IEnumerator PlayerLoopTimeTest()
47+
public IEnumerator PlayerLoopTimeTest_WithDifferentTimeScale([Values(0.0f, 0.1f, 0.5f, 1.0f, 2.0f, 5.0f)] float timeScale)
2948
{
30-
m_MonoBehaviourTest = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();
49+
Time.timeScale = timeScale;
50+
51+
m_PlayerLoopTimeTestComponent = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();
3152

32-
yield return m_MonoBehaviourTest;
53+
yield return m_PlayerLoopTimeTestComponent;
3354
}
3455

3556
/// <summary>
@@ -40,10 +61,10 @@ public IEnumerator PlayerLoopTimeTest()
4061
[UnityTest]
4162
public IEnumerator CorrectAmountTicksTest()
4263
{
43-
var tickSystem = NetworkManager.Singleton.NetworkTickSystem;
44-
var delta = tickSystem.LocalTime.FixedDeltaTime;
45-
var previous_localTickCalculated = 0;
46-
var previous_serverTickCalculated = 0;
64+
NetworkTickSystem tickSystem = NetworkManager.Singleton.NetworkTickSystem;
65+
float delta = tickSystem.LocalTime.FixedDeltaTime;
66+
int previous_localTickCalculated = 0;
67+
int previous_serverTickCalculated = 0;
4768

4869
while (tickSystem.LocalTime.Time < 3f)
4970
{
@@ -70,7 +91,7 @@ public IEnumerator CorrectAmountTicksTest()
7091

7192
Assert.AreEqual(previous_localTickCalculated, NetworkManager.Singleton.LocalTime.Tick, $"Calculated local tick {previous_localTickCalculated} does not match local tick {NetworkManager.Singleton.LocalTime.Tick}!");
7293
Assert.AreEqual(previous_serverTickCalculated, NetworkManager.Singleton.ServerTime.Tick, $"Calculated server tick {previous_serverTickCalculated} does not match server tick {NetworkManager.Singleton.ServerTime.Tick}!");
73-
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time), $"Local time {(float)NetworkManager.Singleton.LocalTime.Time} is not approximately server time {(float)NetworkManager.Singleton.ServerTime.Time}!");
94+
Assert.AreEqual((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time, $"Local time {(float)NetworkManager.Singleton.LocalTime.Time} is not approximately server time {(float)NetworkManager.Singleton.ServerTime.Time}!", FloatComparer.s_ComparerWithDefaultTolerance);
7495
}
7596
}
7697

@@ -80,15 +101,23 @@ public void TearDown()
80101
// Stop, shutdown, and destroy
81102
NetworkManagerHelper.ShutdownNetworkManager();
82103

83-
if (m_MonoBehaviourTest != null)
104+
Time.timeScale = m_OriginalTimeScale;
105+
106+
if (m_PlayerLoopFixedTimeTestComponent != null)
84107
{
85-
Object.DestroyImmediate(m_MonoBehaviourTest.gameObject);
108+
Object.DestroyImmediate(m_PlayerLoopFixedTimeTestComponent.gameObject);
109+
m_PlayerLoopFixedTimeTestComponent = null;
86110
}
87-
}
88111

112+
if (m_PlayerLoopTimeTestComponent != null)
113+
{
114+
Object.DestroyImmediate(m_PlayerLoopTimeTestComponent.gameObject);
115+
m_PlayerLoopTimeTestComponent = null;
116+
}
117+
}
89118
}
90119

91-
public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
120+
public class PlayerLoopFixedTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
92121
{
93122
public const int Passes = 100;
94123

@@ -101,7 +130,7 @@ public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
101130
private NetworkTime m_ServerTimePreviousUpdate;
102131
private NetworkTime m_LocalTimePreviousFixedUpdate;
103132

104-
public void Start()
133+
private void Start()
105134
{
106135
// Run fixed update at same rate as network tick
107136
Time.fixedDeltaTime = NetworkManager.Singleton.LocalTime.FixedDeltaTime;
@@ -110,23 +139,23 @@ public void Start()
110139
Time.maximumDeltaTime = float.MaxValue;
111140
}
112141

113-
public void Update()
142+
private void Update()
114143
{
115144
// This must run first else it wont run if there is an exception
116145
m_UpdatePasses++;
117146

118-
var localTime = NetworkManager.Singleton.LocalTime;
119-
var serverTime = NetworkManager.Singleton.ServerTime;
147+
NetworkTime localTime = NetworkManager.Singleton.LocalTime;
148+
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;
120149

121150
// time should have advanced on the host/server
122-
Assert.True(m_LocalTimePreviousUpdate.Time < localTime.Time);
123-
Assert.True(m_ServerTimePreviousUpdate.Time < serverTime.Time);
151+
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
152+
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);
124153

125154
// time should be further then last fixed step in update
126-
Assert.True(m_LocalTimePreviousFixedUpdate.FixedTime < localTime.Time);
155+
Assert.Less(m_LocalTimePreviousFixedUpdate.FixedTime, localTime.Time);
127156

128157
// we should be in same or further tick then fixed update
129-
Assert.True(m_LocalTimePreviousFixedUpdate.Tick <= localTime.Tick);
158+
Assert.LessOrEqual(m_LocalTimePreviousFixedUpdate.Tick, localTime.Tick);
130159

131160
// fixed update should result in same amounts of tick as network time
132161
if (m_TickOffset == -1)
@@ -135,23 +164,61 @@ public void Update()
135164
}
136165
else
137166
{
138-
// offset of 1 is ok, this happens due to different tick duration offsets
139-
Assert.True(Mathf.Abs(serverTime.Tick - m_TickOffset - m_LastFixedUpdateTick) <= 1);
167+
// offset of 1 is ok, this happens due to different tick duration offsets
168+
Assert.LessOrEqual(Mathf.Abs(serverTime.Tick - m_TickOffset - m_LastFixedUpdateTick), 1);
140169
}
141170

142171
m_LocalTimePreviousUpdate = localTime;
172+
m_ServerTimePreviousUpdate = serverTime;
143173
}
144174

145-
public void FixedUpdate()
175+
private void FixedUpdate()
146176
{
147-
var time = NetworkManager.Singleton.LocalTime;
177+
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;
148178

149-
m_LocalTimePreviousFixedUpdate = time;
179+
Assert.AreEqual(Time.fixedDeltaTime, m_LocalTimePreviousFixedUpdate.FixedDeltaTime);
180+
Assert.AreEqual((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time, null, FloatComparer.s_ComparerWithDefaultTolerance);
181+
m_LastFixedUpdateTick++;
182+
}
150183

151-
Assert.AreEqual(Time.fixedDeltaTime, time.FixedDeltaTime);
152-
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time));
184+
public bool IsTestFinished => m_UpdatePasses >= Passes;
185+
}
153186

154-
m_LastFixedUpdateTick++;
187+
public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
188+
{
189+
public const int Passes = 100;
190+
191+
private int m_UpdatePasses = 0;
192+
193+
private NetworkTime m_LocalTimePreviousUpdate;
194+
private NetworkTime m_ServerTimePreviousUpdate;
195+
private NetworkTime m_LocalTimePreviousFixedUpdate;
196+
197+
private void Update()
198+
{
199+
// This must run first else it wont run if there is an exception
200+
m_UpdatePasses++;
201+
202+
NetworkTime localTime = NetworkManager.Singleton.LocalTime;
203+
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;
204+
205+
// time should have advanced on the host/server
206+
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
207+
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);
208+
209+
// time should be further then last fixed step in update
210+
Assert.Less(m_LocalTimePreviousFixedUpdate.FixedTime, localTime.Time);
211+
212+
// we should be in same or further tick then fixed update
213+
Assert.LessOrEqual(m_LocalTimePreviousFixedUpdate.Tick, localTime.Tick);
214+
215+
m_LocalTimePreviousUpdate = localTime;
216+
m_ServerTimePreviousUpdate = serverTime;
217+
}
218+
219+
private void FixedUpdate()
220+
{
221+
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;
155222
}
156223

157224
public bool IsTestFinished => m_UpdatePasses >= Passes;

0 commit comments

Comments
 (0)