Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
- Fixed ClientRpcs always reporting in the profiler view as going to all clients, even when limited to a subset of clients by `ClientRpcParams`. (#2144)
- 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)
- Fixed throwing an exception in `OnNetworkUpdate` causing other `OnNetworkUpdate` calls to not be executed. (#1739)
- 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)

## [1.0.1] - 2022-08-23

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,7 @@ private void OnNetworkPreUpdate()
}

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

if (IsServer == false)
{
NetworkTimeSystem.Sync(NetworkTimeSystem.LastSyncedServerTimeSec + Time.deltaTime, NetworkConfig.NetworkTransport.GetCurrentRtt(ServerClientId) / 1000d);
NetworkTimeSystem.Sync(NetworkTimeSystem.LastSyncedServerTimeSec + Time.unscaledDeltaTime, NetworkConfig.NetworkTransport.GetCurrentRtt(ServerClientId) / 1000d);
}
}

Expand Down
6 changes: 3 additions & 3 deletions com.unity.netcode.gameobjects/Runtime/Timing/NetworkTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct NetworkTime
public double TickOffset => m_CachedTickOffset;

/// <summary>
/// Gets the current time. This is a non fixed time value and similar to <see cref="Time.time"/>
/// Gets the current time. This is a non fixed time value and similar to <see cref="Time.time"/>.
/// </summary>
public double Time => m_TimeSec;

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static NetworkTimeSystem ServerTimeSystem()
}

/// <summary>
/// Advances the time system by a certain amount of time. Should be called once per frame with Time.deltaTime or similar.
/// Advances the time system by a certain amount of time. Should be called once per frame with Time.unscaledDeltaTime or similar.
/// </summary>
/// <param name="deltaTimeSec">The amount of time to advance. The delta time which passed since Advance was last called.</param>
/// <returns></returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public abstract class NetcodeIntegrationTest
/// </summary>
internal static bool IsRunning { get; private set; }
protected static TimeoutHelper s_GlobalTimeoutHelper = new TimeoutHelper(8.0f);
protected static WaitForSeconds s_DefaultWaitForTick = new WaitForSeconds(1.0f / k_DefaultTickRate);
protected static WaitForSecondsRealtime s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / k_DefaultTickRate);

public NetcodeLogAssert NetcodeLogAssert;

Expand Down Expand Up @@ -339,7 +339,7 @@ protected void CreateServerAndClients(int numberOfClients)

if (m_ServerNetworkManager != null)
{
s_DefaultWaitForTick = new WaitForSeconds(1.0f / m_ServerNetworkManager.NetworkConfig.TickRate);
s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / m_ServerNetworkManager.NetworkConfig.TickRate);
}

// Set the player prefab for the server and clients
Expand Down Expand Up @@ -574,7 +574,7 @@ protected void ShutdownAndCleanUp()
UnloadRemainingScenes();

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ protected override IEnumerator OnSetup()
// Host is irrelevant, messages don't get sent to the host "client"
Comment thread
jeffreyrainy marked this conversation as resolved.
m_UseHost = false;

yield return null;
}

protected override void OnServerAndClientsCreated()
{
m_Prefab = new GameObject("Object");
var networkObject = m_Prefab.AddComponent<NetworkObject>();
m_Prefab.AddComponent<EmptyComponent>();

// Make it a prefab
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
yield return null;
}

