#include "SHpch.h" #include #include "SHSerialization.h" #include "SHSerializationHelper.hpp" #include "ECS_Base/Managers/SHEntityManager.h" #include "Scene/SHSceneManager.h" #include "Tools/SHException.h" #include "Assets/SHAssetManager.h" #include #include "Assets/Asset Types/SHSceneAsset.h" #include "Camera/SHCameraComponent.h" #include "Camera/SHCameraArmComponent.h" #include "Math/Transform/SHTransformComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Physics/Interface/SHRigidBodyComponent.h" #include "UI/SHCanvasComponent.h" #include "UI/SHButtonComponent.h" #include "UI/SHToggleButtonComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" #include "Tools/FileIO/SHFileIO.h" namespace SHADE { bool SHSerialization::SerializeSceneToFile(AssetID const& sceneAssetID) { auto assetData = SHAssetManager::GetData(sceneAssetID); if(!assetData) { SHLOG_ERROR("Asset does not exist: {}", sceneAssetID); return false; } YAML::Emitter out; SerializeSceneToEmitter(out); assetData->data = out.c_str(); return SHAssetManager::SaveAsset(sceneAssetID); } std::string SHSerialization::SerializeSceneToString() { YAML::Emitter out; SerializeSceneToEmitter(out); return std::basic_string(out.c_str()); } void SHSerialization::SerializeSceneToEmitter(YAML::Emitter& out) { auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto root = sceneGraph.GetRoot(); SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); auto const& children = root->GetChildren(); out << YAML::BeginSeq; auto pred = [&out](SHSceneNode* node) {out << SerializeEntityToNode(node); }; sceneGraph.Traverse(pred); //out << SerializeEntityToNode(child); out << YAML::EndSeq; } static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, SHSerialization::CreatedEntitiesList& createdEntities, EntityID parentEID = MAX_EID) { EntityID eid{MAX_EID}, oldEID{MAX_EID}; if (!node) return eid; if (node[EIDNode]) oldEID = eid = node[EIDNode].as(); std::string name = "UnnamedEntitiy"; if (node[EntityNameNode]) name = node[EntityNameNode].as(); //Compile component IDs const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]); eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID); createdEntities[oldEID] = eid; //createdEntities.push_back(eid); if (node[NumberOfChildrenNode]) { if (const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) { ++it; for (int i = 0; i < numOfChildren; ++i) { DeserializeEntity(it, (*it), createdEntities, eid); if ((i + 1) < numOfChildren) ++it; } } } // Deserialise scripts if (node[ScriptsNode]) SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); return eid; } std::string SHSerialization::DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept { auto assetData = SHAssetManager::GetData(sceneAssetID); if(!assetData) { SHLOG_ERROR("Attempted to load scene that doesn't exist {}", sceneAssetID) SHSceneManager::SetCurrentSceneAssetID(0); return NewSceneName.data(); } YAML::Node entities = YAML::Load(assetData->data); CreatedEntitiesList createdEntities{}; //Create Entities for (auto it = entities.begin(); it != entities.end(); ++it) { DeserializeEntity(it, (*it), createdEntities); } if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") return NewSceneName.data(); } auto entityVecIt = createdEntities.begin(); AssetQueue assetQueue; for (auto it = entities.begin(); it != entities.end(); ++it) { SHSerializationHelper::FetchAssetsFromComponent((*it)[ComponentsNode], createdEntities[(*it)[EIDNode].as()], assetQueue); } LoadAssetsFromAssetQueue(assetQueue); //Initialize Entity entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, createdEntities[(*it)[EIDNode].as()]); } return assetData->name; } void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out) { out << SerializeEntityToNode(entityNode); auto const& children = entityNode->GetChildren(); for (auto const& child : children) { EmitEntity(child, out); } } std::string SHSerialization::SerializeEntitiesToString(std::vector const& entities) noexcept { YAML::Emitter out; YAML::Node node; auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); out << YAML::BeginSeq; for (auto const& eid : entities) { auto entityNode = sceneGraph.GetNode(eid); EmitEntity(entityNode, out); } out << YAML::EndSeq; return std::string(out.c_str()); } //void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) //{ //} template, bool> = true> static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) { YAML::Node node{}; if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) { node = SHSerializationHelper::SerializeComponentToNode(component); componentsNode[rttr::type::get().get_name().data()] = node; } } YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) { YAML::Node node; auto eid = sceneNode->GetEntityID(); auto entity = SHEntityManager::GetEntityByID(eid); if (!sceneNode && !entity) { node = YAML::Null; return node; } node.SetStyle(YAML::EmitterStyle::Block); node[EIDNode] = eid; node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); auto const& children = sceneNode->GetChildren(); node[NumberOfChildrenNode] = children.size(); YAML::Node components; AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); node[ComponentsNode] = components; YAML::Node scripts; SHSystemManager::GetSystem()->SerialiseScripts(eid, scripts); node[ScriptsNode] = scripts; return node; } SHSerialization::CreatedEntitiesList SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept { if (data.empty()) return {}; YAML::Node entities = YAML::Load(data.c_str()); EntityID eid{ MAX_EID }; CreatedEntitiesList createdEntities{}; for (auto it = entities.begin(); it != entities.end(); ++it) { eid = DeserializeEntity(it, *it, createdEntities, parentEID); } if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") return createdEntities; } //auto entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, createdEntities[(*it)[EIDNode].as()]); } return createdEntities; } template, bool> = true> static void AddComponentID(std::vector& idList, YAML::Node const& componentNode) { if (componentNode[rttr::type::get().get_name().data()]) idList.push_back(SHFamilyID::GetID()); } std::vector SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) { std::vector componentIDList; AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); return componentIDList; } void SHSerialization::LoadAssetsFromAssetQueue(AssetQueue& assetQueue) { for (auto& [assetId, assetType] : assetQueue) { switch(assetType) { case AssetType::INVALID: break; case AssetType::SHADER: break; case AssetType::SHADER_BUILT_IN: break; case AssetType::TEXTURE: SHResourceManager::LoadOrGet(assetId); break; case AssetType::MESH: SHResourceManager::LoadOrGet(assetId); break; case AssetType::SCENE: break; case AssetType::PREFAB: break; case AssetType::MATERIAL: SHResourceManager::LoadOrGet(assetId); break; case AssetType::MAX_COUNT: break; default: ; } } SHResourceManager::FinaliseChanges(); } void ResolveSerializedEntityID(YAML::Emitter& out, YAML::iterator& it, YAML::Node const& entityNode, SHSerialization::CreatedEntitiesList const& createdEntities) { EntityID eid = entityNode[EIDNode].as(); YAML::Node resolvedNode = entityNode; resolvedNode[EIDNode] = createdEntities.at(eid); out << resolvedNode; if (entityNode[NumberOfChildrenNode]) { if (const int numOfChildren = entityNode[NumberOfChildrenNode].as(); numOfChildren > 0) { ++it; for (int i = 0; i < numOfChildren; ++i) { ResolveSerializedEntityID(out, it, (*it), createdEntities); //DeserializeEntity(it, (*it), createdEntities, eid); if ((i + 1) < numOfChildren) ++it; } } } } std::string SHSerialization::ResolveSerializedEntityIndices(std::string serializedEntityData, CreatedEntitiesList const& createdEntities) noexcept { YAML::Node entities = YAML::Load(serializedEntityData); YAML::Emitter out; out << YAML::BeginSeq; for (auto it = entities.begin(); it != entities.end(); ++it) { ResolveSerializedEntityID(out, it, (*it), createdEntities); } out << YAML::EndSeq; return out.c_str(); } void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid) { auto const componentsNode = entityNode[ComponentsNode]; if (!componentsNode) return; SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } }