diff --git a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp index 8ab098b8..048298ed 100644 --- a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp +++ b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.cpp @@ -1,5 +1,9 @@ #include "SHpch.h" #include "SHPrefabManager.h" +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Assets/SHAssetManager.h" +#include "Assets/Asset Types/SHPrefabAsset.h" +#include "Serialization/SHSerialization.h" namespace SHADE { @@ -32,7 +36,7 @@ namespace SHADE { if (prefabMap.contains(prefabAssetID)) { - prefabMap[prefabAssetID].insert(eid); + prefabMap[prefabAssetID].push_back(eid); } } @@ -40,10 +44,21 @@ namespace SHADE { if (prefabMap.contains(prefabAssetID)) { - prefabMap[prefabAssetID].erase(eid); + std::ranges::remove(prefabMap[prefabAssetID], eid); } } + void SHPrefabManager::SaveEntityAsPrefab(EntityID const& eid) noexcept + { + SHEntity* const entity = SHEntityManager::GetEntityByID(eid); + AssetID const assetID = SHAssetManager::CreateNewAsset(AssetType::PREFAB, entity->name); + + auto assetData = SHAssetManager::GetData(assetID); + assetData->data = SHSerialization::SerializeEntitiesToString({eid}); + + SHAssetManager::SaveAsset(assetID); + } + void SHPrefabManager::Clear() noexcept { prefabMap.clear(); diff --git a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h index 37c317ed..29d47c5c 100644 --- a/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h +++ b/SHADE_Engine/src/Serialization/Prefab/SHPrefabManager.h @@ -2,7 +2,8 @@ #include "Assets/SHAssetMacros.h" #include "ECS_Base/SHECSMacros.h" -#include +#include "ECS_Base/General/SHFamily.h" +#include "ECS_Base/Components/SHComponent.h" #include @@ -11,7 +12,17 @@ namespace SHADE class SHPrefabManager { public: - using PrefabMap = std::unordered_map>; + + enum class PrefabEntityComponentStatus : uint8_t + { + PES_UNCHANGED = 0, + PES_MODIFIED, + PES_ADDED, + PES_REMOVED + }; + + using PrefabMap = std::unordered_map>; + using PrefabEntitiesComponentStatusData = std::unordered_map,PrefabEntityComponentStatus>>; static void AddPrefab(AssetID const& prefabAssetID) noexcept; static void RemovePrefab(AssetID const& prefabAssetID) noexcept; @@ -19,10 +30,15 @@ namespace SHADE static void UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept; static void AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; static void RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; + static void SaveEntityAsPrefab(EntityID const& eid) noexcept; static void Clear() noexcept; static bool Empty() noexcept; private: static PrefabMap prefabMap; + static PrefabEntitiesComponentStatusData prefabEntitiesComponentStatusData; + + friend class SHSerialization; + friend class SHSerializationHelper; }; } diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index febca024..c291e4ea 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -23,7 +23,7 @@ namespace SHADE auto assetData = SHAssetManager::GetData(sceneAssetID); if(!assetData) { - SHLOG_ERROR("Asset does not exist: {}", sceneAssetID); + SHLOG_ERROR("Serialization: Asset does not exist: {}", sceneAssetID); return false; } YAML::Emitter out; @@ -45,7 +45,7 @@ namespace SHADE auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto root = sceneGraph.GetRoot(); - SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); + SHASSERT(root != nullptr, "Serialization: Root is null. Failed to serialize scene to node."); auto const& children = root->GetChildren(); out << YAML::BeginSeq; @@ -105,7 +105,7 @@ namespace SHADE auto assetData = SHAssetManager::GetData(sceneAssetID); if(!assetData) { - SHLOG_ERROR("Attempted to load scene that doesn't exist {}", sceneAssetID) + SHLOG_ERROR("Serialization: Attempted to load scene that doesn't exist {}", sceneAssetID) SHSceneManager::SetCurrentSceneAssetID(0); return NewSceneName.data(); } @@ -119,7 +119,7 @@ namespace SHADE } if (createdEntities.empty()) { - SHLOG_ERROR("Failed to create entities from deserializaiton") + SHLOG_ERROR("Serialization: Failed to create entities from deserialization") return NewSceneName.data(); } auto entityVecIt = createdEntities.begin(); @@ -139,26 +139,33 @@ namespace SHADE return assetData->name; } - void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out) + void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out, bool isPrefab /*= false*/, EntityID* entityIndex /*= nullptr*/) { out << SerializeEntityToNode(entityNode); + if(isPrefab) + ++(*entityIndex); + auto const& children = entityNode->GetChildren(); for (auto const& child : children) { - EmitEntity(child, out); + EmitEntity(child, out, isPrefab); } } - std::string SHSerialization::SerializeEntitiesToString(std::vector const& entities) noexcept + std::string SHSerialization::SerializeEntitiesToString(std::vector const& entities, bool isPrefab) noexcept { YAML::Emitter out; YAML::Node node; auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); out << YAML::BeginSeq; + EntityID entityIndex = 0; for (auto const& eid : entities) { auto entityNode = sceneGraph.GetNode(eid); - EmitEntity(entityNode, out); + if(isPrefab) + EmitEntity(entityNode, out, isPrefab); + else + EmitEntity(entityNode, out); } out << YAML::EndSeq; return std::string(out.c_str()); @@ -179,8 +186,11 @@ namespace SHADE } } - YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) + YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode, bool isPrefab /*= false*/, EntityID* entityIndex /*= nullptr*/) { + if(!sceneNode) + return YAML::Node(); + YAML::Node node; auto eid = sceneNode->GetEntityID(); auto entity = SHEntityManager::GetEntityByID(eid); @@ -190,7 +200,14 @@ namespace SHADE return node; } node.SetStyle(YAML::EmitterStyle::Block); + node[EIDNode] = eid; + + if(isPrefab) //TODO: Set asset id for top level prefab entity only + { + node[PrefabID] = 0; + } + node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); auto const& children = sceneNode->GetChildren(); @@ -236,7 +253,7 @@ namespace SHADE } if (createdEntities.empty()) { - SHLOG_ERROR("Failed to create entities from deserializaiton") + SHLOG_ERROR("Failed to create entities from deserialization") return createdEntities; } //auto entityVecIt = createdEntities.begin(); diff --git a/SHADE_Engine/src/Serialization/SHSerialization.h b/SHADE_Engine/src/Serialization/SHSerialization.h index dd487662..9d8362ed 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.h +++ b/SHADE_Engine/src/Serialization/SHSerialization.h @@ -24,6 +24,7 @@ namespace SHADE constexpr const char* IsActiveNode = "IsActive"; constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; constexpr const char* ScriptsNode = "Scripts"; + constexpr const char* PrefabID = "PrefabID"; class SH_API SHSerialization { @@ -38,11 +39,11 @@ namespace SHADE static std::string DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept; - static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); + static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out, bool isPrefab = false, EntityID* entityIndex = nullptr); - static std::string SerializeEntitiesToString(std::vector const& entities) noexcept; + static std::string SerializeEntitiesToString(std::vector const& entities, bool isPrefab = false) noexcept; //static void SerializeEntityToFile(std::filesystem::path const& path); - static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); + static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode, bool isPrefab = false, EntityID* entityIndex = nullptr); static CreatedEntitiesList DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;