protected override void OnServerAndClientsCreated()
{
m_ServerNetworkManager.NetworkConfig.SpawnTimeout = 0;
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
foreach (var client in m_ClientNetworkManagers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,23 @@ public IEnumerator ClientWritePermissionTest([Values(true, false)] bool useHost)
Assert.Throws<InvalidOperationException>(() => m_Player1OnClient1.TheScalar.Value = k_TestVal1);
}

/// <summary>
/// Runs tests that network variables sync on client whatever the local value of <see cref="Time.timeScale"/>.
/// </summary>
[UnityTest]
public IEnumerator NetworkVariableSync_WithDifferentTimeScale([Values(true, false)] bool useHost, [Values(0.0f, 1.0f, 2.0f)] float timeScale)
{
Time.timeScale = timeScale;
Comment thread
jeffreyrainy marked this conversation as resolved.

yield return InitializeServerAndClients(useHost);

m_Player1OnServer.TheScalar.Value = k_TestVal1;

// Now wait for the client side version to be updated to k_TestVal1
yield return WaitForConditionOrTimeOut(() => m_Player1OnClient1.TheScalar.Value == k_TestVal1);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client-side NetworkVariable to update!");
}

[UnityTest]
public IEnumerator FixedString32Test([Values(true, false)] bool useHost)
{
Expand Down Expand Up @@ -758,9 +775,18 @@ public IEnumerator NetworkListIEnumerator([Values(true, false)] bool useHost)
}
#endregion

private float m_OriginalTimeScale = 1.0f;

protected override IEnumerator OnSetup()
{
m_OriginalTimeScale = Time.timeScale;
yield return null;
}

protected override IEnumerator OnTearDown()
{
Time.timeScale = m_OriginalTimeScale;

m_NetworkListPredicateHandler = null;
yield return base.OnTearDown();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Assertions.Comparers;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;

Expand All @@ -11,25 +12,45 @@ namespace Unity.Netcode.RuntimeTests
/// </summary>
public class NetworkTimeSystemTests
{
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_MonoBehaviourTest; // cache for teardown
private MonoBehaviourTest<PlayerLoopFixedTimeTestComponent> m_PlayerLoopFixedTimeTestComponent; // cache for teardown
private MonoBehaviourTest<PlayerLoopTimeTestComponent> m_PlayerLoopTimeTestComponent; // cache for teardown

private float m_OriginalTimeScale = 1.0f;

[SetUp]
public void Setup()
{
m_OriginalTimeScale = Time.timeScale;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️


// Create, instantiate, and host
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out _));
}

/// <summary>
/// Tests whether time is accessible and has correct values inside Update/FixedUpdate.
/// This test applies only when <see cref="Time.timeScale"> is 1.
/// </summary>
/// <returns></returns>
[UnityTest]
public IEnumerator PlayerLoopFixedTimeTest()
{
m_PlayerLoopFixedTimeTestComponent = new MonoBehaviourTest<PlayerLoopFixedTimeTestComponent>();

yield return m_PlayerLoopFixedTimeTestComponent;
}

/// <summary>
/// Tests whether time is accessible and has correct values inside Update, for multiples <see cref="Time.timeScale"/> values.
/// </summary>
/// <returns></returns>
[UnityTest]
public IEnumerator PlayerLoopTimeTest()
public IEnumerator PlayerLoopTimeTest_WithDifferentTimeScale([Values(0.0f, 0.1f, 0.5f, 1.0f, 2.0f, 5.0f)] float timeScale)
{
m_MonoBehaviourTest = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();
Time.timeScale = timeScale;

m_PlayerLoopTimeTestComponent = new MonoBehaviourTest<PlayerLoopTimeTestComponent>();

yield return m_MonoBehaviourTest;
yield return m_PlayerLoopTimeTestComponent;
}

/// <summary>
Expand All @@ -40,10 +61,10 @@ public IEnumerator PlayerLoopTimeTest()
[UnityTest]
public IEnumerator CorrectAmountTicksTest()
{
var tickSystem = NetworkManager.Singleton.NetworkTickSystem;
var delta = tickSystem.LocalTime.FixedDeltaTime;
var previous_localTickCalculated = 0;
var previous_serverTickCalculated = 0;
NetworkTickSystem tickSystem = NetworkManager.Singleton.NetworkTickSystem;
float delta = tickSystem.LocalTime.FixedDeltaTime;
int previous_localTickCalculated = 0;
int previous_serverTickCalculated = 0;

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

Assert.AreEqual(previous_localTickCalculated, NetworkManager.Singleton.LocalTime.Tick, $"Calculated local tick {previous_localTickCalculated} does not match local tick {NetworkManager.Singleton.LocalTime.Tick}!");
Assert.AreEqual(previous_serverTickCalculated, NetworkManager.Singleton.ServerTime.Tick, $"Calculated server tick {previous_serverTickCalculated} does not match server tick {NetworkManager.Singleton.ServerTime.Tick}!");
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}!");
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);
}
}

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

