diff --git a/Editor/src/Misc/ThumbnailManager.cpp b/Editor/src/Misc/ThumbnailManager.cpp index 8045545b..c40a259e 100644 --- a/Editor/src/Misc/ThumbnailManager.cpp +++ b/Editor/src/Misc/ThumbnailManager.cpp @@ -110,7 +110,7 @@ Ref ThumbnailManager::GenerateThumbnail(const std::string& path, camComponent.CameraInstance->AspectRatio = 1.0f; m_ShadedFramebuffer->SetTexture(texture); - Ref prefab = Prefab::InstanceInScene(path, scene); + Ref prefab = Prefab::InstanceInScene(path, scene.get()); scene->Update(0.01f); scene->Draw(*m_ShadedFramebuffer.get()); diff --git a/Nuake/src/Resource/Prefab.cpp b/Nuake/src/Resource/Prefab.cpp index bfd27891..b4a7c13e 100644 --- a/Nuake/src/Resource/Prefab.cpp +++ b/Nuake/src/Resource/Prefab.cpp @@ -35,7 +35,7 @@ namespace Nuake return newPrefab; } - Ref Prefab::InstanceInScene(const std::string& path, Ref scene) + Ref Prefab::InstanceInScene(const std::string& path, Scene* scene) { Ref newPrefab = CreateRef(); newPrefab->Path = path; @@ -53,6 +53,102 @@ namespace Nuake return newPrefab; } + Ref Prefab::InstanceOntoRoot(Entity entity, const std::string & path) + { + Ref newPrefab = CreateRef(); + newPrefab->Path = path; + + if (FileSystem::FileExists(path, false)) + { + std::string prefabTextContent = FileSystem::ReadFile(path); + + if (!prefabTextContent.empty()) + { + json j = json::parse(prefabTextContent); + + if (j == "") + return newPrefab; + + newPrefab->Root = entity; + if (j.contains("Entities")) + { + std::map newIdsLut; + newIdsLut[j["Root"]] = entity.GetID(); + + for (json e : j["Entities"]) + { + if (e["NameComponent"]["ID"] == j["Root"]) + { + continue; // skip root + } + + Entity newEntity = { entity.GetScene()->m_Registry.create(), entity.GetScene() }; + newEntity.Deserialize(e); // Id gets overriden by serialized id. + + auto& nameComponent = newEntity.GetComponent(); + + uint32_t oldId = nameComponent.ID; + uint32_t newId = OS::GetTime(); + nameComponent.Name = nameComponent.Name; + nameComponent.ID = newId; + + newIdsLut[oldId] = newId; + + newPrefab->AddEntity(newEntity); + } + + // Set reference to the parent entity to children + for (auto& e : newPrefab->Entities) + { + auto& parentC = e.GetComponent(); + auto parent = entity.GetScene()->GetEntityByID(newIdsLut[parentC.ParentID]); + + if (parentC.ParentID == j["Root"]) + { + entity.AddChild(e); + } + else + { + 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 : newPrefab->Entities) + { + if (!e.HasComponent()) + { + continue; + } + + auto& skinnedModelComponent = e.GetComponent(); + if (!skinnedModelComponent.ModelResource) + { + continue; + } + + SkeletonNode& currentBone = skinnedModelComponent.ModelResource->GetSkeletonRootNode(); + recursiveBoneRemapping(currentBone); + } + } + } + } + + return newPrefab; + } + void Prefab::ReInstance() { if (FileSystem::FileExists(Path, false)) @@ -159,7 +255,7 @@ namespace Nuake parent.AddChild(e); } - e.GetComponent().owner = Root; + e.GetComponent().owner = Root.GetID(); } // Since the bones point to an entity, and we are instancing a prefab, the new skeleton is gonna be pointing to the wrong diff --git a/Nuake/src/Resource/Prefab.h b/Nuake/src/Resource/Prefab.h index 6bc3d634..57f1065a 100644 --- a/Nuake/src/Resource/Prefab.h +++ b/Nuake/src/Resource/Prefab.h @@ -23,8 +23,8 @@ namespace Nuake { static Ref CreatePrefabFromEntity(Entity entity); static Ref New(const std::string& path); - static Ref InstanceInScene(const std::string& path, Ref targetScene); - + static Ref InstanceInScene(const std::string& path, Scene* targetScene); + static Ref InstanceOntoRoot(Entity entity, const std::string& path); Prefab() { Path = ""; @@ -74,7 +74,7 @@ namespace Nuake { END_SERIALIZE(); } - bool DeserializeIntoScene(const json& j, Ref scene) + bool DeserializeIntoScene(const json& j, Scene* scene) { if (j == "") return false; @@ -96,7 +96,7 @@ namespace Nuake { std::map newIdsLut; for (json e : j["Entities"]) { - Entity entity = { scene->m_Registry.create(), scene.get() }; + Entity entity = { scene->m_Registry.create(), scene }; entity.Deserialize(e); // Id gets overriden by serialized id. auto& nameComponent = entity.GetComponent(); diff --git a/Nuake/src/Scene/Components/PrefabComponent.h b/Nuake/src/Scene/Components/PrefabComponent.h index 78a5d85f..f29ce47a 100644 --- a/Nuake/src/Scene/Components/PrefabComponent.h +++ b/Nuake/src/Scene/Components/PrefabComponent.h @@ -7,16 +7,52 @@ namespace Nuake { { public: Ref PrefabInstance; + std::string Path; void SetPrefab(Ref prefab) { PrefabInstance = prefab; + Path = prefab->Path; } + + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(Path); + END_SERIALIZE(); + } + + bool Deserialize(const json& j) + { + DESERIALIZE_VAL(Path); + return true; + } + + void PostDeserialize(Scene& scene) + { + //PrefabInstance->ReInstance(); + //SetPrefab(Prefab::InstanceInScene(Path, &scene)); + //PrefabInstance->Root.GetComponent().IsPrefab = true; + //PrefabInstance->Root.AddComponent(); + } }; class PrefabMember { public: - Entity owner; + uint32_t owner = 0; + + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(owner); + END_SERIALIZE(); + } + + bool Deserialize(const json& j) + { + owner = j["owner"]; + return true; + } }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Entities/Entity.cpp b/Nuake/src/Scene/Entities/Entity.cpp index ce865fc6..425ba3c1 100644 --- a/Nuake/src/Scene/Entities/Entity.cpp +++ b/Nuake/src/Scene/Entities/Entity.cpp @@ -85,7 +85,10 @@ namespace Nuake SERIALIZE_OBJECT_REF_LBL("NavMeshVolumeComponent", GetComponent()) if (HasComponent()) SERIALIZE_OBJECT_REF_LBL("UIComponent", GetComponent()) - + if(HasComponent()) + SERIALIZE_OBJECT_REF_LBL("PrefabComponent", GetComponent()) + if (HasComponent()) + SERIALIZE_OBJECT_REF_LBL("PrefabMember", GetComponent()) END_SERIALIZE(); } @@ -99,6 +102,54 @@ namespace Nuake } DESERIALIZE_COMPONENT(NameComponent); DESERIALIZE_COMPONENT(ParentComponent); + + if (j.contains("PrefabComponent")) + { + GetComponent().IsPrefab = true; + auto& prefabComp = AddComponent(); + const auto& prefabPath = j["PrefabComponent"]["Path"]; + + if (prefabPath.empty()) + { + return true; + } + + if (!FileSystem::FileExists(prefabPath, false)) + { + return true; + } + + // This will map serialized ID to new generated ones while + // keeping the parent/child relationship in the prefab file. + std::string prefabTextContent = FileSystem::ReadFile(prefabPath); + auto prefabJson = json::parse(prefabTextContent); + auto& rootId = prefabJson["Root"]; + json rootJson = ""; + for (const auto& entJson : prefabJson["Entities"]) + { + bool isRoot = false; + if (entJson["NameComponent"]["ID"] == rootId) + { + rootJson = entJson; + isRoot = true; + continue; + } + } + + Prefab::InstanceOntoRoot(Entity{(entt::entity)GetHandle(), m_Scene}, prefabPath); + + DeserializeComponents(rootJson); + } + else + { + DeserializeComponents(j); + } + + return true; + } + + bool Entity::DeserializeComponents(const json& j) + { DESERIALIZE_COMPONENT(ParticleEmitterComponent); DESERIALIZE_COMPONENT(SpriteComponent); DESERIALIZE_COMPONENT(CameraComponent); @@ -119,12 +170,20 @@ namespace Nuake DESERIALIZE_COMPONENT(NetScriptComponent); DESERIALIZE_COMPONENT(NavMeshVolumeComponent); DESERIALIZE_COMPONENT(UIComponent); - return true; + return false; } void Entity::PostDeserialize() { POSTDESERIALIZE_COMPONENT(QuakeMapComponent); + + if (HasComponent()) + { + auto& prefabComp = GetComponent(); + const std::string& path = prefabComp.Path; + } + + POSTDESERIALIZE_COMPONENT(PrefabComponent); } Entity::Entity(entt::entity handle, Scene* scene) diff --git a/Nuake/src/Scene/Entities/Entity.h b/Nuake/src/Scene/Entities/Entity.h index e4d37400..f0fb2227 100644 --- a/Nuake/src/Scene/Entities/Entity.h +++ b/Nuake/src/Scene/Entities/Entity.h @@ -130,6 +130,8 @@ namespace Nuake json Serialize() override; bool Deserialize(const json& str); + bool DeserializeComponents(const json& str); + void PostDeserialize(); Scene* GetScene() const diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 4cdb06da..f1e15dc1 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -306,7 +306,11 @@ namespace Nuake for (const auto& e : prefabView) { auto& prefabComponent = prefabView.get(e); - + if (prefabComponent.PrefabInstance == nullptr) + { + continue; + } + const std::string& filePath = prefabComponent.PrefabInstance->Path; if (!FileSystem::FileExists(filePath)) { @@ -646,6 +650,11 @@ namespace Nuake std::vector entities = std::vector(); for (Entity e : GetAllEntities()) { + if (e.HasComponent()) + { + continue; + } + auto returnValue = std::async(std::launch::async, [&]() { entities.push_back(e.Serialize()); }); diff --git a/Nuake/src/Scene/Systems/System.h b/Nuake/src/Scene/Systems/System.h index fa954e7a..a1426e4f 100644 --- a/Nuake/src/Scene/Systems/System.h +++ b/Nuake/src/Scene/Systems/System.h @@ -11,6 +11,7 @@ namespace Nuake public: Scene* m_Scene; + virtual bool Init() = 0; virtual void Draw() = 0; diff --git a/Nuake/src/Scene/Systems/TransformSystem.cpp b/Nuake/src/Scene/Systems/TransformSystem.cpp index 61c84c91..30ec2283 100644 --- a/Nuake/src/Scene/Systems/TransformSystem.cpp +++ b/Nuake/src/Scene/Systems/TransformSystem.cpp @@ -147,7 +147,6 @@ namespace Nuake for (auto& c : parentComponent.Children) { - auto& childParentComponent = c.GetComponent(); childParentComponent.GlobalDirty = true; diff --git a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp index ab3f0c6f..2142ea6d 100644 --- a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp +++ b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp @@ -443,7 +443,6 @@ namespace Nuake { bool IsOnGround(int entityId) { Entity entity = Entity((entt::entity)(entityId), Engine::GetCurrentScene().get()); - if (entity.IsValid() && entity.HasComponent()) { auto& characterController = entity.GetComponent(); @@ -500,7 +499,7 @@ namespace Nuake { } void Play(int entityId, Coral::String animation) - { + { Entity entity = Entity((entt::entity)(entityId), Engine::GetCurrentScene().get()); if (entity.IsValid() && entity.HasComponent())