@@ -304,6 +304,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
{
|
||||
for (int32 instanceIndex = 0; instanceIndex < prefabInstancesData.Count(); instanceIndex++)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Instance");
|
||||
auto& instance = prefabInstancesData[instanceIndex];
|
||||
ISerializeModifierCacheType modifier = Cache::ISerializeModifier.Get();
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
|
||||
@@ -377,6 +378,10 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
sceneObjects->Add(obj);
|
||||
}
|
||||
|
||||
// Generate nested prefab instances to properly handle Ids Mapping within each nested prefab
|
||||
SceneObjectsFactory::PrefabSyncData prefabSyncData(*sceneObjects.Value, instance.Data, modifier.Value);
|
||||
SceneObjectsFactory::SetupPrefabInstances(context, prefabSyncData);
|
||||
|
||||
// Apply modifications
|
||||
for (int32 i = existingObjectsCount - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -388,6 +393,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
if (prefabObjectIdToDiffData.TryGet(obj->GetPrefabObjectID(), data))
|
||||
{
|
||||
// Apply prefab changes
|
||||
context.SetupIdsMapping(obj, modifier.Value);
|
||||
obj->Deserialize(*(ISerializable::DeserializeStream*)data, modifier.Value);
|
||||
}
|
||||
else
|
||||
@@ -424,7 +430,6 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
|
||||
int32 dataIndex;
|
||||
if (instance.PrefabInstanceIdToDataIndex.TryGet(obj->GetSceneObjectId(), dataIndex))
|
||||
{
|
||||
@@ -440,6 +445,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
data.RemoveMember("ParentID");
|
||||
#endif
|
||||
|
||||
context.SetupIdsMapping(obj, modifier.Value);
|
||||
obj->Deserialize(data, modifier.Value);
|
||||
|
||||
// Preserve order in parent (values from prefab are used)
|
||||
@@ -527,6 +533,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
{
|
||||
if (prefabInstancesData.IsEmpty())
|
||||
return false;
|
||||
PROFILE_CPU();
|
||||
|
||||
// Fully serialize default instance scene objects (accumulate all prefab and nested prefabs changes into a single linear list of objects)
|
||||
rapidjson_flax::Document defaultInstanceData;
|
||||
@@ -926,7 +933,6 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
|
||||
// TODO: what if user applied prefab with references to the other objects from scene? clear them or what?
|
||||
JsonTools::ChangeIds(diffDataDocument, objectInstanceIdToPrefabObjectId);
|
||||
}
|
||||
dataBuffer.Clear();
|
||||
CollectionPoolCache<ActorsCache::SceneObjectsListType>::ScopeCache sceneObjects = ActorsCache::SceneObjectsListCache.Get();
|
||||
|
||||
// Destroy default instance and some cache data in Prefab
|
||||
@@ -1002,6 +1008,32 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
|
||||
obj->RegisterObject();
|
||||
}
|
||||
|
||||
// Generate nested prefab instances to properly handle Ids Mapping within each nested prefab
|
||||
rapidjson_flax::Document targetDataDocument;
|
||||
if (NestedPrefabs.HasItems())
|
||||
{
|
||||
targetDataDocument.Parse(dataBuffer.GetString(), dataBuffer.GetSize());
|
||||
SceneObjectsFactory::PrefabSyncData prefabSyncData(*sceneObjects.Value, targetDataDocument, modifier.Value);
|
||||
SceneObjectsFactory::SetupPrefabInstances(context, prefabSyncData);
|
||||
|
||||
if (context.Instances.HasItems())
|
||||
{
|
||||
// Only main prefab instance is allowed (in case nested prefab was added to this prefab)
|
||||
for (auto i = context.ObjectToInstance.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value != 0)
|
||||
context.ObjectToInstance.Remove(i);
|
||||
}
|
||||
context.Instances.Resize(1);
|
||||
|
||||
// Trash object mapping to prevent messing up prefab structure when applying hierarchy changes (only nested instances are used)
|
||||
context.Instances[0].IdsMapping.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
dataBuffer.Clear();
|
||||
auto originalIdsMapping = modifier.Value->IdsMapping;
|
||||
|
||||
// Deserialize prefab objects and apply modifications
|
||||
for (int32 i = 0; i < ObjectsCount; i++)
|
||||
{
|
||||
@@ -1037,6 +1069,9 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
|
||||
}
|
||||
}
|
||||
|
||||
// Use the initial Ids Mapping (SetupIdsMapping overrides it for instanced prefabs)
|
||||
modifier.Value->IdsMapping = originalIdsMapping;
|
||||
|
||||
// Deserialize new prefab objects
|
||||
newPrefabInstanceIdToDataIndexCounter = 0;
|
||||
for (auto i = newPrefabInstanceIdToDataIndex.Begin(); i.IsNotEnd(); ++i)
|
||||
@@ -1283,6 +1318,10 @@ bool Prefab::UpdateInternal(const Array<SceneObject*>& defaultInstanceObjects, r
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -172,7 +172,9 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const SpawnOptions& options)
|
||||
SceneObjectsFactory::HandleObjectDeserializationError(stream);
|
||||
}
|
||||
SceneObjectsFactory::PrefabSyncData prefabSyncData(*sceneObjects.Value, data, modifier.Value);
|
||||
if (options.WithSync)
|
||||
bool withSync = options.WithSync || prefab->NestedPrefabs.HasItems(); // Nested prefabs needs prefab instances generation for correct IdsMapping if the same prefab exists multiple times
|
||||
// TODO: let prefab check if has multiple nested prefabs at cook time?
|
||||
if (withSync)
|
||||
{
|
||||
// Synchronize new prefab instances (prefab may have new objects added so deserialized instances need to synchronize with it)
|
||||
// TODO: resave and force sync prefabs during game cooking so this step could be skipped in game
|
||||
@@ -187,14 +189,14 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const SpawnOptions& options)
|
||||
if (obj)
|
||||
SceneObjectsFactory::Deserialize(context, obj, stream);
|
||||
}
|
||||
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
||||
|
||||
// Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it)
|
||||
if (options.WithSync)
|
||||
if (withSync)
|
||||
{
|
||||
// TODO: resave and force sync scenes during game cooking so this step could be skipped in game
|
||||
SceneObjectsFactory::SynchronizePrefabInstances(context, prefabSyncData);
|
||||
}
|
||||
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
||||
|
||||
// Pick prefab root object
|
||||
Actor* root = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user