@@ -336,7 +336,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
||||
continue;
|
||||
}
|
||||
|
||||
SceneObject* obj = SceneObjectsFactory::Spawn(context, *(ISerializable::DeserializeStream*)data);
|
||||
SceneObject* obj = SceneObjectsFactory::Spawn(context, *data);
|
||||
if (!obj)
|
||||
continue;
|
||||
obj->RegisterObject();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Prefab.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Level/Prefabs/PrefabManager.h"
|
||||
@@ -21,6 +22,36 @@ Prefab::Prefab(const SpawnParams& params, const AssetInfo* info)
|
||||
{
|
||||
}
|
||||
|
||||
Guid Prefab::GetRootObjectId() const
|
||||
{
|
||||
ASSERT(IsLoaded());
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Root is always the first but handle case when prefab root was reordered in the base prefab while the nested prefab has still the old state
|
||||
// TODO: resave and force sync prefabs during game cooking so this step could be skipped in game
|
||||
int32 objectIndex = 0;
|
||||
if (NestedPrefabs.HasItems())
|
||||
{
|
||||
const auto& data = *Data;
|
||||
const Guid basePrefabId = JsonTools::GetGuid(data[objectIndex], "PrefabID");
|
||||
if (const auto basePrefab = Content::Load<Prefab>(basePrefabId))
|
||||
{
|
||||
const Guid basePrefabRootId = basePrefab->GetRootObjectId();
|
||||
for (int32 i = 0; i < ObjectsCount; i++)
|
||||
{
|
||||
const Guid prefabObjectId = JsonTools::GetGuid(data[i], "PrefabObjectID");
|
||||
if (prefabObjectId == basePrefabRootId)
|
||||
{
|
||||
objectIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ObjectsIds[objectIndex];
|
||||
}
|
||||
|
||||
Actor* Prefab::GetDefaultInstance()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
@@ -50,11 +50,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the root object identifier (prefab object ID). Asset must be loaded.
|
||||
/// </summary>
|
||||
Guid GetRootObjectId() const
|
||||
{
|
||||
ASSERT(IsLoaded());
|
||||
return ObjectsIds[0];
|
||||
}
|
||||
Guid GetRootObjectId() const;
|
||||
|
||||
/// <summary>
|
||||
/// Requests the default prefab object instance. Deserializes the prefab objects from the asset. Skips if already done.
|
||||
|
||||
@@ -121,7 +121,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
{
|
||||
auto& stream = data[i];
|
||||
auto obj = SceneObjectsFactory::Spawn(context, stream);
|
||||
SceneObject* obj = SceneObjectsFactory::Spawn(context, stream);
|
||||
sceneObjects->At(i) = obj;
|
||||
if (obj)
|
||||
obj->RegisterObject();
|
||||
@@ -146,16 +146,25 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
}
|
||||
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
||||
|
||||
// Assume that prefab has always only one root actor that is serialized first
|
||||
if (sceneObjects.Value->IsEmpty())
|
||||
// Pick prefab root object
|
||||
if (sceneObjects->IsEmpty())
|
||||
{
|
||||
LOG(Warning, "No valid objects in prefab.");
|
||||
return nullptr;
|
||||
}
|
||||
auto root = (Actor*)sceneObjects.Value->At(0);
|
||||
Actor* root = nullptr;
|
||||
const Guid prefabRootObjectId = prefab->GetRootObjectId();
|
||||
for (int32 i = 0; i < objectsCount; i++)
|
||||
{
|
||||
if (JsonTools::GetGuid(data[i], "ID") == prefabRootObjectId)
|
||||
{
|
||||
root = dynamic_cast<Actor*>(sceneObjects->At(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!root)
|
||||
{
|
||||
LOG(Warning, "Failed to load prefab root object.");
|
||||
LOG(Warning, "Missing prefab root object.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -167,6 +176,8 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
}
|
||||
|
||||
// Prepare parent linkage for prefab root actor
|
||||
if (root->_parent)
|
||||
root->_parent->Children.Remove(root);
|
||||
root->_parent = parent;
|
||||
if (parent)
|
||||
parent->Children.Add(root);
|
||||
@@ -174,16 +185,16 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
// Link actors hierarchy
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
auto obj = sceneObjects->At(i);
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
if (obj)
|
||||
obj->Initialize();
|
||||
}
|
||||
|
||||
// Delete objects without parent or with invalid linkage to the prefab
|
||||
for (int32 i = 1; i < sceneObjects->Count(); i++)
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
if (!obj)
|
||||
if (!obj || obj == root)
|
||||
continue;
|
||||
|
||||
// Check for missing parent (eg. parent object has been deleted)
|
||||
@@ -251,8 +262,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
const Guid prefabObjectId = JsonTools::GetGuid(stream, "ID");
|
||||
if (objectsCache)
|
||||
objectsCache->Add(prefabObjectId, obj);
|
||||
obj->_prefabID = prefabId;
|
||||
obj->_prefabObjectID = prefabObjectId;
|
||||
obj->LinkPrefab(prefabId, prefabObjectId);
|
||||
}
|
||||
|
||||
// Update transformations
|
||||
@@ -317,7 +327,7 @@ bool PrefabManager::CreatePrefab(Actor* targetActor, const StringView& outputPat
|
||||
writer.StartArray();
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects.Value->At(i);
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
writer.SceneObject(obj);
|
||||
}
|
||||
writer.EndArray();
|
||||
@@ -335,7 +345,7 @@ bool PrefabManager::CreatePrefab(Actor* targetActor, const StringView& outputPat
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
// Generate new IDs for the prefab objects (other than reference instance used to create prefab)
|
||||
const SceneObject* obj = sceneObjects.Value->At(i);
|
||||
const SceneObject* obj = sceneObjects->At(i);
|
||||
objectInstanceIdToPrefabObjectId.Add(obj->GetSceneObjectId(), Guid::New());
|
||||
}
|
||||
{
|
||||
@@ -382,7 +392,7 @@ bool PrefabManager::CreatePrefab(Actor* targetActor, const StringView& outputPat
|
||||
|
||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects.Value->At(i);
|
||||
SceneObject* obj = sceneObjects->At(i);
|
||||
Guid prefabObjectId;
|
||||
|
||||
if (objectInstanceIdToPrefabObjectId.TryGet(obj->GetSceneObjectId(), prefabObjectId))
|
||||
|
||||
@@ -58,6 +58,7 @@ API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API SceneObject : public Scripting
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(SceneObject);
|
||||
friend PrefabInstanceData;
|
||||
friend PrefabManager;
|
||||
friend Actor;
|
||||
friend Level;
|
||||
friend ScriptsFactory;
|
||||
|
||||
@@ -31,7 +31,7 @@ void SceneObjectsFactory::Context::SetupIdsMapping(const SceneObject* obj)
|
||||
}
|
||||
}
|
||||
|
||||
SceneObject* SceneObjectsFactory::Spawn(Context& context, ISerializable::DeserializeStream& stream)
|
||||
SceneObject* SceneObjectsFactory::Spawn(Context& context, const ISerializable::DeserializeStream& stream)
|
||||
{
|
||||
// Get object id
|
||||
Guid id = JsonTools::GetGuid(stream, "ID");
|
||||
@@ -81,7 +81,7 @@ SceneObject* SceneObjectsFactory::Spawn(Context& context, ISerializable::Deseria
|
||||
context.Modifier->IdsMapping[prefabObjectId] = id;
|
||||
|
||||
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
||||
obj = Spawn(context, *(ISerializable::DeserializeStream*)prefabData);
|
||||
obj = Spawn(context, *prefabData);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -584,7 +584,7 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstance(Context& context, PrefabS
|
||||
data.Modifier->IdsMapping[prefabObjectId] = id;
|
||||
|
||||
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
||||
auto child = Spawn(context, *(ISerializable::DeserializeStream*)prefabData);
|
||||
auto child = Spawn(context, *prefabData);
|
||||
if (!child)
|
||||
{
|
||||
LOG(Warning, "Failed to create object {1} from prefab {0}.", prefab->ToString(), prefabObjectId);
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="context">The serialization context.</param>
|
||||
/// <param name="stream">The serialized data stream.</param>
|
||||
static SceneObject* Spawn(Context& context, ISerializable::DeserializeStream& stream);
|
||||
static SceneObject* Spawn(Context& context, const ISerializable::DeserializeStream& stream);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the scene object from the specified data value.
|
||||
|
||||
Reference in New Issue
Block a user