mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
fix: #3832 NetworkServer.Destroy now doesn't call ResetState for prefabs, fixes isServer flag always being false in OnDestroy (#3848)
* repro
* NetworkServer.Destroy(): refactor to split scene vs. prefab cases more obviously
* fix: #3832 NetworkServer.Destroy now doesn't call ResetState for prefabs, fixes isServer flag always being false in OnDestroy
* fix the runtime test
* Revert "repro"
This reverts commit 3a5a33e8e4
.
---------
Co-authored-by: mischa <info@noobtuts.com>
This commit is contained in:
parent
4e28b1a2b2
commit
d1aa191550
@ -1592,14 +1592,12 @@ static void SpawnObject(GameObject obj, NetworkConnection ownerConnection)
|
||||
RebuildObservers(identity, true);
|
||||
}
|
||||
|
||||
/// <summary>This takes an object that has been spawned and un-spawns it.</summary>
|
||||
// The object will be removed from clients that it was spawned on, or
|
||||
// the custom spawn handler function on the client will be called for
|
||||
// the object.
|
||||
// Unlike when calling NetworkServer.Destroy(), on the server the object
|
||||
// will NOT be destroyed. This allows the server to re-use the object,
|
||||
// even spawn it again later.
|
||||
public static void UnSpawn(GameObject obj)
|
||||
// internal Unspawn function which has the 'resetState' parameter.
|
||||
// resetState calls .ResetState() on the object after unspawning.
|
||||
// this is necessary for scene objects, but not for prefabs since we
|
||||
// don't want to reset their isServer flags etc.
|
||||
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3832
|
||||
static void UnSpawnInternal(GameObject obj, bool resetState)
|
||||
{
|
||||
// Debug.Log($"DestroyObject instance:{identity.netId}");
|
||||
|
||||
@ -1673,10 +1671,22 @@ public static void UnSpawn(GameObject obj)
|
||||
identity.OnStopServer();
|
||||
|
||||
// finally reset the state and deactivate it
|
||||
identity.ResetState();
|
||||
identity.gameObject.SetActive(false);
|
||||
if (resetState)
|
||||
{
|
||||
identity.ResetState();
|
||||
identity.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>This takes an object that has been spawned and un-spawns it.</summary>
|
||||
// The object will be removed from clients that it was spawned on, or
|
||||
// the custom spawn handler function on the client will be called for
|
||||
// the object.
|
||||
// Unlike when calling NetworkServer.Destroy(), on the server the object
|
||||
// will NOT be destroyed. This allows the server to re-use the object,
|
||||
// even spawn it again later.
|
||||
public static void UnSpawn(GameObject obj) => UnSpawnInternal(obj, resetState: true);
|
||||
|
||||
// destroy /////////////////////////////////////////////////////////////
|
||||
/// <summary>Destroys this object and corresponding objects on all clients.</summary>
|
||||
// In some cases it is useful to remove an object but not delete it on
|
||||
@ -1698,17 +1708,31 @@ public static void Destroy(GameObject obj)
|
||||
return;
|
||||
}
|
||||
|
||||
// first, we unspawn it on clients and server
|
||||
UnSpawn(obj);
|
||||
// get the NetworkIdentity component first
|
||||
if (!GetNetworkIdentity(obj, out NetworkIdentity identity))
|
||||
{
|
||||
Debug.LogWarning($"NetworkServer.Destroy() called on {obj.name} which doesn't have a NetworkIdentity component.");
|
||||
return;
|
||||
}
|
||||
|
||||
// additionally, if it's a prefab then we destroy it completely.
|
||||
// is this a scene object?
|
||||
// then we simply unspawn & reset it so it can still be spawned again.
|
||||
// we never destroy scene objects on server or on client, since once
|
||||
// they are gone, they are gone forever and can't be instantiate again.
|
||||
// for example, server may Destroy() a scene object and once a match
|
||||
// restarts, the scene objects would be gone from the new match.
|
||||
if (GetNetworkIdentity(obj, out NetworkIdentity identity) &&
|
||||
identity.sceneId == 0)
|
||||
if (identity.sceneId != 0)
|
||||
{
|
||||
UnSpawnInternal(obj, resetState: true);
|
||||
}
|
||||
// is this a prefab?
|
||||
// then we destroy it completely.
|
||||
else
|
||||
{
|
||||
// unspawn without calling ResetState.
|
||||
// otherwise isServer/isClient flags might be reset in OnDestroy.
|
||||
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3832
|
||||
UnSpawnInternal(obj, resetState: false);
|
||||
identity.destroyCalled = true;
|
||||
|
||||
// Destroy if application is running
|
||||
|
@ -855,6 +855,28 @@ public void OnStopLocalPlayer()
|
||||
Assert.That(comp.onStopLocalPlayerCalled, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
// test to prevent: https://github.com/MirrorNetworking/Mirror/issues/3832
|
||||
class NetworkBehaviourOnDestroy : NetworkBehaviour
|
||||
{
|
||||
void OnDestroy()
|
||||
{
|
||||
Debug.LogWarning("OnDestroy called with isServer=" + isServer);
|
||||
// on server, IsServer should still be false in OnDestroy.
|
||||
Assert.That(isServer, Is.EqualTo(NetworkServer.active));
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void NetworkDestroy_OnDestroyFlags()
|
||||
{
|
||||
NetworkServer.Listen(1);
|
||||
ConnectClientBlockingAuthenticatedAndReady(out _);
|
||||
|
||||
CreateNetworked(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourOnDestroy comp);
|
||||
NetworkServer.Destroy(identity.gameObject);
|
||||
|
||||
// the NetworkBehaviourOnDestroy component has the asset to check isServer..
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthorityIsFalseVariations()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user