Serialize/Deserialize [WIP]

This commit is contained in:
Sri Sham Haran 2022-10-01 23:43:00 +08:00
parent 6fd1cadf01
commit 01f648ceb6
3 changed files with 185 additions and 54 deletions

View File

@ -7,21 +7,31 @@
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Tools/SHException.h" #include "Tools/SHException.h"
#include "Assets/SHAssetManager.h"
#include <fstream>
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
namespace SHADE namespace SHADE
{ {
void SHSerialization::SerializeSceneToFile(std::filesystem::path const& path) 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() std::string SHSerialization::SerializeSceneToString()
{ {
YAML::Emitter out; YAML::Emitter out;
SerializeSceneToEmitter(out); SerializeSceneToEmitter(out);
return std::string(out.c_str()); return std::basic_string<char>(out.c_str());
} }
void SHSerialization::SerializeSceneToEmitter(YAML::Emitter& out) void SHSerialization::SerializeSceneToEmitter(YAML::Emitter& out)
@ -32,53 +42,80 @@ namespace SHADE
SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node.");
auto const& children = root->GetChildren(); auto const& children = root->GetChildren();
out << YAML::BeginDoc; out << YAML::BeginSeq;
auto pred = [&out](SHSceneNode* node){out << SerializeEntityToNode(node);}; auto pred = [&out](SHSceneNode* node) {out << SerializeEntityToNode(node); };
sceneGraph.Traverse(pred); sceneGraph.Traverse(pred);
//out << SerializeEntityToNode(child); //out << SerializeEntityToNode(child);
out << YAML::EndDoc; out << YAML::EndSeq;
} }
static void DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID) static void DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID)
{ {
if(!node[EIDNode]) if (!node[EIDNode])
return; return;
EntityID eid = node[EIDNode].as<EntityID>(); EntityID eid = node[EIDNode].as<EntityID>();
std::string name = "Default"; std::string name = "Default";
if(node[EntityNameNode]) if (node[EntityNameNode])
name = node[EntityNameNode].as<std::string>(); name = node[EntityNameNode].as<std::string>();
//Compile component IDs //Compile component IDs
const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]); const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]);
eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID); eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID);
createdEntities.push_back(eid); createdEntities.push_back(eid);
if(node[NumberOfChildrenNode]) if (node[NumberOfChildrenNode])
{ int numOfChildren = node[NumberOfChildrenNode].as<int>();
for(int i = 0; i < numOfChildren; ++i)
{ {
DeserializeEntity(it, *it, createdEntities, eid); if(const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
{
++it;
for (int i = 0; i < numOfChildren; ++i)
{
DeserializeEntity(it, (*it), createdEntities, eid);
if((i + 1) < numOfChildren)
++it; ++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<EntityID> createdEntities{}; std::vector<EntityID> createdEntities{};
//Create Entities //Create Entities
for(auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
DeserializeEntity(it, (*it), createdEntities); DeserializeEntity(it, (*it), createdEntities);
} }
//Initialize Entity //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 InitializeEntity(*it, *entityVecIt++);
//Recurse through properties
} }
} }
@ -103,7 +140,7 @@ namespace SHADE
node = YAML::Null; node = YAML::Null;
return node; return node;
} }
node.SetStyle(YAML::EmitterStyle::Block);
node[EIDNode] = eid; node[EIDNode] = eid;
node[EntityNameNode] = entity->name; node[EntityNameNode] = entity->name;
node[IsActiveNode] = sceneNode->IsActive(); node[IsActiveNode] = sceneNode->IsActive();
@ -121,10 +158,10 @@ namespace SHADE
} }
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
std::optional<ComponentTypeID> GetComponentID(YAML::Node const & componentNode) std::optional<ComponentTypeID> GetComponentID(YAML::Node const& componentNode)
{ {
if(componentNode[rttr::type::get<ComponentType>().get_name().data()]) if (componentNode[rttr::type::get<ComponentType>().get_name().data()])
return {SHFamilyID<SHComponent>::GetID<ComponentType>()}; return { SHFamilyID<SHComponent>::GetID<ComponentType>() };
else else
return std::nullopt; return std::nullopt;
} }
@ -134,9 +171,20 @@ namespace SHADE
std::vector<ComponentTypeID> componentIDList; std::vector<ComponentTypeID> componentIDList;
auto id = GetComponentID<SHTransformComponent>(componentsNode); auto id = GetComponentID<SHTransformComponent>(componentsNode);
if(id.has_value()) if (id.has_value())
componentIDList.push_back(id.value());
id = GetComponentID<SHRenderable>(componentsNode);
if (id.has_value())
componentIDList.push_back(id.value()); componentIDList.push_back(id.value());
return componentIDList; return componentIDList;
} }
void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid)
{
auto componentsNode = entityNode[ComponentsNode];
if(!componentsNode)
return;
SHSerializationHelper::InitializeComponentFromNode<SHTransformComponent>(componentsNode, eid);
}
} }

View File

@ -28,7 +28,7 @@ namespace SHADE
static void SerializeSceneToFile(std::filesystem::path const& path); static void SerializeSceneToFile(std::filesystem::path const& path);
static std::string SerializeSceneToString(); static std::string SerializeSceneToString();
static void SerializeSceneToEmitter(YAML::Emitter& out); 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(); static std::string SerializeEntityToString();
@ -37,5 +37,6 @@ namespace SHADE
static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode); static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode);
private: private:
static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid);
}; };
} }

