#pragma once #include "ECS_Base/Components/SHComponent.h" #include #include #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec4.h" #include "Physics/Components/SHColliderComponent.h" namespace YAML { using namespace SHADE; template<> struct convert { static constexpr const char* x = "x"; static constexpr const char* y = "y"; static constexpr const char* z = "z"; static constexpr const char* w = "w"; static Node encode(SHVec4 const& rhs) { Node node; node.SetStyle(EmitterStyle::Flow); node[x] = rhs.x; node[y] = rhs.y; node[z] = rhs.z; node[w] = rhs.w; return node; } static bool decode(Node const& node, SHVec4& rhs) { if (node[x]) rhs.x = node[x].as(); if (node[y]) rhs.y = node[y].as(); if (node[z]) rhs.z = node[z].as(); if (node[w]) rhs.w = node[w].as(); return true; } }; template<> struct convert { static constexpr const char* x = "x"; static constexpr const char* y = "y"; static constexpr const char* z = "z"; static Node encode(SHVec3 const& rhs) { Node node; node.SetStyle(EmitterStyle::Flow); node[x] = rhs.x; node[y] = rhs.y; node[z] = rhs.z; return node; } static bool decode(Node const& node, SHVec3& rhs) { if (node[x]) rhs.x = node[x].as(); if (node[y]) rhs.y = node[y].as(); if (node[z]) rhs.z = node[z].as(); return true; } }; template<> struct convert { static constexpr const char* x = "x"; static constexpr const char* y = "y"; static Node encode(SHVec2 const& rhs) { Node node; node.SetStyle(EmitterStyle::Flow); node[x] = rhs.x; node[y] = rhs.y; return node; } static bool decode(Node const& node, SHVec2& rhs) { if (node[x]) rhs.x = node[x].as(); if (node[y]) rhs.y = node[y].as(); return true; } }; template<> struct convert { static constexpr const char* IsTrigger = "Is Trigger"; static constexpr const char* Type = "Type"; static constexpr const char* HalfExtents = "Half Extents"; static constexpr const char* Radius = "Radius"; static constexpr const char* Friction = "Friction"; static constexpr const char* Bounciness = "Bounciness"; static constexpr const char* Density = "Density"; static constexpr const char* PositionOffset = "Position Offset"; static Node encode(SHCollider& rhs) { Node node; node[IsTrigger] = rhs.IsTrigger(); rttr::type const shapeRttrType = rttr::type::get(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); SHCollider::Type colliderType = rhs.GetType(); node[Type] = enumAlign.value_to_name(colliderType).data(); switch (colliderType) { case SHCollider::Type::BOX: { auto const bb = reinterpret_cast(rhs.GetShape()); node[HalfExtents] = bb->GetHalfExtents(); } break; case SHCollider::Type::SPHERE: { auto const bs = reinterpret_cast(rhs.GetShape()); node[Radius] = bs->GetRadius(); } break; case SHCollider::Type::CAPSULE: break; default:; } node[Friction] = rhs.GetFriction(); node[Bounciness] = rhs.GetBounciness(); node[Density] = rhs.GetDensity(); node[PositionOffset] = rhs.GetPositionOffset(); return node; } static bool decode(Node const& node, SHCollider& rhs) { if (node[IsTrigger]) rhs.SetIsTrigger(node[IsTrigger].as()); if (!node[Type]) return false; rttr::type const shapeRttrType = rttr::type::get(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); bool ok; const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as()).convert(&ok); if (!ok) return false; switch (colliderType) { case SHCollider::Type::BOX: { if(auto const bb = dynamic_cast(rhs.GetShape()); bb) { if (node[HalfExtents]) { bb->SetHalfExtents(node[HalfExtents].as()); } } } break; case SHCollider::Type::SPHERE: { if(auto const bs = dynamic_cast(rhs.GetShape()); bs) { if (node[Radius]) { bs->SetRadius(node[Radius].as()); } } } break; case SHCollider::Type::CAPSULE: break; default:; } if (node[Friction]) rhs.SetFriction(node[Friction].as()); if (node[Bounciness]) rhs.SetBounciness(rhs.GetBounciness()); if (node[Density]) rhs.SetDensity(node[Density].as()); if (node[PositionOffset]) rhs.SetPositionOffset(node[PositionOffset].as()); return true; } }; template<> struct convert { static constexpr const char* Colliders = "Colliders"; static Node encode(SHColliderComponent& rhs) { Node node, collidersNode; auto const& colliders = rhs.GetColliders(); int const numColliders = static_cast(colliders.size()); for (int i = 0; i < numColliders; ++i) { auto& collider = rhs.GetCollider(i); Node colliderNode = convert::encode(collider); if (colliderNode.IsDefined()) collidersNode[i] = colliderNode; } node[Colliders] = collidersNode; return node; } static bool decode(Node const& node, SHColliderComponent& rhs) { if(node.IsNull()) return false; if (node[Colliders]) { int numColliders{}; for (auto const& colliderNode : node[Colliders]) { rttr::type const shapeRttrType = rttr::type::get(); rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); bool ok; const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert::Type].as()).convert(&ok); if (!ok) return false; switch (colliderType) { case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; case SHCollider::Type::CAPSULE: break; default:; } rhs.GetCollider(numColliders++) = colliderNode.as(); } } } }; } namespace SHADE { struct SHSerializationHelper { static YAML::Node RTTRToNode(const rttr::variant& var) { YAML::Node node; auto varType = var.get_type(); if (varType.is_sequential_container()) { for (auto const& elem : var.create_sequential_view()) { node.push_back(RTTRToNode(elem)); } } if (varType == rttr::type::get()) { node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { node = YAML::convert::encode(var.convert()); } else if (varType == rttr::type::get()) { node = YAML::convert::encode(var.convert()); } else if (varType.is_arithmetic()) { bool ok = false; if (varType == rttr::type::get()) node = var.to_bool(); else if (varType == rttr::type::get()) node = var.to_int8(&ok); else if (varType == rttr::type::get()) node = var.to_int16(&ok); else if (varType == rttr::type::get()) node = var.to_int32(&ok); else if (varType == rttr::type::get()) node = var.to_int64(&ok); else if (varType == rttr::type::get()) node = var.to_uint8(&ok); else if (varType == rttr::type::get()) node = var.to_uint16(&ok); else if (varType == rttr::type::get()) node = var.to_uint32(&ok); else if (varType == rttr::type::get()) node = var.to_uint64(&ok); else if (varType == rttr::type::get()) node = var.to_float(&ok); else if (varType == rttr::type::get()) node = var.to_double(&ok); //else if (varType == rttr::type::get()) //same as uint8_t // node = var.to_uint8(); } else if (varType.is_enumeration()) { bool ok = false; auto result = var.to_string(&ok); if (ok) { node = var.to_string(); } else { 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 const& property : properties) { node[property.get_name().data()] = RTTRToNode(property.get_value(var)); } } return node; } template , bool> = true> static std::string SerializeComponentToString(ComponentType* component) { return std::string(); } template , bool> = true> static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) { } template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { YAML::Node 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.as(); prop.set_value(component, vec); } else if (propType == rttr::type::get()) { SHVec3 vec = propertyNode.as(); prop.set_value(component, vec); } else if (propType == rttr::type::get()) { SHVec2 vec = propertyNode.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 const& property : properties) { InitializeProperty(component, property, propertyNode[property.get_name().data()]); } } } template , bool> = true> static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) { ComponentType* 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()].IsDefined()) { InitializeProperty(component, prop, componentNode[prop.get_name().data()]); } } } template , bool> = true> static void InitializeComponentFromNodeData(YAML::Node const& componentsNode, EntityID const& eid) { ComponentType* 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; YAML::convert::decode(componentNode, *component); } }; }