#include "SHpch.h" #include "SHSerializationHelper.hpp" #include "SHSerialization.h" #include #include "ECS_Base/Managers/SHEntityManager.h" #include "Scene/SHSceneManager.h" #include "Tools/SHException.h" #include "Assets/SHAssetManager.h" #include #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" #include "Physics/Components/SHRigidBodyComponent.h" #include "ECS_Base/Managers/SHSystemManager.h" #include "Scripting/SHScriptEngine.h" namespace SHADE { void SHSerialization::SerializeSceneToFile(std::filesystem::path const& path) { YAML::Emitter out; SerializeSceneToEmitter(out); std::ofstream file(path.c_str()); if (file.good()) { file << out.c_str(); file.close(); } } 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; } void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) { //TODO:Shift to using XQ's FileIO std::ifstream iFile; iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); std::string fileContent = ""; try { // Open file // Read file's buffer contents into streams iFile.open(path); std::stringstream fileStream; fileStream << iFile.rdbuf(); fileContent = fileStream.str(); // Close file handler iFile.close(); } catch (std::ifstream::failure e) { SHLOG_ERROR("Could not read file"); } YAML::Node entities = YAML::Load(fileContent); 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; } //Initialize Entity auto entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } } 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) { } 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; if (const auto transform = SHComponentManager::GetComponent_s(eid)) { components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(transform); } if (const auto renderable = SHComponentManager::GetComponent_s(eid)) { components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(renderable); } if (const auto rigidbody = SHComponentManager::GetComponent_s(eid)) { components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody); } if (auto collisionComp = SHComponentManager::GetComponent_s(eid)) { components[rttr::type::get().get_name().data()] = YAML::convert::encode(*collisionComp); } 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> std::optional GetComponentID(YAML::Node const& componentNode) { if (componentNode[rttr::type::get().get_name().data()]) return { SHFamilyID::GetID() }; else return std::nullopt; } std::vector SHSerialization::GetComponentIDList(YAML::Node const& componentsNode) { std::vector componentIDList; auto id = GetComponentID(componentsNode); if (id.has_value()) componentIDList.push_back(id.value()); id = GetComponentID(componentsNode); if (id.has_value()) componentIDList.push_back(id.value()); id = GetComponentID(componentsNode); if (id.has_value()) componentIDList.push_back(id.value()); id = GetComponentID(componentsNode); if(id.has_value()) componentIDList.push_back(id.value()); return componentIDList; } 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::InitializeComponentFromNodeData(componentsNode, eid); } }