if (m_MonoBehaviourTest != null)
Time.timeScale = m_OriginalTimeScale;

if (m_PlayerLoopFixedTimeTestComponent != null)
{
Object.DestroyImmediate(m_MonoBehaviourTest.gameObject);
Object.DestroyImmediate(m_PlayerLoopFixedTimeTestComponent.gameObject);
m_PlayerLoopFixedTimeTestComponent = null;
}
}

if (m_PlayerLoopTimeTestComponent != null)
{
Object.DestroyImmediate(m_PlayerLoopTimeTestComponent.gameObject);
m_PlayerLoopTimeTestComponent = null;
}
}
}

public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
public class PlayerLoopFixedTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
{
public const int Passes = 100;

Expand All @@ -101,7 +130,7 @@ public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
private NetworkTime m_ServerTimePreviousUpdate;
private NetworkTime m_LocalTimePreviousFixedUpdate;

public void Start()
private void Start()
{
// Run fixed update at same rate as network tick
Time.fixedDeltaTime = NetworkManager.Singleton.LocalTime.FixedDeltaTime;
Expand All @@ -110,23 +139,23 @@ public void Start()
Time.maximumDeltaTime = float.MaxValue;
}

public void Update()
private void Update()
{
// This must run first else it wont run if there is an exception
m_UpdatePasses++;

var localTime = NetworkManager.Singleton.LocalTime;
var serverTime = NetworkManager.Singleton.ServerTime;
NetworkTime localTime = NetworkManager.Singleton.LocalTime;
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;

// time should have advanced on the host/server
Assert.True(m_LocalTimePreviousUpdate.Time < localTime.Time);
Assert.True(m_ServerTimePreviousUpdate.Time < serverTime.Time);
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);

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

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

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

m_LocalTimePreviousUpdate = localTime;
m_ServerTimePreviousUpdate = serverTime;
}

public void FixedUpdate()
private void FixedUpdate()
{
var time = NetworkManager.Singleton.LocalTime;
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;

m_LocalTimePreviousFixedUpdate = time;
Assert.AreEqual(Time.fixedDeltaTime, m_LocalTimePreviousFixedUpdate.FixedDeltaTime);
Assert.AreEqual((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time, null, FloatComparer.s_ComparerWithDefaultTolerance);
m_LastFixedUpdateTick++;
}

Assert.AreEqual(Time.fixedDeltaTime, time.FixedDeltaTime);
Assert.True(Mathf.Approximately((float)NetworkManager.Singleton.LocalTime.Time, (float)NetworkManager.Singleton.ServerTime.Time));
public bool IsTestFinished => m_UpdatePasses >= Passes;
}

m_LastFixedUpdateTick++;
public class PlayerLoopTimeTestComponent : MonoBehaviour, IMonoBehaviourTest
{
public const int Passes = 100;

private int m_UpdatePasses = 0;

private NetworkTime m_LocalTimePreviousUpdate;
private NetworkTime m_ServerTimePreviousUpdate;
private NetworkTime m_LocalTimePreviousFixedUpdate;

private void Update()
{
// This must run first else it wont run if there is an exception
m_UpdatePasses++;

NetworkTime localTime = NetworkManager.Singleton.LocalTime;
NetworkTime serverTime = NetworkManager.Singleton.ServerTime;

// time should have advanced on the host/server
Assert.Less(m_LocalTimePreviousUpdate.Time, localTime.Time);
Assert.Less(m_ServerTimePreviousUpdate.Time, serverTime.Time);

// time should be further then last fixed step in update
Assert.Less(m_LocalTimePreviousFixedUpdate.FixedTime, localTime.Time);

// we should be in same or further tick then fixed update
Assert.LessOrEqual(m_LocalTimePreviousFixedUpdate.Tick, localTime.Tick);

m_LocalTimePreviousUpdate = localTime;
m_ServerTimePreviousUpdate = serverTime;
}

private void FixedUpdate()
{
m_LocalTimePreviousFixedUpdate = NetworkManager.Singleton.LocalTime;
}

public bool IsTestFinished => m_UpdatePasses >= Passes;
Expand Down