View File

@ -5,6 +5,7 @@
#include <rttr/registration> #include <rttr/registration>
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
@ -28,7 +29,7 @@ namespace SHADE
{ {
YAML::Node node; YAML::Node node;
auto varType = var.get_type(); auto varType = var.get_type();
if(varType == rttr::type::get<SHVec4>()) if (varType == rttr::type::get<SHVec4>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node.SetStyle(YAML::EmitterStyle::Flow);
node["X"] = var.convert<SHVec4>().x; node["X"] = var.convert<SHVec4>().x;
@ -36,20 +37,20 @@ namespace SHADE
node["Z"] = var.convert<SHVec4>().z; node["Z"] = var.convert<SHVec4>().z;
node["W"] = var.convert<SHVec4>().w; node["W"] = var.convert<SHVec4>().w;
} }
else if(varType == rttr::type::get<SHVec3>()) else if (varType == rttr::type::get<SHVec3>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node.SetStyle(YAML::EmitterStyle::Flow);
node["X"] = var.convert<SHVec3>().x; node["X"] = var.convert<SHVec3>().x;
node["Y"] = var.convert<SHVec3>().y; node["Y"] = var.convert<SHVec3>().y;
node["Z"] = var.convert<SHVec3>().z; node["Z"] = var.convert<SHVec3>().z;
} }
else if(varType == rttr::type::get<SHVec2>()) else if (varType == rttr::type::get<SHVec2>())
{ {
node.SetStyle(YAML::EmitterStyle::Flow); node.SetStyle(YAML::EmitterStyle::Flow);
node["X"] = var.convert<SHVec3>().x; node["X"] = var.convert<SHVec3>().x;
node["Y"] = var.convert<SHVec3>().y; node["Y"] = var.convert<SHVec3>().y;
} }
else if(varType.is_arithmetic()) else if (varType.is_arithmetic())
{ {
bool ok = false; bool ok = false;
if (varType == rttr::type::get<bool>()) if (varType == rttr::type::get<bool>())
@ -98,7 +99,7 @@ namespace SHADE
else else
{ {
auto properties = var.get_type().get_properties(); 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)); node[property.get_name().data()] = RTTRToNode(property.get_value(var));
} }
@ -110,7 +111,7 @@ namespace SHADE
static YAML::Node SerializeComponentToNode(ComponentType* component) static YAML::Node SerializeComponentToNode(ComponentType* component)
{ {
YAML::Node node{}; YAML::Node node{};
if(!component) if (!component)
return node; return node;
auto componentType = rttr::type::get<ComponentType>(); auto componentType = rttr::type::get<ComponentType>();
@ -118,5 +119,86 @@ namespace SHADE
return node; return node;
} }
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, 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>())
{
SHVec4 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>(), propertyNode["Z"].as<float>(), propertyNode["W"].as<float>() };
prop.set_value(component, vec);
}
else if (propType == rttr::type::get<SHVec3>())
{
SHVec3 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>(), propertyNode["Z"].as<float>() };
prop.set_value(component, vec);
}
else if (propType == rttr::type::get<SHVec2>())
{
SHVec2 vec{ propertyNode["X"].as<float>(), propertyNode["Y"].as<float>() };
prop.set_value(component, vec);
}
else if (propType.is_arithmetic())
{
bool ok = false;
if (propType == rttr::type::get<bool>())
prop.set_value(component, propertyNode.as<bool>());
else if (propType == rttr::type::get<int8_t>())
prop.set_value(component, propertyNode.as<int8_t>());
else if (propType == rttr::type::get<int16_t>())
prop.set_value(component, propertyNode.as<int16_t>());
else if (propType == rttr::type::get<int32_t>())
prop.set_value(component, propertyNode.as<int32_t>());
else if (propType == rttr::type::get<int64_t>())
prop.set_value(component, propertyNode.as<int64_t>());
else if (propType == rttr::type::get<uint8_t>())
prop.set_value(component, propertyNode.as<uint8_t>());
else if (propType == rttr::type::get<uint16_t>())
prop.set_value(component, propertyNode.as<uint16_t>());
else if (propType == rttr::type::get<uint32_t>())
prop.set_value(component, propertyNode.as<uint32_t>());
else if (propType == rttr::type::get<uint64_t>())
prop.set_value(component, propertyNode.as<uint64_t>());
else if (propType == rttr::type::get<float>())
prop.set_value(component, propertyNode.as<float>());
else if (propType == rttr::type::get<double>())
prop.set_value(component, propertyNode.as<double>());
}
else if (propType.is_enumeration())
{
auto enumAlign = prop.get_enumeration();
prop.set_value(component, enumAlign.name_to_value(propertyNode.as<std::string>()));
}
else
{
auto properties = propType.get_properties();
for (auto property : properties)
{
InitializeProperty(component, property, propertyNode[property.get_name().data()]);
}
}
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid)
{
auto component = SHComponentManager::GetComponent_s<ComponentType>(eid);
if (componentsNode.IsNull() && !component)
return;
auto rttrType = rttr::type::get<ComponentType>();
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<ComponentType>(component, prop, componentNode[prop.get_name().data()]);
}
}
}
}; };
} }