Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ public IEnumerator TearDown()
}

VerboseDebug($"Exiting {nameof(TearDown)}");
LogWaitForMessages();
NetcodeLogAssert.Dispose();
}

Expand Down Expand Up @@ -1057,5 +1058,61 @@ private void UnloadRemainingScenes()
var asyncOperation = SceneManager.UnloadSceneAsync(scene);
}
}

private System.Text.StringBuilder m_WaitForLog = new System.Text.StringBuilder();

private void LogWaitForMessages()
{
VerboseDebug(m_WaitForLog.ToString());
m_WaitForLog.Clear();
}

private IEnumerator WaitForTickAndFrames(NetworkManager networkManager, int tickCount, float targetFrames)
{
var tickAndFramesConditionMet = false;
var frameCount = 0;
var waitForFixedUpdate = new WaitForFixedUpdate();
m_WaitForLog.Append($"[NetworkManager-{networkManager.LocalClientId}][WaitForTicks-Begin] Waiting for ({tickCount}) network ticks and ({targetFrames}) frames to pass.\n");
var tickStart = networkManager.NetworkTickSystem.LocalTime.Tick;
while (!tickAndFramesConditionMet)
{
// Wait until both tick and frame counts have reached their targeted values
if ((networkManager.NetworkTickSystem.LocalTime.Tick - tickStart) >= tickCount && frameCount >= targetFrames)
{
tickAndFramesConditionMet = true;
}
else
{
yield return waitForFixedUpdate;
frameCount++;
// In the event something is broken with time systems (or the like)
// Exit if we have exceeded 1000 frames
if (frameCount >= 1000.0f)
{
tickAndFramesConditionMet = true;
}
}
}
m_WaitForLog.Append($"[NetworkManager-{networkManager.LocalClientId}][WaitForTicks-End] Waited for ({networkManager.NetworkTickSystem.LocalTime.Tick - tickStart}) network ticks and ({frameCount}) frames to pass.\n");
yield break;
}

/// <summary>
/// Yields until specified amount of network ticks and the expected number of frames has been passed.
/// </summary>
protected IEnumerator WaitForTicks(NetworkManager networkManager, int count)
{
var targetTick = networkManager.NetworkTickSystem.LocalTime.Tick + count;

// Calculate the expected number of frame updates that should occur during the tick count wait period
var frameFrequency = 1.0f / (Application.targetFrameRate >= 60 && Application.targetFrameRate <= 100 ? Application.targetFrameRate : 60.0f);
var tickFrequency = 1.0f / networkManager.NetworkConfig.TickRate;
var framesPerTick = tickFrequency / frameFrequency;

// Total number of frames to occur over the specified number of ticks
var totalFrameCount = framesPerTick * count;
m_WaitForLog.Append($"[NetworkManager-{networkManager.LocalClientId}][WaitForTicks] TickRate ({networkManager.NetworkConfig.TickRate}) | Tick Wait ({count}) | TargetFrameRate ({Application.targetFrameRate}) | Target Frames ({framesPerTick * count})\n");
yield return WaitForTickAndFrames(networkManager, count, totalFrameCount);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -537,15 +537,6 @@ public static void MarkAsSceneObjectRoot(GameObject networkObjectRoot, NetworkMa
}
}

/// <summary>
/// Waits (yields) until specified amount of network ticks has been passed.
/// </summary>
public static IEnumerator WaitForTicks(NetworkManager networkManager, int count)
{
var targetTick = networkManager.NetworkTickSystem.LocalTime.Tick + count;
yield return new WaitUntil(() => networkManager.NetworkTickSystem.LocalTime.Tick >= targetTick);
}

/// <summary>
/// Waits on the client side to be connected.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private IEnumerator CheckVisible(bool isVisible)
int count = 0;
do
{
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);
count++;

if (count > 20)
Expand Down Expand Up @@ -268,11 +268,11 @@ public IEnumerator NetworkShowHideTest()
// hide them on one client
Show(mode == 0, false);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyNetworkVariable.Value = 3;

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

