From 01f648ceb626ba8b6bec50c87198e380ac277b24 Mon Sep 17 00:00:00 2001 From: Sri Sham Haran Date: Sat, 1 Oct 2022 23:43:00 +0800 Subject: [PATCH] Serialize/Deserialize [WIP] --- .../src/Serialization/SHSerialization.cpp | 100 +++++++++---- .../src/Serialization/SHSerialization.h | 3 +- .../Serialization/SHSerializationHelper.hpp | 136 ++++++++++++++---- 3 files changed, 185 insertions(+), 54 deletions(-) diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 926e4ff5..ee189f2c 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -7,21 +7,31 @@ #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" 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::string(out.c_str()); + return std::basic_string(out.c_str()); } void SHSerialization::SerializeSceneToEmitter(YAML::Emitter& out) @@ -30,55 +40,82 @@ namespace SHADE auto root = sceneGraph.GetRoot(); SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); - - auto const& children = root->GetChildren(); - out << YAML::BeginDoc; - auto pred = [&out](SHSceneNode* node){out << SerializeEntityToNode(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::EndDoc; + //out << SerializeEntityToNode(child); + + out << YAML::EndSeq; } static void DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector& createdEntities, EntityID parentEID = MAX_EID) { - if(!node[EIDNode]) + if (!node[EIDNode]) return; EntityID eid = node[EIDNode].as(); std::string name = "Default"; - if(node[EntityNameNode]) + 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]) - { int numOfChildren = node[NumberOfChildrenNode].as(); - for(int i = 0; i < numOfChildren; ++i) + if (node[NumberOfChildrenNode]) + { + if(const int numOfChildren = node[NumberOfChildrenNode].as(); numOfChildren > 0) { - DeserializeEntity(it, *it, createdEntities, eid); ++it; + for (int i = 0; i < numOfChildren; ++i) + { + DeserializeEntity(it, (*it), createdEntities, eid); + if((i + 1) < numOfChildren) + ++it; + } } } } - void SHSerialization::DeserializeSceneFromFile(std::string const& fileData) + void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) { - YAML::Node entities = YAML::Load(fileData.c_str()); + //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) + for (auto it = entities.begin(); it != entities.end(); ++it) { DeserializeEntity(it, (*it), createdEntities); } //Initialize Entity - for(auto it = entities.begin(); it != entities.end(); ++it) + auto entityVecIt = createdEntities.begin(); + for (auto it = entities.begin(); it != entities.end(); ++it) { - //For each node, Deserialize component - //Recurse through properties + InitializeEntity(*it, *entityVecIt++); } } @@ -103,7 +140,7 @@ namespace SHADE node = YAML::Null; return node; } - + node.SetStyle(YAML::EmitterStyle::Block); node[EIDNode] = eid; node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); @@ -121,10 +158,10 @@ namespace SHADE } template, bool> = true> - std::optional GetComponentID(YAML::Node const & componentNode) + std::optional GetComponentID(YAML::Node const& componentNode) { - if(componentNode[rttr::type::get().get_name().data()]) - return {SHFamilyID::GetID()}; + if (componentNode[rttr::type::get().get_name().data()]) + return { SHFamilyID::GetID() }; else return std::nullopt; } @@ -134,9 +171,20 @@ namespace SHADE std::vector componentIDList; auto id = GetComponentID(componentsNode); - if(id.has_value()) + 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 componentsNode = entityNode[ComponentsNode]; + if(!componentsNode) + return; + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + } } diff --git a/SHADE_Engine/src/Serialization/SHSerialization.h b/SHADE_Engine/src/Serialization/SHSerialization.h index 022a01c4..8a57f036 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.h +++ b/SHADE_Engine/src/Serialization/SHSerialization.h @@ -28,7 +28,7 @@ namespace SHADE static void SerializeSceneToFile(std::filesystem::path const& path); static std::string SerializeSceneToString(); static void SerializeSceneToEmitter(YAML::Emitter& out); - static void DeserializeSceneFromFile(std::string const& fileData); + static void DeserializeSceneFromFile(std::filesystem::path const& path); static std::string SerializeEntityToString(); @@ -37,5 +37,6 @@ namespace SHADE static std::vector GetComponentIDList(YAML::Node const& componentsNode); private: + static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index e702dd24..da98c885 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -5,6 +5,7 @@ #include +#include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" @@ -13,13 +14,13 @@ namespace SHADE { struct SHSerializationHelper { - template , bool> = true> + template , bool> = true> static std::string SerializeComponentToString(ComponentType* component) { return std::string(); } - template , bool> = true> + template , bool> = true> static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) { } @@ -28,7 +29,7 @@ namespace SHADE { YAML::Node node; auto varType = var.get_type(); - if(varType == rttr::type::get()) + if (varType == rttr::type::get()) { node.SetStyle(YAML::EmitterStyle::Flow); node["X"] = var.convert().x; @@ -36,44 +37,44 @@ namespace SHADE node["Z"] = var.convert().z; node["W"] = var.convert().w; } - else if(varType == rttr::type::get()) + else if (varType == rttr::type::get()) { node.SetStyle(YAML::EmitterStyle::Flow); node["X"] = var.convert().x; node["Y"] = var.convert().y; node["Z"] = var.convert().z; } - else if(varType == rttr::type::get()) + else if (varType == rttr::type::get()) { node.SetStyle(YAML::EmitterStyle::Flow); node["X"] = var.convert().x; node["Y"] = var.convert().y; } - else if(varType.is_arithmetic()) + else if (varType.is_arithmetic()) { bool ok = false; if (varType == rttr::type::get()) - node = var.to_bool(); + node = var.to_bool(); else if (varType == rttr::type::get()) - node = var.to_int8(&ok); + node = var.to_int8(&ok); else if (varType == rttr::type::get()) - node = var.to_int16(&ok); + node = var.to_int16(&ok); else if (varType == rttr::type::get()) - node = var.to_int32(&ok); + node = var.to_int32(&ok); else if (varType == rttr::type::get()) - node = var.to_int64(&ok); + node = var.to_int64(&ok); else if (varType == rttr::type::get()) - node = var.to_uint8(&ok); + node = var.to_uint8(&ok); else if (varType == rttr::type::get()) - node = var.to_uint16(&ok); + node = var.to_uint16(&ok); else if (varType == rttr::type::get()) - node = var.to_uint32(&ok); + node = var.to_uint32(&ok); else if (varType == rttr::type::get()) - node = var.to_uint64(&ok); + node = var.to_uint64(&ok); else if (varType == rttr::type::get()) - node = var.to_float(&ok); + node = var.to_float(&ok); else if (varType == rttr::type::get()) - node = var.to_double(&ok); + node = var.to_double(&ok); //else if (varType == rttr::type::get()) //same as uint8_t // node = var.to_uint8(); } @@ -87,18 +88,18 @@ namespace SHADE } else { - ok = false; - auto value = var.to_uint64(&ok); - if (ok) - node = value; - else - node = YAML::Null; + ok = false; + auto value = var.to_uint64(&ok); + if (ok) + node = value; + else + node = YAML::Null; } } else { auto properties = var.get_type().get_properties(); - for(auto property : properties) + for (auto property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } @@ -106,17 +107,98 @@ namespace SHADE return node; } - template , bool> = true> + template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { YAML::Node node{}; - if(!component) - return node; + if (!component) + return node; auto componentType = rttr::type::get(); node = RTTRToNode(*component); return node; } + + template , bool> = true> + static void InitializeProperty(ComponentType* component, rttr::property const& prop, YAML::Node const& propertyNode) + { + auto propType = prop.get_type(); + if (propType == rttr::type::get()) + { + SHVec4 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as(), propertyNode["W"].as() }; + prop.set_value(component, vec); + } + else if (propType == rttr::type::get()) + { + SHVec3 vec{ propertyNode["X"].as(), propertyNode["Y"].as(), propertyNode["Z"].as() }; + prop.set_value(component, vec); + } + else if (propType == rttr::type::get()) + { + SHVec2 vec{ propertyNode["X"].as(), propertyNode["Y"].as() }; + prop.set_value(component, vec); + } + else if (propType.is_arithmetic()) + { + bool ok = false; + if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + else if (propType == rttr::type::get()) + prop.set_value(component, propertyNode.as()); + } + else if (propType.is_enumeration()) + { + auto enumAlign = prop.get_enumeration(); + prop.set_value(component, enumAlign.name_to_value(propertyNode.as())); + } + else + { + auto properties = propType.get_properties(); + for (auto property : properties) + { + InitializeProperty(component, property, propertyNode[property.get_name().data()]); + } + } + } + + template , bool> = true> + static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) + { + auto component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() && !component) + return; + auto rttrType = rttr::type::get(); + auto componentNode = componentsNode[rttrType.get_name().data()]; + if (componentsNode.IsNull()) + return; + auto properties = rttrType.get_properties(); + for (auto const& prop : properties) + { + if (componentNode[prop.get_name().data()]) + { + InitializeProperty(component, prop, componentNode[prop.get_name().data()]); + } + } + } + }; }