diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 5de7aa6f..da146dd4 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -975,7 +975,7 @@ namespace Nuake { if (!savePath.empty()) { - newPrefab->SaveAs(savePath); + newPrefab->SaveAs(FileSystem::AbsoluteToRelative(savePath)); Selection.Entity.AddComponent().PrefabInstance = newPrefab; FileSystem::Scan(); FileSystemUI::m_CurrentDirectory = FileSystem::RootDirectory; @@ -2282,7 +2282,9 @@ namespace Nuake { char* file = (char*)payload->Data; std::string fullPath = std::string(file, 256); std::string relPath = FileSystem::AbsoluteToRelative(fullPath); - Prefab::New(relPath); + auto newPrefabInstance = Prefab::New(relPath); + newPrefabInstance->Root.GetComponent().SetPrefab(newPrefabInstance); + newPrefabInstance->Root.GetComponent().IsPrefab = true; } ImGui::EndDragDropTarget(); } diff --git a/Nuake/src/Resource/Prefab.cpp b/Nuake/src/Resource/Prefab.cpp index 3dd2b350..bfd27891 100644 --- a/Nuake/src/Resource/Prefab.cpp +++ b/Nuake/src/Resource/Prefab.cpp @@ -1,5 +1,6 @@ #include "Prefab.h" #include "src/Scene/Components/ParentComponent.h" +#include namespace Nuake { @@ -27,7 +28,7 @@ namespace Nuake if (!prefabTextContent.empty()) { - newPrefab->Deserialize(json::parse(prefabTextContent)); + newPrefab->Deserialize(json::parse(prefabTextContent), false); } } @@ -52,6 +53,153 @@ namespace Nuake return newPrefab; } + void Prefab::ReInstance() + { + if (FileSystem::FileExists(Path, false)) + { + for (auto& c : Entities) + { + if (c.IsValid() && c != Root) + { + + } + } + + std::string prefabTextContent = FileSystem::ReadFile(Path); + if (!prefabTextContent.empty()) + { + Deserialize(json::parse(prefabTextContent), true); + } + } + } + + bool Prefab::Deserialize(const json & j, bool skipRoot) + { + if (j == "") + return false; + + Path = j["Path"]; + + if (j.contains("DisplayName")) + { + DisplayName = j["DisplayName"]; + } + + if (j.contains("Description")) + { + Description = j["Description"]; + } + + if (j.contains("Entities")) + { + auto scene = Engine::GetCurrentScene(); + + std::map newIdsLut; + for (json e : j["Entities"]) + { + if (e["NameComponent"]["ID"] == j["Root"] && skipRoot) + { + newIdsLut[e["NameComponent"]["ID"]] = e["NameComponent"]["ID"]; + continue; + } + + Entity entity = { scene->m_Registry.create(), scene.get() }; + entity.Deserialize(e); // Id gets overriden by serialized id. + + auto& nameComponent = entity.GetComponent(); + bool isRoot = false; + if (nameComponent.ID == j["Root"]) + { + isRoot = true; // We found the root entity of the prefab. + auto& parentComponent = entity.GetComponent(); + parentComponent.HasParent = false; + parentComponent.ParentID = 0; + } + + uint32_t oldId = nameComponent.ID; + uint32_t newId = OS::GetTime(); + nameComponent.Name = nameComponent.Name; + nameComponent.ID = newId; + + newIdsLut[oldId] = newId; + if (isRoot) + { + Root = entity; + entity.AddComponent(); + } + else + { + entity.AddComponent(); + } + + AddEntity(entity); + } + + // Set reference to the parent entity to children + for (auto& e : Entities) + { + if (!e.IsValid()) + { + continue; + } + + if (e.GetID() == Root.GetID()) + { + continue; + } + + auto& parentC = e.GetComponent(); + auto parent = Engine::GetCurrentScene()->GetEntityByID(newIdsLut[parentC.ParentID]); + if (parent.GetHandle() == 0) + { + Root.AddChild(e); + } + else + { + parent.AddChild(e); + } + + e.GetComponent().owner = Root; + } + + // Since the bones point to an entity, and we are instancing a prefab, the new skeleton is gonna be pointing to the wrong + // bones, we need to remap the skeleton to the new entities. We are simply reussing the same map we are using for the + // reparenting. Pretty neat. + std::function recursiveBoneRemapping = [&recursiveBoneRemapping, &newIdsLut](SkeletonNode& currentBone) + { + currentBone.EntityHandle = newIdsLut[currentBone.EntityHandle]; + for (SkeletonNode& bone : currentBone.Children) + { + recursiveBoneRemapping(bone); + } + }; + + // Do the remapping of the skeleton + for (auto& e : Entities) + { + if (!e.IsValid()) + { + continue; + } + + if (e.GetID() == Root.GetID() || !e.HasComponent()) + { + continue; + } + + auto& skinnedModelComponent = e.GetComponent(); + if (!skinnedModelComponent.ModelResource) + { + continue; + } + + SkeletonNode& currentBone = skinnedModelComponent.ModelResource->GetSkeletonRootNode(); + recursiveBoneRemapping(currentBone); + } + } + return true; + } + void Prefab::EntityWalker(Entity entity) { Root = entity; diff --git a/Nuake/src/Resource/Prefab.h b/Nuake/src/Resource/Prefab.h index 563b3e21..6bc3d634 100644 --- a/Nuake/src/Resource/Prefab.h +++ b/Nuake/src/Resource/Prefab.h @@ -4,6 +4,7 @@ #include "src/Resource/Serializable.h" #include "Engine.h" + #include #include #include @@ -35,6 +36,8 @@ namespace Nuake { Entities.push_back(entity); } + void ReInstance(); + void SaveAs(const std::string& path) { Path = path; @@ -169,101 +172,11 @@ namespace Nuake { bool Deserialize(const json& j) { - if (j == "") - return false; - - Path = j["Path"]; - - if (j.contains("DisplayName")) - { - DisplayName = j["DisplayName"]; - } - - if (j.contains("Description")) - { - Description = j["Description"]; - } - - if (j.contains("Entities")) - { - auto scene = Engine::GetCurrentScene(); - - std::map newIdsLut; - for (json e : j["Entities"]) - { - Entity entity = { scene->m_Registry.create(), scene.get() }; - entity.Deserialize(e); // Id gets overriden by serialized id. - - auto& nameComponent = entity.GetComponent(); - bool isRoot = false; - if (nameComponent.ID == j["Root"]) - { - isRoot = true; // We found the root entity of the prefab. - auto& parentComponent = entity.GetComponent(); - parentComponent.HasParent = false; - parentComponent.ParentID = 0; - } - - uint32_t oldId = nameComponent.ID; - uint32_t newId = OS::GetTime(); - nameComponent.Name = nameComponent.Name; - nameComponent.ID = newId; - - newIdsLut[oldId] = newId; - if (isRoot) - { - Root = entity; - } - - AddEntity(entity); - } - - // Set reference to the parent entity to children - for (auto& e : Entities) - { - if (e.GetID() == Root.GetID()) - { - continue; - } - - auto& parentC = e.GetComponent(); - auto parent = Engine::GetCurrentScene()->GetEntityByID(newIdsLut[parentC.ParentID]); - parent.AddChild(e); - } - - // Since the bones point to an entity, and we are instancing a prefab, the new skeleton is gonna be pointing to the wrong - // bones, we need to remap the skeleton to the new entities. We are simply reussing the same map we are using for the - // reparenting. Pretty neat. - std::function recursiveBoneRemapping = [&recursiveBoneRemapping, &newIdsLut](SkeletonNode& currentBone) - { - currentBone.EntityHandle = newIdsLut[currentBone.EntityHandle]; - for (SkeletonNode& bone : currentBone.Children) - { - recursiveBoneRemapping(bone); - } - }; - - // Do the remapping of the skeleton - for (auto& e : Entities) - { - if (e.GetID() == Root.GetID() || !e.HasComponent()) - { - continue; - } - - auto& skinnedModelComponent = e.GetComponent(); - if (!skinnedModelComponent.ModelResource) - { - continue; - } - - SkeletonNode& currentBone = skinnedModelComponent.ModelResource->GetSkeletonRootNode(); - recursiveBoneRemapping(currentBone); - } - } - return true; + return Deserialize(j, false); } + bool Deserialize(const json& j, bool skipRoot = false); + private: void EntityWalker(Entity entity); }; diff --git a/Nuake/src/Scene/Components/PrefabComponent.h b/Nuake/src/Scene/Components/PrefabComponent.h index 5bc62f6f..78a5d85f 100644 --- a/Nuake/src/Scene/Components/PrefabComponent.h +++ b/Nuake/src/Scene/Components/PrefabComponent.h @@ -13,4 +13,10 @@ namespace Nuake { PrefabInstance = prefab; } }; + + class PrefabMember + { + public: + Entity owner; + }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 9a568fef..09cc2154 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -296,6 +296,67 @@ namespace Nuake builder.BuildQuakeMap(entity, map.HasCollisions); } } + + std::map> prefabToReimport; + const auto& prefabView = m_Registry.view(); + for (const auto& e : prefabView) + { + auto& prefabComponent = prefabView.get(e); + + const std::string& filePath = prefabComponent.PrefabInstance->Path; + if (!FileSystem::FileExists(filePath)) + { + continue; + } + + Ref file = FileSystem::GetFile(filePath); + if (file->GetHasBeenModified()) + { + prefabToReimport[filePath] = file; + } + } + + if (prefabToReimport.size() > 0) + { + for (const auto& e : prefabView) + { + auto& prefabComponent = prefabView.get(e); + auto& prefabInstance = prefabComponent.PrefabInstance; + + if (prefabInstance == nullptr) + { + continue; + } + + // We don't need to reimport that one + if (!prefabToReimport.contains(prefabInstance->Path)) + { + continue; + } + + + for (auto& ent : prefabInstance->Entities) + { + // Destroy all children, not the root! + if (ent.IsValid() && ent != prefabInstance->Root) + { + this->DestroyEntity(ent); + } + } + + std::remove_if(prefabInstance->Entities.begin(), prefabInstance->Entities.end(), [](const Entity& entity) + { + return !entity.IsValid(); + }); + + prefabInstance->ReInstance(); + } + + for (auto& [path, prefabFile] : prefabToReimport) + { + prefabFile->SetHasBeenModified(false); + } + } } for (auto& system : m_Systems)