@@ -336,7 +336,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneObject* obj = SceneObjectsFactory::Spawn(context, *(ISerializable::DeserializeStream*)data);
|
SceneObject* obj = SceneObjectsFactory::Spawn(context, *data);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
continue;
|
continue;
|
||||||
obj->RegisterObject();
|
obj->RegisterObject();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Prefab.h"
|
#include "Prefab.h"
|
||||||
#include "Engine/Serialization/JsonTools.h"
|
#include "Engine/Serialization/JsonTools.h"
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Level/Prefabs/PrefabManager.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()
|
Actor* Prefab::GetDefaultInstance()
|
||||||
{
|
{
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|||||||
@@ -50,11 +50,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the root object identifier (prefab object ID). Asset must be loaded.
|
/// Gets the root object identifier (prefab object ID). Asset must be loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Guid GetRootObjectId() const
|
Guid GetRootObjectId() const;
|
||||||
{
|
|
||||||
ASSERT(IsLoaded());
|
|
||||||
return ObjectsIds[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Requests the default prefab object instance. Deserializes the prefab objects from the asset. Skips if already done.
|
/// 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++)
|
for (int32 i = 0; i < objectsCount; i++)
|
||||||
{
|
{
|
||||||
auto& stream = data[i];
|
auto& stream = data[i];
|
||||||
auto obj = SceneObjectsFactory::Spawn(context, stream);
|
SceneObject* obj = SceneObjectsFactory::Spawn(context, stream);
|
||||||
sceneObjects->At(i) = obj;
|
sceneObjects->At(i) = obj;
|
||||||
if (obj)
|
if (obj)
|
||||||
obj->RegisterObject();
|
obj->RegisterObject();
|
||||||
@@ -146,16 +146,25 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
|||||||
}
|
}
|
||||||
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
Scripting::ObjectsLookupIdMapping.Set(prevIdMapping);
|
||||||
|
|
||||||
// Assume that prefab has always only one root actor that is serialized first
|
// Pick prefab root object
|
||||||
if (sceneObjects.Value->IsEmpty())
|
if (sceneObjects->IsEmpty())
|
||||||
{
|
{
|
||||||
LOG(Warning, "No valid objects in prefab.");
|
LOG(Warning, "No valid objects in prefab.");
|
||||||
return nullptr;
|
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)
|
if (!root)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Failed to load prefab root object.");
|
LOG(Warning, "Missing prefab root object.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +176,8 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare parent linkage for prefab root actor
|
// Prepare parent linkage for prefab root actor
|
||||||
|
if (root->_parent)
|
||||||
|
root->_parent->Children.Remove(root);
|
||||||
root->_parent = parent;
|
root->_parent = parent;
|
||||||
if (parent)
|
if (parent)
|
||||||
parent->Children.Add(root);
|
parent->Children.Add(root);
|
||||||
@@ -174,16 +185,16 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
|||||||
// Link actors hierarchy
|
// Link actors hierarchy
|
||||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||||
{
|
{
|
||||||
auto obj = sceneObjects->At(i);
|
SceneObject* obj = sceneObjects->At(i);
|
||||||
if (obj)
|
if (obj)
|
||||||
obj->Initialize();
|
obj->Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete objects without parent or with invalid linkage to the prefab
|
// 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);
|
SceneObject* obj = sceneObjects->At(i);
|
||||||
if (!obj)
|
if (!obj || obj == root)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check for missing parent (eg. parent object has been deleted)
|
// 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");
|
const Guid prefabObjectId = JsonTools::GetGuid(stream, "ID");
|
||||||
if (objectsCache)
|
if (objectsCache)
|
||||||
objectsCache->Add(prefabObjectId, obj);
|
objectsCache->Add(prefabObjectId, obj);
|
||||||
obj->_prefabID = prefabId;
|
obj->LinkPrefab(prefabId, prefabObjectId);
|
||||||
obj->_prefabObjectID = prefabObjectId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update transformations
|
// Update transformations
|
||||||
@@ -317,7 +327,7 @@ bool PrefabManager::CreatePrefab(Actor* targetActor, const StringView& outputPat
|
|||||||
writer.StartArray();
|
writer.StartArray();
|
||||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||||
{
|
{
|
||||||
SceneObject* obj = sceneObjects.Value->At(i);
|
SceneObject* obj = sceneObjects->At(i);
|
||||||
writer.SceneObject(obj);
|
writer.SceneObject(obj);
|
||||||
}
|
}
|
||||||
writer.EndArray();
|
writer.EndArray();
|
||||||
@@ -335,7 +345,7 @@ bool PrefabManager::CreatePrefab(Actor* targetActor, const StringView& outputPat
|
|||||||
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||||
{
|
{
|
||||||
// Generate new IDs for the prefab objects (other than reference instance used to create prefab)
|
// 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());
|
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++)
|
for (int32 i = 0; i < sceneObjects->Count(); i++)
|
||||||
{
|
{
|
||||||
SceneObject* obj = sceneObjects.Value->At(i);
|
SceneObject* obj = sceneObjects->At(i);
|
||||||
Guid prefabObjectId;
|
Guid prefabObjectId;
|
||||||
|
|
||||||
if (objectInstanceIdToPrefabObjectId.TryGet(obj->GetSceneObjectId(), 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);
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(SceneObject);
|
||||||
friend PrefabInstanceData;
|
friend PrefabInstanceData;
|
||||||
|
friend PrefabManager;
|
||||||
friend Actor;
|
friend Actor;
|
||||||
friend Level;
|
friend Level;
|
||||||
friend ScriptsFactory;
|
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
|
// Get object id
|
||||||
Guid id = JsonTools::GetGuid(stream, "ID");
|
Guid id = JsonTools::GetGuid(stream, "ID");
|
||||||
@@ -81,7 +81,7 @@ SceneObject* SceneObjectsFactory::Spawn(Context& context, ISerializable::Deseria
|
|||||||
context.Modifier->IdsMapping[prefabObjectId] = id;
|
context.Modifier->IdsMapping[prefabObjectId] = id;
|
||||||
|
|
||||||
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
||||||
obj = Spawn(context, *(ISerializable::DeserializeStream*)prefabData);
|
obj = Spawn(context, *prefabData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -584,7 +584,7 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstance(Context& context, PrefabS
|
|||||||
data.Modifier->IdsMapping[prefabObjectId] = id;
|
data.Modifier->IdsMapping[prefabObjectId] = id;
|
||||||
|
|
||||||
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
// Create prefab instance (recursive prefab loading to support nested prefabs)
|
||||||
auto child = Spawn(context, *(ISerializable::DeserializeStream*)prefabData);
|
auto child = Spawn(context, *prefabData);
|
||||||
if (!child)
|
if (!child)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Failed to create object {1} from prefab {0}.", prefab->ToString(), prefabObjectId);
|
LOG(Warning, "Failed to create object {1} from prefab {0}.", prefab->ToString(), prefabObjectId);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The serialization context.</param>
|
/// <param name="context">The serialization context.</param>
|
||||||
/// <param name="stream">The serialized data stream.</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>
|
/// <summary>
|
||||||
/// Deserializes the scene object from the specified data value.
|
/// Deserializes the scene object from the specified data value.
|
||||||
|
|||||||
Reference in New Issue
Block a user