diff --git a/Source/Engine/ContentImporters/ImportModel.cpp b/Source/Engine/ContentImporters/ImportModel.cpp index 77cac2f03..c8777779b 100644 --- a/Source/Engine/ContentImporters/ImportModel.cpp +++ b/Source/Engine/ContentImporters/ImportModel.cpp @@ -24,6 +24,7 @@ #include "Engine/Level/Scripts/ModelPrefab.h" #include "Engine/Platform/FileSystem.h" #include "Engine/Utilities/RectPack.h" +#include "Engine/Scripting/Scripting.h" #include "Engine/Profiler/ProfilerCPU.h" #include "AssetsImportingManager.h" @@ -169,6 +170,33 @@ bool SortMeshGroups(IGrouping const& i1, IGroupingGetType().GetDefaultInstance(); + src->Serialize(writer, defaultInstance); + writer.EndObject(); + + // Parse json + rapidjson_flax::Document document; + document.Parse(buffer.GetString(), buffer.GetSize()); + + // Strip unwanted data + document.RemoveMember("ID"); + document.RemoveMember("ParentID"); + document.RemoveMember("PrefabID"); + document.RemoveMember("PrefabObjectID"); + if (stripName) + document.RemoveMember("Name"); + + // Deserialize destination + auto modifier = Cache::ISerializeModifier.Get(); + dst->Deserialize(document, &*modifier); +} + CreateAssetResult ImportModel::Import(CreateAssetContext& context) { // Get import options @@ -677,6 +705,8 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa // Create prefab structure Dictionary nodeToActor; + Dictionary newPrefabObjects; // Maps prefab object id to the restored and linked object + rapidjson_flax::StringBuffer jsonBuffer; Array nodeActors; Actor* rootActor = nullptr; for (int32 nodeIndex = 0; nodeIndex < data.Nodes.Count(); nodeIndex++) @@ -767,7 +797,6 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa // Link with object from prefab (if reimporting) if (prefab) { - rapidjson_flax::StringBuffer buffer; for (Actor* a : nodeActors) { for (const auto& i : prefab->ObjectsCache) @@ -779,33 +808,12 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa continue; // Preserve local changes made in the prefab - { - // Serialize - buffer.Clear(); - CompactJsonWriter writer(buffer); - writer.StartObject(); - const void* defaultInstance = o->GetType().GetDefaultInstance(); - o->Serialize(writer, defaultInstance); - writer.EndObject(); - - // Parse json - rapidjson_flax::Document document; - document.Parse(buffer.GetString(), buffer.GetSize()); - - // Strip unwanted data - document.RemoveMember("ID"); - document.RemoveMember("ParentID"); - document.RemoveMember("PrefabID"); - document.RemoveMember("PrefabObjectID"); - document.RemoveMember("Name"); - - // Deserialize object - auto modifier = Cache::ISerializeModifier.Get(); - a->Deserialize(document, &*modifier); - } + CloneObject(jsonBuffer, o, a, true); // Mark as this object already exists in prefab so will be preserved when updating it - a->LinkPrefab(o->GetPrefabID(), o->GetPrefabObjectID()); + const Guid prefabObjectId = o->GetPrefabObjectID(); + a->LinkPrefab(o->GetPrefabID(), prefabObjectId); + newPrefabObjects.Add(prefabObjectId, a); break; } } @@ -826,12 +834,43 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa { if (i.Value->GetTypeHandle() == modelPrefabScript->GetTypeHandle()) { - modelPrefabScript->LinkPrefab(i.Value->GetPrefabID(), i.Value->GetPrefabObjectID()); + const Guid prefabObjectId = i.Value->GetPrefabObjectID(); + modelPrefabScript->LinkPrefab(i.Value->GetPrefabID(), prefabObjectId); + newPrefabObjects.Add(prefabObjectId, modelPrefabScript); break; } } } } + if (prefab) + { + // Preserve existing objects added by user (eg. colliders, sfx, vfx, scripts) + for (const auto& i : prefab->ObjectsCache) + { + // Skip already restored objects + const Guid prefabObjectId = i.Key; + if (newPrefabObjects.ContainsKey(prefabObjectId)) + continue; + SceneObject* defaultObject = i.Value; + // TODO: ignore objects that were imported previously but not now (eg. mesh was removed from source asset) + + // Find parent to link + SceneObject* parent; + if (!newPrefabObjects.TryGet(defaultObject->GetParent()->GetPrefabObjectID(), parent)) + continue; + + // Duplicate object + SceneObject* restoredObject = (SceneObject*)Scripting::NewObject(defaultObject->GetTypeHandle()); + if (!restoredObject) + continue; + CloneObject(jsonBuffer, defaultObject, restoredObject); + restoredObject->SetParent((Actor*)parent); + + // Link with existing prefab instance + restoredObject->LinkPrefab(i.Value->GetPrefabID(), prefabObjectId); + newPrefabObjects.Add(prefabObjectId, restoredObject); + } + } // Create prefab instead of native asset bool failed;