diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs index cf786bd0c4..e055a53e9b 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectSpawnManyObjectsTests.cs @@ -1,8 +1,11 @@ using System.Collections; +using System.Diagnostics; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; +using Unity.PerformanceTesting; using UnityEngine; using UnityEngine.TestTools; +using Debug = UnityEngine.Debug; namespace Unity.Netcode.RuntimeTests { @@ -16,11 +19,22 @@ internal class NetworkObjectSpawnManyObjectsTests : NetcodeIntegrationTest private NetworkPrefab m_PrefabToSpawn; - public NetworkObjectSpawnManyObjectsTests(NetworkTopologyTypes networkTopologyType) : base(networkTopologyType) { } + public NetworkObjectSpawnManyObjectsTests(NetworkTopologyTypes topology) : base(topology) + { + } + + private static void ResetTracking() + { + SpawnObjectTrackingComponent.SpawnedObjects = 0; + SpawnObjectTrackingComponent.DespawnedObjects = 0; + } + // Using this component assures we will know precisely how many prefabs were spawned on the client internal class SpawnObjectTrackingComponent : NetworkBehaviour { public static int SpawnedObjects; + public static int DespawnedObjects; + public override void OnNetworkSpawn() { if (!IsOwner) @@ -28,11 +42,19 @@ public override void OnNetworkSpawn() SpawnedObjects++; } } + + public override void OnNetworkDespawn() + { + if (!IsOwner) + { + DespawnedObjects++; + } + } } protected override void OnServerAndClientsCreated() { - SpawnObjectTrackingComponent.SpawnedObjects = 0; + ResetTracking(); // create prefab var gameObject = new GameObject("TestObject"); var networkObject = gameObject.AddComponent(); @@ -44,6 +66,8 @@ protected override void OnServerAndClientsCreated() foreach (var client in m_NetworkManagers) { + client.NetworkConfig.RecycleNetworkIds = true; + client.NetworkConfig.NetworkIdRecycleDelay = 0.01f; client.NetworkConfig.Prefabs.Add(m_PrefabToSpawn); } } @@ -51,7 +75,6 @@ protected override void OnServerAndClientsCreated() [UnityTest] public IEnumerator WhenManyObjectsAreSpawnedAtOnce_AllAreReceived() { - var timeStarted = Time.realtimeSinceStartup; var authority = GetAuthorityNetworkManager(); for (int x = 0; x < k_SpawnedObjects; x++) { @@ -61,13 +84,66 @@ public IEnumerator WhenManyObjectsAreSpawnedAtOnce_AllAreReceived() serverObject.Spawn(); } - var timeSpawned = Time.realtimeSinceStartup - timeStarted; - // Provide plenty of time to spawn all 1500 objects in case the CI VM is running slow var timeoutHelper = new TimeoutHelper(30); // ensure all objects are replicated yield return WaitForConditionOrTimeOut(() => SpawnObjectTrackingComponent.SpawnedObjects == k_SpawnedObjects, timeoutHelper); + AssertOnTimeout($"Timed out waiting for the client to spawn {k_SpawnedObjects} objects! expected: {k_SpawnedObjects} | have: {SpawnObjectTrackingComponent.SpawnedObjects}", timeoutHelper); + + // Provide one full tick for all messages to finish being processed. + // DANGO-TODO: Determine if this is only when testing against Rust server (i.e. messages still pending and clients shutting down before they are dequeued) + // yield return s_DefaultWaitForTick; + } + + [UnityTest, Performance] + public IEnumerator PerformanceWhenManyObjectsAreSpawnedAndDespawned() + { + var authority = GetAuthorityNetworkManager(); + SampleGroup sampleGroup = new SampleGroup($"ManyObjectsSpawnedAndDespawned"); + for (var i = 0; i < 100; i++) + { + ResetTracking(); + var objects = new NetworkObject[k_SpawnedObjects]; + + Stopwatch stopwatch = Stopwatch.StartNew(); + for (int x = 0; x < k_SpawnedObjects; x++) + { + NetworkObject serverObject = Object.Instantiate(m_PrefabToSpawn.Prefab).GetComponent(); + serverObject.NetworkManagerOwner = authority; + serverObject.SpawnWithObservers = true; + serverObject.Spawn(); + objects[x] = serverObject; + + if (x % 100 == 0) + { + yield return null; + } + } + + for (int x = 0; x < k_SpawnedObjects; x++) + { + var serverObject = objects[x]; + serverObject.Despawn(); + + if (x % 100 == 0) + { + yield return null; + } + } + + // Provide plenty of time to spawn all objects in case the CI VM is running slow + var timeoutHelper = new TimeoutHelper(30); + // ensure all objects are replicated + yield return WaitForConditionOrTimeOut(() => SpawnObjectTrackingComponent.SpawnedObjects == k_SpawnedObjects, timeoutHelper); + AssertOnTimeout($"Timed out waiting for the client to spawn {k_SpawnedObjects} objects! expected: {k_SpawnedObjects} | have: {SpawnObjectTrackingComponent.SpawnedObjects}", timeoutHelper); + + yield return WaitForConditionOrTimeOut(() => SpawnObjectTrackingComponent.DespawnedObjects == k_SpawnedObjects, timeoutHelper); + AssertOnTimeout($"Timed out waiting for the client to despawn {k_SpawnedObjects} objects! expected: {k_SpawnedObjects} | have: {SpawnObjectTrackingComponent.DespawnedObjects}", timeoutHelper); + stopwatch.Stop(); + Measure.Custom(sampleGroup, stopwatch.ElapsedMilliseconds); + yield return null; + } - AssertOnTimeout($"Timed out waiting for the client to spawn {k_SpawnedObjects} objects! Time to spawn: {timeSpawned} | Time to timeout: {timeStarted - Time.realtimeSinceStartup}", timeoutHelper); + yield return s_DefaultWaitForTick; } } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef b/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef index 7153a15480..fb8e99a82d 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef +++ b/com.unity.netcode.gameobjects/Tests/Runtime/com.unity.netcode.runtimetests.asmdef @@ -14,7 +14,8 @@ "Unity.Netcode.TestHelpers.Runtime", "Unity.Mathematics", "UnityEngine.TestRunner", - "UnityEditor.TestRunner" + "UnityEditor.TestRunner", + "Unity.PerformanceTesting" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/testproject/Packages/manifest.json b/testproject/Packages/manifest.json index 50e5a2a32e..3104811f43 100644 --- a/testproject/Packages/manifest.json +++ b/testproject/Packages/manifest.json @@ -49,6 +49,7 @@ "com.unity.modules.xr": "1.0.0" }, "testables": [ - "com.unity.netcode.gameobjects" + "com.unity.netcode.gameobjects", + "com.unity.test-framework.performance" ] }