// verify they got hidden
yield return CheckVisible(false);
Expand Down Expand Up @@ -314,10 +314,10 @@ public IEnumerator NetworkShowHideQuickTest()
Show(mode == 0, false);
Show(mode == 0, true);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForConditionOrTimeOut(RefreshNetworkObjects);
AssertOnTimeout($"Could not refresh all NetworkObjects!");
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

// verify they become visible
yield return CheckVisible(true);
Expand All @@ -343,7 +343,7 @@ public IEnumerator NetworkHideDespawnTest()
m_NetSpawnedObject1.NetworkHide(m_ClientId0);
m_NetSpawnedObject1.Despawn();

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

LogAssert.NoUnexpectedReceived();
}
Expand Down Expand Up @@ -400,7 +400,7 @@ public IEnumerator NetworkHideChangeOwnershipNotHidden()
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyOwnerReadNetworkVariable.Value++;

// wait for three ticks
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// check we'll actually be changing owners
Assert.False(ShowHideObject.ClientTargetedNetworkObjects[0].OwnerClientId == m_ClientNetworkManagers[0].LocalClientId);
Expand All @@ -412,8 +412,8 @@ public IEnumerator NetworkHideChangeOwnershipNotHidden()
m_NetSpawnedObject1.ChangeOwnership(m_ClientNetworkManagers[0].LocalClientId);

// wait three ticks
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);

// verify ownership changed
Assert.True(ShowHideObject.ClientTargetedNetworkObjects[0].OwnerClientId == m_ClientNetworkManagers[0].LocalClientId);
Expand Down Expand Up @@ -461,64 +461,64 @@ private IEnumerator HideThenShowAndHideThenModifyAndShow()
Debug.Log("Hiding");
// hide
m_NetSpawnedObject1.NetworkHide(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);

Debug.Log("Showing and Hiding");
// show and hide
m_NetSpawnedObject1.NetworkShow(1);
m_NetSpawnedObject1.NetworkHide(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);

Debug.Log("Modifying and Showing");
// modify and show
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyList.Add(5);
m_NetSpawnedObject1.NetworkShow(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);
}


private IEnumerator HideThenModifyAndShow()
{
// hide
m_NetSpawnedObject1.NetworkHide(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// modify
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyList.Add(5);
// show
m_NetSpawnedObject1.NetworkShow(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);

}

private IEnumerator HideThenShowAndModify()
{
// hide
m_NetSpawnedObject1.NetworkHide(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// show
m_NetSpawnedObject1.NetworkShow(1);
// modify
m_NetSpawnedObject1.GetComponent<ShowHideObject>().MyList.Add(5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);
}

private IEnumerator HideThenShowAndRPC()
{
// hide
m_NetSpawnedObject1.NetworkHide(1);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// show
m_NetSpawnedObject1.NetworkShow(1);
m_NetSpawnedObject1.GetComponent<ShowHideObject>().TriggerRpc();
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
}

[UnityTest]
Expand All @@ -540,8 +540,8 @@ public IEnumerator NetworkShowHideAroundListModify()
for (int i = 0; i < 4; i++)
{
// wait for three ticks
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ClientNetworkManagers[0], 3);

switch (i)
{
Expand All @@ -561,7 +561,9 @@ public IEnumerator NetworkShowHideAroundListModify()
Debug.Log("Running HideThenShowAndRPC");
ShowHideObject.ClientIdsRpcCalledOn = new List<ulong>();
yield return HideThenShowAndRPC();
Debug.Assert(ShowHideObject.ClientIdsRpcCalledOn.Count == NumberOfClients + 1);
// Provide enough time for slower systems or VM systems possibly under a heavy load could fail on this test
yield return WaitForConditionOrTimeOut(() => ShowHideObject.ClientIdsRpcCalledOn.Count == NumberOfClients + 1);
AssertOnTimeout($"Timed out waiting for ClientIdsRpcCalledOn.Count ({ShowHideObject.ClientIdsRpcCalledOn.Count}) to equal ({NumberOfClients + 1})!");
break;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public IEnumerator ClientChangesOwnerWritableNetVar()
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForTicks(m_ServerNetworkManager, 2);

yield return WaitForOwnerWritableAreEqualOnAll();

Expand Down Expand Up @@ -269,7 +269,7 @@ public IEnumerator ClientOwnerWithReadWriteChangesNetVar()
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForTicks(m_ServerNetworkManager, 2);

yield return WaitForOwnerWritableAreEqualOnAll();

Expand Down Expand Up @@ -301,7 +301,7 @@ public IEnumerator ClientCannotChangeServerWritableNetVar()
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForTicks(m_ServerNetworkManager, 2);

yield return WaitForServerWritableAreEqualOnAll();

Expand Down Expand Up @@ -333,7 +333,7 @@ public IEnumerator ServerCannotChangeOwnerWritableNetVar()
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForTicks(m_ServerNetworkManager, 2);

yield return WaitForOwnerWritableAreEqualOnAll();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ public IEnumerator OwnerModifiedTest()
ownerModLastClient.NetworkUpdateStageToCheck = (NetworkUpdateStage)updateLoopType;
Debug.Log($"Testing Update Stage: {ownerModLastClient.NetworkUpdateStageToCheck}");
ownerModLastClient.AddValues = true;
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);
}

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

// We'll have at least one update per stage per client, if all goes well.
Assert.True(OwnerModifiedObject.Updates > 20);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ public IEnumerator OwnerPermissionTest()
// Verify client-owned networkList can only be written by owner
Debug.Assert(gotException == (clientWriting != objectIndex));

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[0], 5);
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ClientNetworkManagers[1], 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ClientNetworkManagers[0], 5);
yield return WaitForTicks(m_ClientNetworkManagers[1], 5);

