Refactor prefab instances loading to improve refs loading between prefab objects

This commit is contained in:
Wojtek Figat
2021-08-19 13:02:56 +02:00
parent 066c668f6f
commit 4c1dbb7f8e
6 changed files with 435 additions and 290 deletions

View File

@@ -933,42 +933,35 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
// Fire event
CallSceneEvent(SceneEventType::OnSceneLoading, scene, sceneId);
// Maps the loaded actor object to the json data with the RemovedObjects array (used to skip restoring objects removed per prefab instance)
SceneObjectsFactory::ActorToRemovedObjectsDataLookup actorToRemovedObjectsData;
// Loaded scene objects list
CollectionPoolCache<ActorsCache::SceneObjectsListType>::ScopeCache sceneObjects = ActorsCache::SceneObjectsListCache.Get();
sceneObjects->Resize(objectsCount);
sceneObjects->At(0) = scene;
SceneObjectsFactory::Context context(modifier.Value);
{
PROFILE_CPU_NAMED("Spawn");
// Spawn all scene objects
for (int32 i = 1; i < objectsCount; i++) // start from 1. at index [0] was scene
{
auto& objData = data[i];
auto obj = SceneObjectsFactory::Spawn(objData, modifier.Value);
auto& stream = data[i];
auto obj = SceneObjectsFactory::Spawn(context, stream);
sceneObjects->At(i) = obj;
if (obj)
{
// Register object so it can be later referenced during deserialization (FindObject will work to link references between objects)
obj->RegisterObject();
// Special case for actors
if (auto actor = dynamic_cast<Actor*>(obj))
{
// Check for RemovedObjects listing
const auto removedObjects = SERIALIZE_FIND_MEMBER(objData, "RemovedObjects");
if (removedObjects != objData.MemberEnd())
{
actorToRemovedObjectsData.Add(actor, &removedObjects->value);
}
}
}
else
SceneObjectsFactory::HandleObjectDeserializationError(stream);
}
}
SceneObjectsFactory::PrefabSyncData prefabSyncData(*sceneObjects.Value, data, modifier.Value);
SceneObjectsFactory::SetupPrefabInstances(context, prefabSyncData);
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
SceneObjectsFactory::SynchronizeNewPrefabInstances(context, prefabSyncData);
// /\ all above this has to be done on an any thread
// \/ all below this has to be done on multiple threads at once
@@ -984,9 +977,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
auto& objData = data[i];
auto obj = sceneObjects->At(i);
if (obj)
SceneObjectsFactory::Deserialize(obj, objData, modifier.Value);
else
SceneObjectsFactory::HandleObjectDeserializationError(objData);
SceneObjectsFactory::Deserialize(context, obj, objData);
}
Scripting::ObjectsLookupIdMapping.Set(nullptr);
}
@@ -994,11 +985,15 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
// /\ all above this has to be done on multiple threads at once
// \/ all below this has to be done on an any thread
// Synchronize prefab instances (prefab may have objects removed or reordered so deserialized instances need to synchronize with it)
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
SceneObjectsFactory::SynchronizePrefabInstances(context, prefabSyncData);
// Call post load event to connect all scene actors
{
PROFILE_CPU_NAMED("Post Load");
for (int32 i = 0; i < objectsCount; i++)
for (int32 i = 0; i < sceneObjects->Count(); i++)
{
SceneObject* obj = sceneObjects->At(i);
if (obj)
@@ -1006,17 +1001,12 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
}
}
// Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it)
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value);
// Delete objects without parent
for (int32 i = 1; i < objectsCount; i++)
{
SceneObject* obj = sceneObjects->At(i);
if (obj && obj->GetParent() == nullptr)
{
sceneObjects->At(i) = nullptr;
LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString());
obj->DeleteObject();
}