From a20011ed5724f97c7e04e9b938a18cb85368a13c Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 31 Jan 2025 15:01:44 -0500 Subject: [PATCH 1/8] fix: NetworkObject.DeferDespawn not respecting DestroyGameObject parameter --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + .../Messages/DestroyObjectMessage.cs | 2 +- .../Runtime/Spawning/NetworkSpawnManager.cs | 14 ++++++-- .../DeferredDespawningTests.cs | 35 ++++++++++++++++--- .../InScenePlacedNetworkObjectTests.cs | 30 ++++++++++++++-- 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 8f2dee46b1..5ad931940e 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed `NetworkObject.DeferDespawn` to respect the `DestroyGameObject` parameter. - Changed the `NetworkTimeSystem.Sync` method to use half RTT to calculate the desired local time offset as opposed to the full RTT. (#3212) - 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) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DestroyObjectMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DestroyObjectMessage.cs index 868d5a2540..cdcff74251 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DestroyObjectMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/DestroyObjectMessage.cs @@ -150,7 +150,7 @@ public void Handle(ref NetworkContext context) { networkObject.DeferredDespawnTick = DeferredDespawnTick; var hasCallback = networkObject.OnDeferredDespawnComplete != null; - networkManager.SpawnManager.DeferDespawnNetworkObject(NetworkObjectId, DeferredDespawnTick, hasCallback); + networkManager.SpawnManager.DeferDespawnNetworkObject(NetworkObjectId, DeferredDespawnTick, hasCallback, DestroyGameObject); return; } } diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 854bc8fba2..55528e185c 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -1450,7 +1450,7 @@ internal void ServerSpawnSceneObjectsOnStartSweep() } // Since we are spawing in-scene placed NetworkObjects for already loaded scenes, - // we need to add any in-scene placed NetworkObject to our tracking table + // we need to add any in-scene placed NetworkObject to our tracking table var clearFirst = true; foreach (var sceneLoaded in NetworkManager.SceneManager.ScenesLoaded) { @@ -1582,6 +1582,12 @@ internal void OnDespawnObject(NetworkObject networkObject, bool destroyGameObjec } } + if (networkObject.IsSceneObject == false && destroyGameObject == false) + { + // DANGO-TODO: Check that this is still a valid restriction + Debug.LogWarning("Only Scene Objects are valid to not be destroyed when despawned"); + } + if (m_TargetClientIds.Count > 0 && !NetworkManager.ShutdownInProgress) { var message = new DestroyObjectMessage @@ -1920,6 +1926,7 @@ internal struct DeferredDespawnObject { public int TickToDespawn; public bool HasDeferredDespawnCheck; + public bool DestroyGameObject; public ulong NetworkObjectId; } @@ -1931,12 +1938,13 @@ internal struct DeferredDespawnObject /// associated NetworkObject /// when to despawn the NetworkObject /// if true, user script is to be invoked to determine when to despawn - internal void DeferDespawnNetworkObject(ulong networkObjectId, int tickToDespawn, bool hasDeferredDespawnCheck) + internal void DeferDespawnNetworkObject(ulong networkObjectId, int tickToDespawn, bool hasDeferredDespawnCheck, bool destroyGameObject) { var deferredDespawnObject = new DeferredDespawnObject() { TickToDespawn = tickToDespawn, HasDeferredDespawnCheck = hasDeferredDespawnCheck, + DestroyGameObject = destroyGameObject, NetworkObjectId = networkObjectId, }; DeferredDespawnObjects.Add(deferredDespawnObject); @@ -2001,7 +2009,7 @@ internal void DeferredDespawnUpdate(NetworkTime serverTime) } var networkObject = SpawnedObjects[deferredObjectEntry.NetworkObjectId]; // Local instance despawns the instance - OnDespawnObject(networkObject, true); + OnDespawnObject(networkObject, deferredObjectEntry.DestroyGameObject); DeferredDespawnObjects.Remove(deferredObjectEntry); } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs index faba405079..5787f169f1 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DeferredDespawningTests.cs @@ -9,6 +9,8 @@ namespace Unity.Netcode.RuntimeTests { + [TestFixture(SetDestroyGameObject.DestroyGameObject)] + [TestFixture(SetDestroyGameObject.DontDestroyGameObject)] internal class DeferredDespawningTests : IntegrationTestWithApproximation { private const int k_DaisyChainedCount = 5; @@ -16,8 +18,16 @@ internal class DeferredDespawningTests : IntegrationTestWithApproximation private List m_DaisyChainedDespawnObjects = new List(); private List m_HasReachedEnd = new List(); - public DeferredDespawningTests() : base(HostOrServer.DAHost) + public enum SetDestroyGameObject { + DestroyGameObject, + DontDestroyGameObject, + } + private bool m_DestroyGameObject; + + public DeferredDespawningTests(SetDestroyGameObject destroyGameObject) : base(HostOrServer.DAHost) + { + m_DestroyGameObject = destroyGameObject == SetDestroyGameObject.DestroyGameObject; } protected override void OnServerAndClientsCreated() @@ -45,12 +55,28 @@ protected override void OnServerAndClientsCreated() [UnityTest] public IEnumerator DeferredDespawning() { + // Setup for test + DeferredDespawnDaisyChained.DestroyGameObject = m_DestroyGameObject; DeferredDespawnDaisyChained.EnableVerbose = m_EnableVerboseDebug; + DeferredDespawnDaisyChained.ClientRelativeInstances = new Dictionary>(); + + // Spawn the initial object var rootInstance = SpawnObject(m_DaisyChainedDespawnObjects[0], m_ServerNetworkManager); DeferredDespawnDaisyChained.ReachedLastChainInstance = ReachedLastChainObject; + + // Wait for the chain of objects to spawn and despawn var timeoutHelper = new TimeoutHelper(300); yield return WaitForConditionOrTimeOut(HaveAllClientsReachedEndOfChain, timeoutHelper); AssertOnTimeout($"Timed out waiting for all children to reach the end of their chained deferred despawns!", timeoutHelper); + + if (m_DestroyGameObject) + { + Assert.IsTrue(rootInstance == null); // Assert.IsNull doesn't work here + } + else + { + Assert.IsTrue(rootInstance != null); // Assert.IsNotNull doesn't work here + } } private bool HaveAllClientsReachedEndOfChain() @@ -88,9 +114,10 @@ private void ReachedLastChainObject(ulong clientId) internal class DeferredDespawnDaisyChained : NetworkBehaviour { public static bool EnableVerbose; + public static bool DestroyGameObject; public static Action ReachedLastChainInstance; private const int k_StartingDeferTick = 4; - public static Dictionary> ClientRelativeInstances = new Dictionary>(); + public static Dictionary> ClientRelativeInstances; public bool IsRoot; public GameObject PrefabToSpawnWhenDespawned; public bool WasContactedByPeviousChainMember { get; private set; } @@ -182,7 +209,7 @@ private void InvokeDespawn() { FailTest($"[{nameof(InvokeDespawn)}] Client is not the authority but this was invoked (integration test logic issue)!"); } - NetworkObject.DeferDespawn(DeferDespawnTick); + NetworkObject.DeferDespawn(DeferDespawnTick, DestroyGameObject); } public override void OnDeferringDespawn(int despawnTick) @@ -241,7 +268,7 @@ private void Update() continue; } - // This should happen shortly afte the instances spawns (based on the deferred despawn count) + // This should happen shortly after the instances spawn (based on the deferred despawn count) if (!IsRoot && !ClientRelativeInstances[clientId][NetworkObjectId].WasContactedByPeviousChainMember) { // exit early if the non-authority instance has not been contacted yet diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs index 59922c5959..b5a0c3e450 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs @@ -53,6 +53,12 @@ protected override bool CanStartServerAndClients() return m_CanStartServerAndClients; } + public enum DespawnMode + { + Despawn, + DeferredDespawn, + } + /// /// This verifies that in-scene placed NetworkObjects will be properly /// synchronized if: @@ -61,8 +67,13 @@ protected override bool CanStartServerAndClients() /// NetworkObject as a NetworkPrefab /// [UnityTest] - public IEnumerator InSceneNetworkObjectSynchAndSpawn() + public IEnumerator InSceneNetworkObjectSynchAndSpawn([Values] DespawnMode despawnMode) { + if (!m_DistributedAuthority && despawnMode == DespawnMode.DeferredDespawn) + { + Assert.Ignore("Deferred Despawn is only valid with Distributed Authority mode."); + } + NetworkObjectTestComponent.VerboseDebug = true; // Because despawning a client will cause it to shutdown and clean everything in the // scene hierarchy, we have to prevent one of the clients from spawning initially before @@ -99,7 +110,16 @@ public IEnumerator InSceneNetworkObjectSynchAndSpawn() // Despawn the in-scene placed NetworkObject Debug.Log("Despawning In-Scene placed NetworkObject"); - serverObject.Despawn(false); + + if (despawnMode == DespawnMode.Despawn) + { + serverObject.Despawn(false); + } + else + { + serverObject.DeferDespawn(1, false); + } + yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == 0); AssertOnTimeout($"Timed out waiting for all in-scene instances to be despawned! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()}"); @@ -130,6 +150,12 @@ public IEnumerator InSceneNetworkObjectSynchAndSpawn() yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == clientCount); AssertOnTimeout($"Timed out waiting for all in-scene instances to be spawned! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()} | Expected spawn count: {clientCount}"); + if (despawnMode == DespawnMode.DeferredDespawn) + { + // TODO: Check if this is the expected behavior + serverObject.DeferredDespawnTick = 0; + } + // Test NetworkHide on the first client var firstClientId = m_ClientNetworkManagers[0].LocalClientId; From 16659e8c60f1b52a23bb2436faca769f351db06f Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Mon, 3 Feb 2025 10:28:00 -0600 Subject: [PATCH 2/8] test-fix Checking to see if the failure was due to the network prefab being spawned when the host-server starts. --- testproject/Assets/Tests/Runtime/MessageOrdering.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MessageOrdering.cs b/testproject/Assets/Tests/Runtime/MessageOrdering.cs index d4fe59193c..e3dfb8b4bd 100644 --- a/testproject/Assets/Tests/Runtime/MessageOrdering.cs +++ b/testproject/Assets/Tests/Runtime/MessageOrdering.cs @@ -66,7 +66,7 @@ public IEnumerator SpawnChangeOwnership() { client.NetworkConfig.Prefabs.Add(validNetworkPrefab); } - + m_Prefab.gameObject.SetActive(false); // Start the instances if (!NetcodeIntegrationTestHelpers.Start(true, server, clients)) { @@ -80,6 +80,7 @@ public IEnumerator SpawnChangeOwnership() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(server, clients.Length + 1, null, 512); + m_Prefab.gameObject.SetActive(true); var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = server; @@ -125,7 +126,7 @@ public IEnumerator SpawnRpcDespawn() { client.NetworkConfig.Prefabs.Add(validNetworkPrefab); } - + m_Prefab.gameObject.SetActive(false); // Start the instances if (!NetcodeIntegrationTestHelpers.Start(true, m_ServerNetworkManager, m_ClientNetworkManagers)) { @@ -138,7 +139,7 @@ public IEnumerator SpawnRpcDespawn() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(m_ServerNetworkManager, m_ClientNetworkManagers.Length + 1, null, 512); - + m_Prefab.gameObject.SetActive(true); var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = m_ServerNetworkManager; @@ -229,7 +230,7 @@ public IEnumerator RpcOnNetworkSpawn() } var waitForTickInterval = new WaitForSeconds(1.0f / server.NetworkConfig.TickRate); - + m_Prefab.gameObject.SetActive(false); // Start the instances if (!NetcodeIntegrationTestHelpers.Start(false, server, clients)) { @@ -242,7 +243,7 @@ public IEnumerator RpcOnNetworkSpawn() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(server, clients.Length, null, 512); - + m_Prefab.gameObject.SetActive(true); var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = server; From 233c1b365b99528a89eec4b6c914feea57105629 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Mon, 3 Feb 2025 13:58:41 -0600 Subject: [PATCH 3/8] test-fix Assure all NetworkManagers are destroyed at the end of TearDown. --- .../TestHelpers/Runtime/NetcodeIntegrationTest.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs index 921d70b928..fefb128f4e 100644 --- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs @@ -1244,6 +1244,20 @@ public IEnumerator TearDown() VerboseDebug($"Exiting {nameof(TearDown)}"); LogWaitForMessages(); NetcodeLogAssert.Dispose(); + // Assure any remaining NetworkManagers are destroyed + DestroyNetworkManagers(); + } + + /// + /// Destroys any remaining NetworkManager instances + /// + private void DestroyNetworkManagers() + { + var networkManagers = Object.FindObjectsByType(FindObjectsSortMode.None); + foreach (var networkManager in networkManagers) + { + Object.DestroyImmediate(networkManager.gameObject); + } } /// From f18beb7998b3328d7810e7abd5756c7113b57795 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Mon, 3 Feb 2025 14:01:22 -0600 Subject: [PATCH 4/8] Revert "test-fix" This reverts commit 16659e8c60f1b52a23bb2436faca769f351db06f. --- testproject/Assets/Tests/Runtime/MessageOrdering.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/testproject/Assets/Tests/Runtime/MessageOrdering.cs b/testproject/Assets/Tests/Runtime/MessageOrdering.cs index e3dfb8b4bd..d4fe59193c 100644 --- a/testproject/Assets/Tests/Runtime/MessageOrdering.cs +++ b/testproject/Assets/Tests/Runtime/MessageOrdering.cs @@ -66,7 +66,7 @@ public IEnumerator SpawnChangeOwnership() { client.NetworkConfig.Prefabs.Add(validNetworkPrefab); } - m_Prefab.gameObject.SetActive(false); + // Start the instances if (!NetcodeIntegrationTestHelpers.Start(true, server, clients)) { @@ -80,7 +80,6 @@ public IEnumerator SpawnChangeOwnership() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(server, clients.Length + 1, null, 512); - m_Prefab.gameObject.SetActive(true); var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = server; @@ -126,7 +125,7 @@ public IEnumerator SpawnRpcDespawn() { client.NetworkConfig.Prefabs.Add(validNetworkPrefab); } - m_Prefab.gameObject.SetActive(false); + // Start the instances if (!NetcodeIntegrationTestHelpers.Start(true, m_ServerNetworkManager, m_ClientNetworkManagers)) { @@ -139,7 +138,7 @@ public IEnumerator SpawnRpcDespawn() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(m_ServerNetworkManager, m_ClientNetworkManagers.Length + 1, null, 512); - m_Prefab.gameObject.SetActive(true); + var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = m_ServerNetworkManager; @@ -230,7 +229,7 @@ public IEnumerator RpcOnNetworkSpawn() } var waitForTickInterval = new WaitForSeconds(1.0f / server.NetworkConfig.TickRate); - m_Prefab.gameObject.SetActive(false); + // Start the instances if (!NetcodeIntegrationTestHelpers.Start(false, server, clients)) { @@ -243,7 +242,7 @@ public IEnumerator RpcOnNetworkSpawn() // [Host-Side] Check to make sure all clients are connected yield return NetcodeIntegrationTestHelpers.WaitForClientsConnectedToServer(server, clients.Length, null, 512); - m_Prefab.gameObject.SetActive(true); + var serverObject = Object.Instantiate(m_Prefab, Vector3.zero, Quaternion.identity); NetworkObject serverNetworkObject = serverObject.GetComponent(); serverNetworkObject.NetworkManagerOwner = server; From cf62c80d6df9ea8bf88ccc5125dfde657e6d4289 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity Date: Mon, 3 Feb 2025 15:26:29 -0600 Subject: [PATCH 5/8] test-fix-fix Fixing the bug in my previous fix. --- .../TestHelpers/Runtime/NetcodeIntegrationTest.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs index fefb128f4e..a6e31a1a49 100644 --- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTest.cs @@ -1156,6 +1156,9 @@ protected void ShutdownAndCleanUp() // reset the m_ServerWaitForTick for the next test to initialize s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / k_DefaultTickRate); VerboseDebug($"Exiting {nameof(ShutdownAndCleanUp)}"); + + // Assure any remaining NetworkManagers are destroyed + DestroyNetworkManagers(); } protected IEnumerator CoroutineShutdownAndCleanUp() @@ -1195,6 +1198,9 @@ protected IEnumerator CoroutineShutdownAndCleanUp() // reset the m_ServerWaitForTick for the next test to initialize s_DefaultWaitForTick = new WaitForSecondsRealtime(1.0f / k_DefaultTickRate); VerboseDebug($"Exiting {nameof(ShutdownAndCleanUp)}"); + + // Assure any remaining NetworkManagers are destroyed + DestroyNetworkManagers(); } /// @@ -1244,8 +1250,7 @@ public IEnumerator TearDown() VerboseDebug($"Exiting {nameof(TearDown)}"); LogWaitForMessages(); NetcodeLogAssert.Dispose(); - // Assure any remaining NetworkManagers are destroyed - DestroyNetworkManagers(); + } /// From 40b3c206cc8bdad8889f3177b7800cb1207c8e03 Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 4 Feb 2025 11:39:41 -0500 Subject: [PATCH 6/8] Ensure DeferDespawn tick is always reset --- .../Runtime/Spawning/NetworkSpawnManager.cs | 12 +++++------- .../InScenePlacedNetworkObjectTests.cs | 12 +++--------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 55528e185c..cb01d7a08d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -1582,19 +1582,16 @@ internal void OnDespawnObject(NetworkObject networkObject, bool destroyGameObjec } } - if (networkObject.IsSceneObject == false && destroyGameObject == false) - { - // DANGO-TODO: Check that this is still a valid restriction - Debug.LogWarning("Only Scene Objects are valid to not be destroyed when despawned"); - } - if (m_TargetClientIds.Count > 0 && !NetworkManager.ShutdownInProgress) { + // DANGO-TODO: Reconfigure Client-side object destruction on despawn + bool destroyOnClient = !(networkObject.IsSceneObject == false && destroyGameObject == false); + var message = new DestroyObjectMessage { NetworkObjectId = networkObject.NetworkObjectId, DeferredDespawnTick = networkObject.DeferredDespawnTick, - DestroyGameObject = networkObject.IsSceneObject != false ? destroyGameObject : true, + DestroyGameObject = destroyOnClient, IsTargetedDestroy = false, IsDistributedAuthority = distributedAuthority, }; @@ -1607,6 +1604,7 @@ internal void OnDespawnObject(NetworkObject networkObject, bool destroyGameObjec } networkObject.IsSpawned = false; + networkObject.DeferredDespawnTick = 0; if (SpawnedObjects.Remove(networkObject.NetworkObjectId)) { diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs index b5a0c3e450..f0def620ff 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/InScenePlacedNetworkObjectTests.cs @@ -56,7 +56,7 @@ protected override bool CanStartServerAndClients() public enum DespawnMode { Despawn, - DeferredDespawn, + DeferDespawn, } /// @@ -69,9 +69,9 @@ public enum DespawnMode [UnityTest] public IEnumerator InSceneNetworkObjectSynchAndSpawn([Values] DespawnMode despawnMode) { - if (!m_DistributedAuthority && despawnMode == DespawnMode.DeferredDespawn) + if (!m_DistributedAuthority && despawnMode == DespawnMode.DeferDespawn) { - Assert.Ignore("Deferred Despawn is only valid with Distributed Authority mode."); + Assert.Ignore($"Test ignored as DeferDespawn is only valid with Distributed Authority mode."); } NetworkObjectTestComponent.VerboseDebug = true; @@ -150,12 +150,6 @@ public IEnumerator InSceneNetworkObjectSynchAndSpawn([Values] DespawnMode despaw yield return WaitForConditionOrTimeOut(() => NetworkObjectTestComponent.SpawnedInstances.Count == clientCount); AssertOnTimeout($"Timed out waiting for all in-scene instances to be spawned! Current spawned count: {NetworkObjectTestComponent.SpawnedInstances.Count()} | Expected spawn count: {clientCount}"); - if (despawnMode == DespawnMode.DeferredDespawn) - { - // TODO: Check if this is the expected behavior - serverObject.DeferredDespawnTick = 0; - } - // Test NetworkHide on the first client var firstClientId = m_ClientNetworkManagers[0].LocalClientId; From f973dfc9a0bf76ea1ebe937490ebe9ae45773074 Mon Sep 17 00:00:00 2001 From: Emma Date: Tue, 4 Feb 2025 16:00:36 -0500 Subject: [PATCH 7/8] revert DestroyObject message change --- .../Runtime/Spawning/NetworkSpawnManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index cb01d7a08d..beba9c7055 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -1584,14 +1584,12 @@ internal void OnDespawnObject(NetworkObject networkObject, bool destroyGameObjec if (m_TargetClientIds.Count > 0 && !NetworkManager.ShutdownInProgress) { - // DANGO-TODO: Reconfigure Client-side object destruction on despawn - bool destroyOnClient = !(networkObject.IsSceneObject == false && destroyGameObject == false); - var message = new DestroyObjectMessage { NetworkObjectId = networkObject.NetworkObjectId, DeferredDespawnTick = networkObject.DeferredDespawnTick, - DestroyGameObject = destroyOnClient, + // DANGO-TODO: Reconfigure Client-side object destruction on despawn + DestroyGameObject = networkObject.IsSceneObject != false ? destroyGameObject : true, IsTargetedDestroy = false, IsDistributedAuthority = distributedAuthority, }; From 7a4eaf1fe812b77789ce56b14dcf804698ff5c7e Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Tue, 4 Feb 2025 16:14:01 -0600 Subject: [PATCH 8/8] Update CHANGELOG.md Adding PR number to changelog entry. --- com.unity.netcode.gameobjects/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 5ad931940e..b32356deba 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -12,7 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed -- Fixed `NetworkObject.DeferDespawn` to respect the `DestroyGameObject` parameter. +- Fixed `NetworkObject.DeferDespawn` to respect the `DestroyGameObject` parameter. (#3219) - Changed the `NetworkTimeSystem.Sync` method to use half RTT to calculate the desired local time offset as opposed to the full RTT. (#3212) - 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)