fix: #2705 NetworkClient.SpawnPrefab looks for spawn handlers before looking for registered prefabs, instead of the other way around

This commit is contained in:
vis2k 2022-04-04 19:07:11 +08:00
parent 7d4a9c46e4
commit eded0a2b15
2 changed files with 21 additions and 12 deletions

View File

@ -1078,12 +1078,13 @@ static NetworkIdentity GetExistingObject(uint netid)
static NetworkIdentity SpawnPrefab(SpawnMessage message)
{
if (GetPrefab(message.assetId, out GameObject prefab))
{
GameObject obj = GameObject.Instantiate(prefab, message.position, message.rotation);
//Debug.Log($"Client spawn handler instantiating [netId{message.netId} asset ID:{message.assetId} pos:{message.position} rotation:{message.rotation}]");
return obj.GetComponent<NetworkIdentity>();
}
// custom spawn handler for this prefab? (for prefab pools etc.)
//
// IMPORTANT: look for spawn handlers BEFORE looking for registered
// prefabs. Unspawning also looks for unspawn handlers
// before falling back to regular Destroy. this needs to
// be consistent.
// https://github.com/vis2k/Mirror/issues/2705
if (spawnHandlers.TryGetValue(message.assetId, out SpawnHandlerDelegate handler))
{
GameObject obj = handler(message);
@ -1100,6 +1101,15 @@ static NetworkIdentity SpawnPrefab(SpawnMessage message)
}
return identity;
}
// otherwise look in NetworkManager registered prefabs
if (GetPrefab(message.assetId, out GameObject prefab))
{
GameObject obj = GameObject.Instantiate(prefab, message.position, message.rotation);
//Debug.Log($"Client spawn handler instantiating [netId{message.netId} asset ID:{message.assetId} pos:{message.position} rotation:{message.rotation}]");
return obj.GetComponent<NetworkIdentity>();
}
Debug.LogError($"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={message.assetId} netId={message.netId}");
return null;
}
@ -1348,13 +1358,13 @@ static void DestroyObject(uint netId)
localObject.OnStopClient();
// user handling
// custom unspawn handler for this prefab? (for prefab pools etc.)
if (InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject))
{
// reset object after user's handler
localObject.Reset();
}
// default handling
// otherwise fall back to default Destroy
else if (localObject.sceneId == 0)
{
// don't call reset before destroy so that values are still set in OnDestroy

View File

@ -148,8 +148,9 @@ public void FindOrSpawnObject_ErrorWhenPrefabInNullInDictionary()
Assert.IsNull(networkIdentity);
}
// test to prevent https://github.com/vis2k/Mirror/issues/2705
[Test]
public void FindOrSpawnObject_SpawnsFromPrefabIfBothPrefabAndHandlerExists()
public void FindOrSpawnObject_SpawnsFromHandlerIfBothPrefabAndHandlerExists()
{
const uint netId = 1003;
int handlerCalled = 0;
@ -167,13 +168,11 @@ public void FindOrSpawnObject_SpawnsFromPrefabIfBothPrefabAndHandlerExists()
return go;
});
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
Assert.IsTrue(success);
Assert.IsNotNull(networkIdentity);
Assert.That(networkIdentity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
Assert.That(handlerCalled, Is.EqualTo(0), "Handler should not have been called");
Assert.That(handlerCalled, Is.EqualTo(1));
}
[Test]