diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index b66f8d4cd..e150b1ea0 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -1505,8 +1505,8 @@ void NetworkInternal::OnNetworkMessageObjectSpawn(NetworkEvent& event, NetworkCl } // Recreate object locally (spawn only root) - ScriptingObject* obj = nullptr; Actor* prefabInstance = nullptr; + Array objects; if (msgData.PrefabId.IsValid()) { const NetworkReplicatedObject* parent = ResolveObject(rootItem.ParentId); @@ -1525,7 +1525,7 @@ void NetworkInternal::OnNetworkMessageObjectSpawn(NetworkEvent& event, NetworkCl { if (Objects.Contains(child->GetID())) { - obj = FindPrefabObject(child, rootItem.PrefabObjectID); + ScriptingObject* obj = FindPrefabObject(child, rootItem.PrefabObjectID); if (Objects.Contains(obj->GetID())) { // Other instance with already spawned network object @@ -1557,46 +1557,77 @@ void NetworkInternal::OnNetworkMessageObjectSpawn(NetworkEvent& event, NetworkCl return; } } - if (!obj) - obj = FindPrefabObject(prefabInstance, rootItem.PrefabObjectID); - if (!obj) + + // Resolve objects from prefab instance + objects.Resize(msgData.ItemsCount); + for (int32 i = 0; i < msgData.ItemsCount; i++) { - NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to find object {} in prefab {}", rootItem.PrefabObjectID.ToString(), msgData.PrefabId.ToString()); - Delete(prefabInstance); - return; + auto& msgDataItem = msgDataItems[i]; + ScriptingObject* obj = FindPrefabObject(prefabInstance, msgDataItem.PrefabObjectID); + if (!obj) + { + NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to find object {} in prefab {}", msgDataItem.PrefabObjectID.ToString(), msgData.PrefabId.ToString()); + Delete(prefabInstance); + return; + } + objects[i] = obj; } } - else + else if (msgData.ItemsCount == 1) { // Spawn object - if (msgData.ItemsCount != 1) - { - NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Only prefab object spawning can contain more than one object (for type {})", String(rootItem.ObjectTypeName)); - return; - } const ScriptingTypeHandle objectType = Scripting::FindScriptingType(rootItem.ObjectTypeName); - obj = ScriptingObject::NewObject(objectType); + ScriptingObject* obj = ScriptingObject::NewObject(objectType); if (!obj) { NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to spawn object type {}", String(rootItem.ObjectTypeName)); return; } + objects.Add(obj); + } + else + { + // Spawn objects + objects.Resize(msgData.ItemsCount); + for (int32 i = 0; i < msgData.ItemsCount; i++) + { + auto& msgDataItem = msgDataItems[i]; + const ScriptingTypeHandle objectType = Scripting::FindScriptingType(msgDataItem.ObjectTypeName); + ScriptingObject* obj = ScriptingObject::NewObject(objectType); + if (!obj) + { + NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to spawn object type {}", String(msgDataItem.ObjectTypeName)); + for (ScriptingObject* e : objects) + Delete(e); + return; + } + objects[i] = obj; + if (i != 0) + { + // Link hierarchy of spawned objects before calling any networking code for them + if (auto sceneObject = ScriptingObject::Cast(obj)) + { + Actor* parent = nullptr; + for (int32 j = 0; j < i; j++) + { + if (msgDataItems[j].ObjectId == msgDataItem.ParentId) + { + parent = ScriptingObject::Cast(objects[j]); + break; + } + } + if (parent) + sceneObject->SetParent(parent); + } + } + } } // Setup all newly spawned objects for (int32 i = 0; i < msgData.ItemsCount; i++) { auto& msgDataItem = msgDataItems[i]; - if (i != 0) - { - obj = FindPrefabObject(prefabInstance, msgDataItem.PrefabObjectID); - if (!obj) - { - NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to find object {} in prefab {}", msgDataItem.PrefabObjectID.ToString(), msgData.PrefabId.ToString()); - Delete(prefabInstance); - return; - } - } + ScriptingObject* obj = objects[i]; if (!obj->IsRegistered()) obj->RegisterObject(); const NetworkReplicatedObject* parent = ResolveObject(msgDataItem.ParentId);