Add support for loading prefab instance if the root was changed or deleted
#2050
This commit is contained in:
@@ -87,17 +87,12 @@ SceneObject* Prefab::GetDefaultInstance(const Guid& objectId)
|
||||
const auto result = GetDefaultInstance();
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
if (objectId.IsValid())
|
||||
{
|
||||
SceneObject* object;
|
||||
if (ObjectsCache.TryGet(objectId, object))
|
||||
{
|
||||
// Actor or Script
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
LOG(Warning, "Waiting for prefab asset be loaded failed. {0}", prefab->ToString());
|
||||
return nullptr;
|
||||
}
|
||||
const int32 objectsCount = prefab->ObjectsCount;
|
||||
if (objectsCount == 0)
|
||||
const int32 dataCount = prefab->ObjectsCount;
|
||||
if (dataCount == 0)
|
||||
{
|
||||
LOG(Warning, "Prefab has no objects. {0}", prefab->ToString());
|
||||
return nullptr;
|
||||
@@ -107,7 +107,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
|
||||
// Prepare
|
||||
CollectionPoolCache<ActorsCache::SceneObjectsListType>::ScopeCache sceneObjects = ActorsCache::SceneObjectsListCache.Get();
|
||||
sceneObjects->Resize(objectsCount);
|
||||
sceneObjects->Resize(dataCount);
|
||||
CollectionPoolCache<ISerializeModifier, Cache::ISerializeModifierClearCallback>::ScopeCache modifier = Cache::ISerializeModifier.Get();
|
||||
modifier->EngineBuild = prefab->DataEngineBuild;
|
||||
modifier->IdsMapping.EnsureCapacity(prefab->ObjectsIds.Count() * 4);
|
||||
@@ -126,7 +126,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
// Deserialize prefab objects
|
||||
auto prevIdMapping = Scripting::ObjectsLookupIdMapping.Get();
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
{
|
||||
auto& stream = data[i];
|
||||
SceneObject* obj = SceneObjectsFactory::Spawn(context, stream);
|
||||
@@ -145,7 +145,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
SceneObjectsFactory::SynchronizeNewPrefabInstances(context, prefabSyncData);
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
|
||||
}
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
{
|
||||
auto& stream = data[i];
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
@@ -154,20 +154,29 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
}
|
||||
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
||||
|
||||
// Pick prefab root object
|
||||
if (sceneObjects->IsEmpty())
|
||||
// Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it)
|
||||
if (withSynchronization)
|
||||
{
|
||||
LOG(Warning, "No valid objects in prefab. {0}", prefab->ToString());
|
||||
return nullptr;
|
||||
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
|
||||
SceneObjectsFactory::SynchronizePrefabInstances(context, prefabSyncData);
|
||||
}
|
||||
|
||||
// Pick prefab root object
|
||||
Actor* root = nullptr;
|
||||
const Guid prefabRootObjectId = prefab->GetRootObjectId();
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
for (int32 i = 0; i < dataCount && !root; i++)
|
||||
{
|
||||
if (JsonTools::GetGuid(data[i], "ID") == prefabRootObjectId)
|
||||
{
|
||||
root = dynamic_cast<Actor*>(sceneObjects->At(i));
|
||||
break;
|
||||
}
|
||||
if (!root)
|
||||
{
|
||||
// Fallback to the first actor that has no parent
|
||||
for (int32 i = 0; i < sceneObjects->Count() && !root; i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
if (obj && !obj->GetParent())
|
||||
root = dynamic_cast<Actor*>(obj);
|
||||
}
|
||||
}
|
||||
if (!root)
|
||||
@@ -176,13 +185,6 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it)
|
||||
if (withSynchronization)
|
||||
{
|
||||
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
|
||||
SceneObjectsFactory::SynchronizePrefabInstances(context, prefabSyncData);
|
||||
}
|
||||
|
||||
// Prepare parent linkage for prefab root actor
|
||||
if (root->_parent)
|
||||
root->_parent->Children.Remove(root);
|
||||
@@ -264,7 +266,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
||||
}
|
||||
|
||||
// Link objects to prefab (only deserialized from prefab data)
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
{
|
||||
auto& stream = data[i];
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
|
||||
@@ -89,7 +89,7 @@ API_CLASS(Static) class FLAXENGINE_API PrefabManager
|
||||
/// <param name="objectsCache">The options output objects cache that can be filled with prefab object id mapping to deserialized object (actor or script).</param>
|
||||
/// <param name="withSynchronization">True if perform prefab changes synchronization for the spawned objects. It will check if need to add new objects due to nested prefab modifications.</param>
|
||||
/// <returns>The created actor (root) or null if failed.</returns>
|
||||
static Actor* SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid, SceneObject*, HeapAllocation>* objectsCache, bool withSynchronization = false);
|
||||
static Actor* SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid, SceneObject*, HeapAllocation>* objectsCache, bool withSynchronization = true);
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the instance of the prefab objects. If parent actor is specified then created actors are fully initialized (OnLoad event and BeginPlay is called if parent actor is already during gameplay).
|
||||
@@ -100,7 +100,7 @@ API_CLASS(Static) class FLAXENGINE_API PrefabManager
|
||||
/// <param name="objectsCache">The options output objects cache that can be filled with prefab object id mapping to deserialized object (actor or script).</param>
|
||||
/// <param name="withSynchronization">True if perform prefab changes synchronization for the spawned objects. It will check if need to add new objects due to nested prefab modifications.</param>
|
||||
/// <returns>The created actor (root) or null if failed.</returns>
|
||||
static Actor* SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary<Guid, SceneObject*, HeapAllocation>* objectsCache, bool withSynchronization = false);
|
||||
static Actor* SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary<Guid, SceneObject*, HeapAllocation>* objectsCache, bool withSynchronization = true);
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
|
||||
Reference in New Issue
Block a user