Fix synchronizing nested prefabs when adding new ObjectsLookupIdMapping
#351
This commit is contained in:
@@ -576,7 +576,7 @@ namespace FlaxEditor.Viewport
|
||||
// Selected UI controls outline
|
||||
for (var i = 0; i < _window.Selection.Count; i++)
|
||||
{
|
||||
if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
|
||||
if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null)
|
||||
{
|
||||
var control = controlActor.Control;
|
||||
var bounds = Rectangle.FromPoints(control.PointToParent(this, Vector2.Zero), control.PointToParent(this, control.Size));
|
||||
|
||||
@@ -296,7 +296,7 @@ namespace FlaxEditor.Windows
|
||||
// Selected UI controls outline
|
||||
for (var i = 0; i < Editor.Instance.SceneEditing.Selection.Count; i++)
|
||||
{
|
||||
if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
|
||||
if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null)
|
||||
{
|
||||
var control = controlActor.Control;
|
||||
var bounds = Rectangle.FromPoints(control.PointToParent(_viewport, Vector2.Zero), control.PointToParent(_viewport, control.Size));
|
||||
|
||||
@@ -1037,9 +1037,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, bool autoI
|
||||
|
||||
// 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
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
|
||||
SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value);
|
||||
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||
|
||||
// Delete objects without parent
|
||||
for (int32 i = 1; i < objectsCount; i++)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "Engine/Core/Cache.h"
|
||||
#include "Engine/Debug/Exceptions/ArgumentException.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Scripting/Script.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -216,21 +217,57 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
|
||||
// TODO: consider caching actorToRemovedObjectsData per prefab
|
||||
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
|
||||
SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value);
|
||||
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||
}
|
||||
|
||||
// Delete objects without parent
|
||||
// Delete objects without parent or with invalid linkage to the prefab
|
||||
for (int32 i = 1; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
if (obj && obj->GetParent() == nullptr)
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
// Check for missing parent (eg. parent object has been deleted)
|
||||
if (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();
|
||||
continue;
|
||||
}
|
||||
|
||||
#if USE_EDITOR && !BUILD_RELEASE
|
||||
// Check for not being added to the parent (eg. invalid setup events fault on registration)
|
||||
auto actor = dynamic_cast<Actor*>(obj);
|
||||
auto script = dynamic_cast<Script*>(obj);
|
||||
if (obj->GetParent() == obj || (actor && !actor->GetParent()->Children.Contains(actor)) || (script && !script->GetParent()->Scripts.Contains(script)))
|
||||
{
|
||||
sceneObjects->At(i) = nullptr;
|
||||
LOG(Warning, "Scene object {0} {1} has invalid parent object linkage after load. Removing it.", obj->GetID(), obj->ToString());
|
||||
obj->DeleteObject();
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_EDITOR && BUILD_DEBUG
|
||||
// Check for being added to parent not from spawned prefab (eg. invalid parentId linkage fault)
|
||||
bool hasParentInInstance = false;
|
||||
for (int32 j = 0; j < sceneObjects->Count(); j++)
|
||||
{
|
||||
if (sceneObjects->At(j) == obj->GetParent())
|
||||
{
|
||||
hasParentInInstance = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasParentInInstance)
|
||||
{
|
||||
sceneObjects->At(i) = nullptr;
|
||||
LOG(Warning, "Scene object {0} {1} has invalid parent object after load. Removing it.", obj->GetID(), obj->ToString());
|
||||
obj->DeleteObject();
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Link objects to prefab (only deserialized from prefab data)
|
||||
|
||||
@@ -204,6 +204,8 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array<SceneObject*>& sceneO
|
||||
{
|
||||
PROFILE_CPU_NAMED("SynchronizePrefabInstances");
|
||||
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping);
|
||||
|
||||
// Check all objects with prefab linkage for moving to a proper parent
|
||||
const int32 objectsToCheckCount = sceneObjects.Count();
|
||||
for (int32 i = 0; i < objectsToCheckCount; i++)
|
||||
@@ -261,7 +263,7 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array<SceneObject*>& sceneO
|
||||
// Preserve order in parent (values from prefab are used)
|
||||
if (i != 0)
|
||||
{
|
||||
const auto defaultInstance = prefab ? prefab->GetDefaultInstance(obj->GetPrefabObjectID()) : nullptr;
|
||||
const auto defaultInstance = prefab->GetDefaultInstance(obj->GetPrefabObjectID());
|
||||
if (defaultInstance)
|
||||
{
|
||||
obj->SetOrderInParent(defaultInstance->GetOrderInParent());
|
||||
@@ -315,6 +317,7 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array<SceneObject*>& sceneO
|
||||
continue;
|
||||
|
||||
// Create instance (including all children)
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping);
|
||||
SynchronizeNewPrefabInstance(prefab, actor, prefabObjectId, sceneObjects, modifier);
|
||||
}
|
||||
}
|
||||
@@ -325,6 +328,8 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array<SceneObject*>& sceneO
|
||||
SceneObject* obj = sceneObjects[i];
|
||||
obj->PostLoad();
|
||||
}
|
||||
|
||||
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||
}
|
||||
|
||||
void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::DeserializeStream& value)
|
||||
@@ -424,6 +429,7 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstance(Prefab* prefab, Actor* ac
|
||||
|
||||
// Map prefab object ID to the new prefab object instance
|
||||
modifier->IdsMapping[prefabObjectId] = Guid::New();
|
||||
Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping);
|
||||
|
||||
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
||||
auto child = Spawn(*(ISerializable::DeserializeStream*)prefabData, modifier);
|
||||
|
||||
Reference in New Issue
Block a user