#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 "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Components/SHRigidBodyComponent.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, std::vector& createdEntities, EntityID parentEID = MAX_EID) { EntityID eid = MAX_EID; if (!node) return eid; if (node[EIDNode]) eid = node[EIDNode].as(); std::string name = "Default"; 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.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); std::vector 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], *entityVecIt, assetQueue); } LoadAssetsFromAssetQueue(assetQueue); //Initialize Entity entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } 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) { if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) { componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); } } template, bool> = true> static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) { if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) { componentsNode[rttr::type::get().get_name().data()] = YAML::convert::encode(*component); } } 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); AddConvComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddConvComponentToComponentNode(components, eid); node[ComponentsNode] = components; YAML::Node scripts; SHSystemManager::GetSystem()->SerialiseScripts(eid, scripts); node[ScriptsNode] = scripts; return node; } EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept { if (data.empty()) return MAX_EID; YAML::Node entities = YAML::Load(data.c_str()); EntityID eid{ MAX_EID }; std::vector 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 MAX_EID; } auto entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } return eid; } 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); 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 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::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } }