diff --git a/Assets/Mirror/Core/NetworkIdentity.cs b/Assets/Mirror/Core/NetworkIdentity.cs index 9856769d5..17c55cde6 100644 --- a/Assets/Mirror/Core/NetworkIdentity.cs +++ b/Assets/Mirror/Core/NetworkIdentity.cs @@ -671,7 +671,24 @@ void OnDestroy() // if an identity is still in .spawned, remove it too. // fixes: https://github.com/MirrorNetworking/Mirror/issues/3324 - NetworkClient.spawned.Remove(netId); + // + // however, verify that spawned[netId] is this NetworkIdentity + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3785 + // - server: netId=42 walks out of and back into AOI range in same frame + // - client frame 1: + // on_destroymsg(42) -> NetworkClient.DestroyObject -> GameObject.Destroy(42) // next frame + // on_spawnmsg(42) -> NetworkClient.SpawnPrefab -> Instantiate(42) -> spawned[42]=new_identity + // - client frame 2: + // Unity destroys the old 42 + // NetworkIdentity.OnDestroy removes .spawned[42] which is new_identity not old_identity + // new_identity becomes orphaned + // + // solution: only remove if spawned[netId] is this NetworkIdentity or null + if (NetworkClient.spawned.TryGetValue(netId, out NetworkIdentity entry)) + { + if (entry == this || entry == null) + NetworkClient.spawned.Remove(netId); + } } // workaround for cyclid NI<->NB reference causing memory leaks