fix: #3785 NetworkIdentity.OnDestroy verifies spawned[netId] before removing

This commit is contained in:
mischa 2024-10-29 10:54:30 +01:00
parent c4f803fcf6
commit a9d280cd4b

View File

@ -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