#pragma once #include "src/Scene/Entities/Entity.h" #include "src/Scene/Components/ParentComponent.h" #include "src/Resource/Serializable.h" #include "Engine.h" #include #include #include namespace Nuake { class Prefab : ISerializable { public: std::string DisplayName; std::string Description; std::string Path; std::vector Entities; Entity Root; static Ref CreatePrefabFromEntity(Entity entity); static Ref New(const std::string& path); Prefab() { Path = ""; Entities = std::vector(); } void AddEntity(Entity& entity) { Entities.push_back(entity); } void SaveAs(const std::string& path) { Path = path; FileSystem::BeginWriteFile(path, true); FileSystem::WriteLine(Serialize().dump(4)); FileSystem::EndWriteFile(); } json Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(Path); SERIALIZE_VAL(DisplayName); SERIALIZE_VAL(Description); auto entities = std::vector(); for (Entity e : Entities) { entities.push_back(e.Serialize()); } j["Root"] = Root.GetComponent().ID; SERIALIZE_VAL_LBL("Entities", entities); // Manual correction to remove parent if we are prefabing a child. // We want to get rid of parent link in the prefab itself. for (auto& e : j["Entities"]) { if (e["NameComponent"]["ID"] == Root.GetComponent().ID) e["ParentComponent"]["HasParent"] = false; } END_SERIALIZE(); } 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")) { const 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 = scene->GetUniqueEntityName(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); } } return true; } private: void EntityWalker(Entity entity); }; }