Optimize SceneObjectsFactory::SynchronizeNewPrefabInstances when loading large scenes
This commit is contained in:
@@ -148,6 +148,10 @@ Asset::LoadResult Prefab::loadAsset()
|
||||
ObjectsDataCache.Add(objectId, &objData);
|
||||
ObjectsCount++;
|
||||
|
||||
Guid parentID;
|
||||
if (JsonTools::GetGuidIfValid(parentID, objData, "ParentID"))
|
||||
ObjectsHierarchyCache[parentID].Add(objectId);
|
||||
|
||||
Guid prefabId = JsonTools::GetGuid(objData, "PrefabID");
|
||||
if (prefabId.IsValid() && !NestedPrefabs.Contains(prefabId))
|
||||
{
|
||||
@@ -186,6 +190,8 @@ void Prefab::unload(bool isReloading)
|
||||
NestedPrefabs.Resize(0);
|
||||
ObjectsDataCache.Clear();
|
||||
ObjectsDataCache.SetCapacity(0);
|
||||
ObjectsHierarchyCache.Clear();
|
||||
ObjectsHierarchyCache.SetCapacity(0);
|
||||
ObjectsCache.Clear();
|
||||
ObjectsCache.SetCapacity(0);
|
||||
if (_defaultInstance)
|
||||
|
||||
@@ -41,6 +41,11 @@ public:
|
||||
/// </summary>
|
||||
Dictionary<Guid, const ISerializable::DeserializeStream*> ObjectsDataCache;
|
||||
|
||||
/// <summary>
|
||||
/// The object hierarchy cache that maps the PrefabObjectID into the list of children (identified also by PrefabObjectID). Objects without any children are not included for sake of optimization. Used for quick validation of the structure of loaded prefab instances. Valid only if asset is loaded.
|
||||
/// </summary>
|
||||
Dictionary<Guid, Array<Guid>> ObjectsHierarchyCache;
|
||||
|
||||
/// <summary>
|
||||
/// The objects cache maps the id of the object contained in the prefab asset (actor or script) to the default instance deserialized from prefab data. Valid only if asset is loaded and GetDefaultInstance was called.
|
||||
/// </summary>
|
||||
|
||||
@@ -719,26 +719,21 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Context& context, PrefabSyn
|
||||
|
||||
void SceneObjectsFactory::SynchronizeNewPrefabInstances(Context& context, PrefabSyncData& data, Prefab* prefab, Actor* actor, const Guid& actorPrefabObjectId, int32 i, const ISerializable::DeserializeStream& stream)
|
||||
{
|
||||
// Check for RemovedObjects list
|
||||
// Use cached acceleration structure for prefab hierarchy validation
|
||||
const auto* hierarchy = prefab->ObjectsHierarchyCache.TryGet(actorPrefabObjectId);
|
||||
if (!hierarchy)
|
||||
return;
|
||||
const Guid actorId = actor->GetID();
|
||||
const auto removedObjects = SERIALIZE_FIND_MEMBER(stream, "RemovedObjects");
|
||||
|
||||
// Check if the given actor has new children or scripts added (inside the prefab that it uses)
|
||||
// TODO: consider caching prefab objects structure maybe to boost this logic?
|
||||
for (auto it = prefab->ObjectsDataCache.Begin(); it.IsNotEnd(); ++it)
|
||||
for (const Guid& prefabObjectId : *hierarchy)
|
||||
{
|
||||
// Use only objects that are linked to the current actor
|
||||
const Guid parentId = JsonTools::GetGuid(*it->Value, "ParentID");
|
||||
if (parentId != actorPrefabObjectId)
|
||||
continue;
|
||||
|
||||
// Skip if object was marked to be removed per instance
|
||||
const Guid prefabObjectId = JsonTools::GetGuid(*it->Value, "ID");
|
||||
if (removedObjects != stream.MemberEnd())
|
||||
{
|
||||
auto& list = removedObjects->value;
|
||||
const int32 size = static_cast<int32>(list.Size());
|
||||
const rapidjson::SizeType size = list.Size();
|
||||
bool removed = false;
|
||||
for (int32 j = 0; j < size; j++)
|
||||
for (rapidjson::SizeType j = 0; j < size; j++)
|
||||
{
|
||||
if (JsonTools::GetGuid(list[j]) == prefabObjectId)
|
||||
{
|
||||
@@ -754,10 +749,19 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstances(Context& context, Prefab
|
||||
bool spawned = false;
|
||||
int32 childSearchStart = i + 1; // Objects are serialized with parent followed by its children
|
||||
int32 instanceIndex = -1;
|
||||
if (context.ObjectToInstance.TryGet(actor->GetID(), instanceIndex) && context.Instances[instanceIndex].Prefab == prefab)
|
||||
if (context.ObjectToInstance.TryGet(actorId, instanceIndex) && context.Instances[instanceIndex].Prefab == prefab)
|
||||
{
|
||||
// Quickly check if that object exists
|
||||
auto& prefabInstance = context.Instances[instanceIndex];
|
||||
Guid id;
|
||||
int32 idInstanceIndex;
|
||||
if (prefabInstance.IdsMapping.TryGet(prefabObjectId, id) &&
|
||||
context.ObjectToInstance.TryGet(id, idInstanceIndex) &&
|
||||
idInstanceIndex == instanceIndex)
|
||||
continue;
|
||||
|
||||
// Start searching from the beginning of that prefab instance (eg. in case prefab objects were reordered)
|
||||
childSearchStart = Math::Min(childSearchStart, context.Instances[instanceIndex].StatIndex);
|
||||
childSearchStart = Math::Min(childSearchStart, prefabInstance.StatIndex);
|
||||
}
|
||||
for (int32 j = childSearchStart; j < data.InitialCount; j++)
|
||||
{
|
||||
@@ -773,7 +777,7 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstances(Context& context, Prefab
|
||||
|
||||
// Map prefab object ID to this actor's prefab instance so the new objects gets added to it
|
||||
context.SetupIdsMapping(actor, data.Modifier);
|
||||
data.Modifier->IdsMapping[actorPrefabObjectId] = actor->GetID();
|
||||
data.Modifier->IdsMapping[actorPrefabObjectId] = actorId;
|
||||
Scripting::ObjectsLookupIdMapping.Set(&data.Modifier->IdsMapping);
|
||||
|
||||
// Create instance (including all children)
|
||||
|
||||
Reference in New Issue
Block a user