OwnerPermissionObject.VerifyConsistency();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public IEnumerator TestRigidbodyKinematicEnableDisable()
Assert.IsNotNull(serverPlayer);
Assert.IsNotNull(clientPlayer);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

// server rigidbody has authority and should have a kinematic mode of false
Assert.True(serverPlayer.GetComponent<Rigidbody2D>().isKinematic == Kinematic);
Expand All @@ -66,12 +66,12 @@ public IEnumerator TestRigidbodyKinematicEnableDisable()
// despawn the server player, (but keep it around on the server)
serverPlayer.GetComponent<NetworkObject>().Despawn(false);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

// This should equal Kinematic
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody2D>().isKinematic == Kinematic);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ServerNetworkManager, 5);

Assert.IsTrue(clientPlayer == null); // safety check that object is actually despawned.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public IEnumerator TestRigidbodyKinematicEnableDisable()
Assert.IsNotNull(serverPlayer, "serverPlayer is not null");
Assert.IsNotNull(clientPlayer, "clientPlayer is not null");

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// server rigidbody has authority and should not be kinematic
Assert.True(serverPlayer.GetComponent<Rigidbody>().isKinematic == false, "serverPlayer kinematic");
Expand All @@ -53,12 +53,12 @@ public IEnumerator TestRigidbodyKinematicEnableDisable()
// despawn the server player (but keep it around on the server)
serverPlayer.GetComponent<NetworkObject>().Despawn(false);

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

// When despawned, we should always be kinematic (i.e. don't apply physics when despawned)
Assert.IsTrue(serverPlayer.GetComponent<Rigidbody>().isKinematic == true, "serverPlayer second kinematic");

yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 3);
yield return WaitForTicks(m_ServerNetworkManager, 3);

Assert.IsTrue(clientPlayer == null, "clientPlayer being null"); // safety check that object is actually despawned.
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#if EXCLUDE_UNTIL_PR_2388_MERGED
using System.Text;
using System.Collections;
using Unity.Netcode.Components;
Expand Down Expand Up @@ -150,6 +151,7 @@ private bool ValidateNetworkTransforms()
return m_ValidationErrors.Length == 0;
}

[Ignore("Issues with this test are resolved in PR-2388, has too many instabilities currently so disabling until PR is merged")]
[UnityTest]
public IEnumerator NestedNetworkTransformSynchronization()
{
Expand Down Expand Up @@ -180,4 +182,4 @@ public IEnumerator NestedNetworkTransformSynchronization()

}
}

#endif