diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua index 35ea2c10..395c3a48 100644 --- a/SHADE_Application/premake5.lua +++ b/SHADE_Application/premake5.lua @@ -37,7 +37,8 @@ project "SHADE_Application" "%{IncludeDir.VULKAN}/include", "%{IncludeDir.spdlog}/include", "%{IncludeDir.tinyddsloader}", - "%{IncludeDir.reactphysics3d}\\include" + "%{IncludeDir.reactphysics3d}\\include", + "%{IncludeDir.yamlcpp}" } externalwarnings "Off" @@ -51,6 +52,7 @@ project "SHADE_Application" { "SHADE_Engine", "SHADE_Managed", + "yaml-cpp", "SDL2.lib", "SDL2main.lib" } diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index d7a090a4..fea59353 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -115,34 +115,22 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Script Serialisation Functions */ /*---------------------------------------------------------------------------------*/ - std::string SHScriptEngine::SerialiseScripts(EntityID entity) const + bool SHScriptEngine::SerialiseScripts(EntityID entity, YAML::Node& scriptsNode) const { - // Create buffer needed to store serialised script data - constexpr int BUFFER_SIZE = 10240; - std::unique_ptr buffer { new char[BUFFER_SIZE] }; - std::memset(buffer.get(), 0, BUFFER_SIZE); - // Attempt to serialise the script - std::string result; - if (csScriptsSerialise(entity, buffer.get(), BUFFER_SIZE)) - { - result = std::string(buffer.get()); - } - else - { - SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!"); - } + if (csScriptsSerialiseYaml(entity, &scriptsNode)) + return true; - // Return an empty string since we failed to serialise - return result; + SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts for entity #{}.", entity); + return false; } /*-----------------------------------------------------------------------------------*/ /* Script Serialisation Functions */ /*-----------------------------------------------------------------------------------*/ - void SHScriptEngine::DeserialiseScript(EntityID entity, const std::string& yaml) const + bool SHScriptEngine::DeserialiseScripts(EntityID entity, const YAML::Node& scriptsNode) const { - csScriptDeserialise(entity, yaml.c_str()); + return csScriptsDeserialiseYaml(entity, &scriptsNode); } /*-----------------------------------------------------------------------------------*/ @@ -380,30 +368,18 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "RemoveAllScriptsImmediately" ); - /*csScriptsSerialise = dotNet.GetFunctionPtr + csScriptsSerialiseYaml = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "SerialiseScripts" ); - csScriptsSerialiseYaml = dotNet.GetFunctionPtr + csScriptsDeserialiseYaml = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "SerialiseScriptsYaml" + "DeserialiseScripts" ); - csScriptDeserialise = dotNet.GetFunctionPtr - ( - DEFAULT_CSHARP_LIB_NAME, - DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "DeserialiseScript" - ); - csScriptDeserialiseYaml = dotNet.GetFunctionPtr - ( - DEFAULT_CSHARP_LIB_NAME, - DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", - "SerialiseScriptsYaml" - );*/ csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 60723425..137d978f 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -13,7 +13,8 @@ of DigiPen Institute of Technology is prohibited. // STL Includes #include - +// External Dependencies +#include // Project Headers #include "SH_API.h" #include "SHDotNetRuntime.h" @@ -141,23 +142,26 @@ namespace SHADE /* Script Serialisation Functions */ /*-----------------------------------------------------------------------------*/ /// - /// Generates a JSON string that represents the set of Scripts attached to the - /// specified Entity. + /// Performs serialization of all scripts for the specified entity into the + /// YAML::Node specified. This node will contain all serialised scripts after + /// calling this function. /// - /// The Entity to Serialise. - /// - /// String that represents the set of scripts attached to the specified Entity. - /// - std::string SerialiseScripts(EntityID entity) const; + /// The Entity to Serialise. + /// + /// YAML Node that will store the serialised scripts. + /// + /// True if successfully serialised. + bool SerialiseScripts(EntityID entity, YAML::Node& scriptsNode) const; /// - /// Loads the specified JSON string and creates a Script for the specified Entity - /// based on the specified JSON string. + /// Creates scripts and sets fields for the specified Entity based on the specified + /// YAML node. /// /// The Entity to deserialise a Script on to. - /// - /// The YAML string that represents the Script to load into the Entity. + /// + /// YAML Node that contains the serialised script data. /// - void DeserialiseScript(EntityID entity, const std::string& yaml) const; + /// True if successfully deserialised. + bool DeserialiseScripts(EntityID entity, const YAML::Node& scriptsNode) const; /*-----------------------------------------------------------------------------*/ /* Script Editor Functions */ @@ -207,14 +211,13 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ - using CsFuncPtr = void(*)(void); - using CsScriptManipFuncPtr = bool(*)(EntityID, const char*); - using CsScriptBasicFuncPtr = void(*)(EntityID); - using CsScriptOptionalFuncPtr = void(*)(EntityID, bool); - using CsScriptSerialiseFuncPtr = bool(*)(EntityID, char*, int); - using CsScriptDeserialiseFuncPtr = bool(*)(EntityID, const char*); - using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); - using CsScriptEditorFuncPtr = void(*)(EntityID); + using CsFuncPtr = void(*)(void); + using CsScriptManipFuncPtr = bool(*)(EntityID, const char*); + using CsScriptBasicFuncPtr = void(*)(EntityID); + using CsScriptOptionalFuncPtr = void(*)(EntityID, bool); + using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*); + using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*); + using CsScriptEditorFuncPtr = void(*)(EntityID); /*-----------------------------------------------------------------------------*/ /* Constants */ @@ -228,31 +231,29 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ - SHDotNetRuntime dotNet { false }; + SHDotNetRuntime dotNet { false }; // Function Pointers to CLR Code // - Engine Lifecycle - CsFuncPtr csEngineInit = nullptr; - CsFuncPtr csEngineLoadScripts = nullptr; - CsFuncPtr csEngineUnloadScripts = nullptr; - CsFuncPtr csEngineReloadScripts = nullptr; - CsFuncPtr csEngineExit = nullptr; + CsFuncPtr csEngineInit = nullptr; + CsFuncPtr csEngineLoadScripts = nullptr; + CsFuncPtr csEngineUnloadScripts = nullptr; + CsFuncPtr csEngineReloadScripts = nullptr; + CsFuncPtr csEngineExit = nullptr; // - Scripts Store - CsFuncPtr csScriptsFrameSetUp = nullptr; - CsFuncPtr csScriptsExecuteFixedUpdate = nullptr; - CsFuncPtr csScriptsExecuteUpdate = nullptr; - CsFuncPtr csScriptsExecuteLateUpdate = nullptr; - CsFuncPtr csScriptsFrameCleanUp = nullptr; - CsScriptManipFuncPtr csScriptsAdd = nullptr; - CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr; - CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; - CsScriptSerialiseFuncPtr csScriptsSerialise = nullptr; - CsScriptDeserialiseFuncPtr csScriptDeserialise = nullptr; - CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; - CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml = nullptr; + CsFuncPtr csScriptsFrameSetUp = nullptr; + CsFuncPtr csScriptsExecuteFixedUpdate = nullptr; + CsFuncPtr csScriptsExecuteUpdate = nullptr; + CsFuncPtr csScriptsExecuteLateUpdate = nullptr; + CsFuncPtr csScriptsFrameCleanUp = nullptr; + CsScriptManipFuncPtr csScriptsAdd = nullptr; + CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr; + CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; + CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; + CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr; // - Editor - CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; - CsFuncPtr csEditorUndo = nullptr; - CsFuncPtr csEditorRedo = nullptr; + CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; + CsFuncPtr csEditorUndo = nullptr; + CsFuncPtr csEditorRedo = nullptr; /*-----------------------------------------------------------------------------*/ /* Event Handler Functions */ diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index e259fbbc..63583cf2 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -13,6 +13,8 @@ #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 { @@ -77,6 +79,10 @@ namespace SHADE } } } + + // Deserialise scripts + if (node[ScriptsNode]) + SHSystemManager::GetSystem()->DeserialiseScripts(eid, node[ScriptsNode]); } void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) @@ -157,7 +163,7 @@ namespace SHADE node = YAML::Null; return node; } - node.SetStyle(YAML::EmitterStyle::Block); + node.SetStyle(YAML::EmitterStyle::Block); node[EIDNode] = eid; node[EntityNameNode] = entity->name; node[IsActiveNode] = sceneNode->IsActive(); @@ -179,6 +185,11 @@ namespace SHADE components[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody); } node[ComponentsNode] = components; + + YAML::Node scripts; + SHSystemManager::GetSystem()->SerialiseScripts(eid, scripts); + node[ScriptsNode] = scripts; + return node; } diff --git a/SHADE_Engine/src/Serialization/SHSerialization.h b/SHADE_Engine/src/Serialization/SHSerialization.h index d247de7a..e02db819 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.h +++ b/SHADE_Engine/src/Serialization/SHSerialization.h @@ -21,6 +21,7 @@ namespace SHADE constexpr const char* EIDNode = "EID"; constexpr const char* IsActiveNode = "IsActive"; constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; + constexpr const char* ScriptsNode = "Scripts"; struct SH_API SHSerialization { diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index 252ab071..b6bc1815 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -26,6 +26,7 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Convert.hxx" #include "Script.hxx" #include "Engine/Entity.hxx" +#include "Serialisation/ReflectionUtilities.hxx" namespace SHADE { @@ -470,72 +471,90 @@ namespace SHADE } SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") } - bool ScriptStore::SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize) + + bool ScriptStore::SerialiseScripts(Entity entity, System::IntPtr yamlNodePtr) { SAFE_NATIVE_CALL_BEGIN - // Create a buffer that we can work with temporarily - System::Text::StringBuilder^ jsonString = gcnew System::Text::StringBuilder(); + // Convert to pointer + YAML::Node* yamlNode = reinterpret_cast(yamlNodePtr.ToPointer()); + // Check if yamlNode is valid + if (yamlNode == nullptr) + { + Debug::LogWarning("[ScriptStore] Attempted to serialise scripts with an invalid YAML Node! Skipping."); + return false; + } + // Check if entity exists, otherwise nothing if (!EntityUtils::IsValid(entity)) - return true; - + { + Debug::LogWarning("[ScriptStore] Attempted to serialise scripts for an invalid Entity! Skipping."); + return false; + } + // Check if entity exists in the script storage - if (!scripts.ContainsKey(entity)) + if (!scripts.ContainsKey(entity)) return true; // Serialise each script + yamlNode->SetStyle(YAML::EmitterStyle::Block); System::Collections::Generic::List^ scriptList = scripts[entity]; - for (int i = 0; i < scriptList->Count; ++i) + for each (Script^ script in scriptList) { - throw gcnew System::NotImplementedException; - //jsonString->Append(ReflectionUtilities::Serialise(scriptList[i])); - - // Only add separator if is not last script - if (i != scriptList->Count - 1) - { - jsonString->Append(",\r\n"); - } + ReflectionUtilities::Serialise(script, *yamlNode); } - // Check if the size is too big - if (jsonString->Length > bufferSize) - return false; - - // Otherwise we copy it over - buffer->Clear(); - buffer->Append(jsonString->ToString()); return true; SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") return false; } - bool ScriptStore::DeserialiseScript(Entity entity, System::String^ yaml) + bool ScriptStore::DeserialiseScripts(Entity entity, System::IntPtr yamlNodePtr) { SAFE_NATIVE_CALL_BEGIN + // Convert to pointer + YAML::Node* yamlNode = reinterpret_cast(yamlNodePtr.ToPointer()); + + // Check if yamlNode is valid + if (yamlNode == nullptr) + { + Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts with an invalid YAML Node! Skipping."); + return false; + } + // Check if entity exists, otherwise nothing if (!EntityUtils::IsValid(entity)) - return false; - - // Get the name of the script - const int FIRST_QUOTE = yaml->IndexOf('\"'); - const int FIRST_COLON = yaml->IndexOf(':'); - if (FIRST_QUOTE < 0 || FIRST_COLON < 0) // No script name, it's invalid - return false; - const int SCRIPT_NAME_START = FIRST_QUOTE + 1; - const int SCRIPT_NAME_END = FIRST_COLON - 1; - System::String^ typeName = yaml->Substring(SCRIPT_NAME_START, SCRIPT_NAME_END - SCRIPT_NAME_START); - - // Create the script - Script^ script; - if (AddScriptViaNameWithRef(entity, typeName, script)) { - // Copy the data in - throw gcnew System::NotImplementedException; - //ReflectionUtilities::Deserialise(json, script); - return true; + Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts for an invalid Entity! Skipping."); + return false; } + // Go through all elements in the node + for (YAML::Node& node : *yamlNode) + { + // Get the name of the script + if (!node["Type"]) + { + Debug::LogWarning("[ScriptStore] Script with no type detected, skipping."); + continue; + } + + System::String^ typeName = Convert::ToCLI(node["Type"].as()); + + // Create + Script^ script; + if (AddScriptViaNameWithRef(entity, typeName, script)) + { + // Copy the data in + ReflectionUtilities::Deserialise(script, node); + } + else + { + Debug::LogWarning("[ScriptStore] Script with unloaded type detected, skipping."); + } + } + return true; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") return false; } diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx index cc0c1db5..4a9be721 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.hxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited. // Project Includes #include "Engine/Entity.hxx" #include "Script.hxx" +#include "Serialization/SHSerialization.h" namespace SHADE { @@ -237,27 +238,23 @@ namespace SHADE /* Serialisation Functions */ /*-----------------------------------------------------------------------------*/ /// - /// Generates a JSON string that represents the set of Scripts attached - /// to the specified Entity. + /// Populates a YAML node with the scripts for a specified Entity. ///

/// This function should only be called from native unmanaged code. ///
/// The Entity to Serialise. - /// - /// StringBuilder handle that maps to a native char array that will contain the - /// serialised string. - /// - /// - /// The size of the char array. + /// + /// Pointer to a YAML::Node that will be populated with all of the serialised + /// scripts and their associated fields. /// /// /// True if serialisation is successful. False if the buffer is too small for /// the serialised output. /// - static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize); + static bool SerialiseScripts(Entity entity, System::IntPtr yamlNode); /// - /// Processes a JSON string that represents a single Script and attaches - /// it onto the specified Entity. + /// Processes a YAML node that contains a list of multiple scripts to be loaded + /// into the specified Entity. ///

/// This function should only be called from native unmanaged code. ///
@@ -265,10 +262,10 @@ namespace SHADE /// The Entity to attach the deserialised Scripts to. /// /// - /// JSON string that describes the Script to serialise. + /// Pointer to the YAML::Node that contains serialized script data. /// /// - static bool DeserialiseScript(Entity entity, System::String^ yaml); + static bool DeserialiseScripts(Entity entity, System::IntPtr yamlNode); private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx index 2a9cc57c..3e963818 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.cxx @@ -38,6 +38,11 @@ if (iter != jsonValue.MemberEnd()) \ vec.MEMBER = iter->value.GetDouble(); \ } \ +/*-------------------------------------------------------------------------------------*/ +/* File-Level Constants */ +/*-------------------------------------------------------------------------------------*/ +static const std::string_view SCRIPT_TYPE_YAMLTAG = "Type"; + /*-------------------------------------------------------------------------------------*/ /* Function Definitions */ /*-------------------------------------------------------------------------------------*/ @@ -61,13 +66,14 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Serialisation Functions */ /*---------------------------------------------------------------------------------*/ - void ReflectionUtilities::Serialise(System::Object^ object, YAML::Emitter& yaml) + void ReflectionUtilities::Serialise(System::Object^ object, YAML::Node& scriptListNode) { using namespace System::Reflection; // Create YAML object - yaml << YAML::Key << Convert::ToNative(object->GetType()->FullName); - yaml << YAML::BeginMap; + YAML::Node scriptNode; + scriptNode.SetStyle(YAML::EmitterStyle::Block); + scriptNode[SCRIPT_TYPE_YAMLTAG.data()] = Convert::ToNative(object->GetType()->FullName); // Get all fields System::Collections::Generic::IEnumerable^ fields = GetInstanceFields(object); @@ -78,12 +84,12 @@ namespace SHADE continue; // Serialise - writeFieldIntoYaml(field, object, yaml); + writeFieldIntoYaml(field, object, scriptNode); } - yaml << YAML::EndMap; + scriptListNode.push_back(scriptNode); } - void ReflectionUtilities::Deserialise(YAML::Node& yamlNode, Object^ object) + void ReflectionUtilities::Deserialise(Object^ object, YAML::Node& yamlNode) { using namespace System::Reflection; @@ -117,53 +123,63 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Serialization Helper Functions */ /*---------------------------------------------------------------------------------*/ - void ReflectionUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Emitter& yaml) + void ReflectionUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode) { - // Field Name - yaml << YAML::Key << Convert::ToNative(fieldInfo->Name); - - // Field Value - yaml << YAML::Value; - if (fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml(fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml) || - fieldInsertYaml (fieldInfo, object, yaml)) + // Field YAML Node + YAML::Node fieldNode; + + // Retrieve string for the YAML + const bool PRIMITIVE_SERIALIZED = fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode) || + fieldInsertYaml(fieldInfo, object, fieldNode); + + // Serialization of more complex types + if (!PRIMITIVE_SERIALIZED) { - return; - } - else if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid)) - { - yaml << safe_cast(fieldInfo->GetValue(object)); - } - else if (fieldInfo->FieldType == System::String::typeid) - { - System::String^ str = safe_cast(fieldInfo->GetValue(object)); - yaml << Convert::ToNative(str); - } - else if (fieldInfo->FieldType == Vector2::typeid) - { - Vector2 vec = safe_cast(fieldInfo->GetValue(object)); - yaml << YAML::BeginSeq << YAML::Flow << vec.x << vec.y << YAML::EndSeq; - } - else if (fieldInfo->FieldType == Vector3::typeid) - { - Vector3 vec = safe_cast(fieldInfo->GetValue(object)); - yaml << YAML::BeginSeq << YAML::Flow << vec.x << vec.y << vec.z << YAML::EndSeq; - } - else // Not any of the supported types - { - Debug::LogWarning(Convert::ToNative(System::String::Format - ( - "[ReflectionUtilities] Failed to parse \"{0}\" of \"{1}\" type for serialization.", - fieldInfo->Name, fieldInfo->FieldType) - )); + if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid)) + { + fieldNode = std::to_string(safe_cast(fieldInfo->GetValue(object))); + } + else if (fieldInfo->FieldType == System::String::typeid) + { + System::String^ str = safe_cast(fieldInfo->GetValue(object)); + fieldNode = Convert::ToNative(str); + } + else if (fieldInfo->FieldType == Vector2::typeid) + { + Vector2 vec = safe_cast(fieldInfo->GetValue(object)); + fieldNode.SetStyle(YAML::EmitterStyle::Flow); + fieldNode.push_back(vec.x); + fieldNode.push_back(vec.y); + } + else if (fieldInfo->FieldType == Vector3::typeid) + { + Vector3 vec = safe_cast(fieldInfo->GetValue(object)); + fieldNode.SetStyle(YAML::EmitterStyle::Flow); + fieldNode.push_back(vec.x); + fieldNode.push_back(vec.y); + fieldNode.push_back(vec.z); + } + else // Not any of the supported types + { + Debug::LogWarning(Convert::ToNative(System::String::Format + ( + "[ReflectionUtilities] Failed to parse \"{0}\" of \"{1}\" type for serialization.", + fieldInfo->Name, fieldInfo->FieldType) + )); + return; + } } + + // Store the field into YAML + yamlNode[Convert::ToNative(fieldInfo->Name)] = fieldNode; } void ReflectionUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ index 88469b34..7c39232a 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.h++ @@ -23,11 +23,12 @@ namespace SHADE /* Serialization Helper Functions */ /*---------------------------------------------------------------------------------*/ template - bool ReflectionUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Emitter& emitter) + bool ReflectionUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode) { if (fieldInfo->FieldType == FieldType::typeid) { - emitter << safe_cast(fieldInfo->GetValue(object)); + const FieldType VALUE = safe_cast(fieldInfo->GetValue(object)); + fieldNode = static_cast(VALUE); return true; } @@ -37,7 +38,7 @@ namespace SHADE template bool ReflectionUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) { - return fieldAssignYaml(fieldInfo, object, node); + return fieldAssignYaml>(fieldInfo, object, node); } template diff --git a/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx b/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx index 53f8fa1d..403c913c 100644 --- a/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx +++ b/SHADE_Managed/src/Serialisation/ReflectionUtilities.hxx @@ -52,24 +52,24 @@ namespace SHADE /// attribute will be serialised. /// /// The object to serialise. - static void Serialise(System::Object^ object, YAML::Emitter& yaml); + static void Serialise(System::Object^ object, YAML::Node& yamlNode); /// /// Deserialises a YAML node that contains a map of Scripts and copies the /// deserialised data into the specified object if there are matching fields. /// /// - /// The JSON string that contains the data to copy into this PlushieScript - /// object. + /// The JSON string that contains the data to copy into this Script object. /// /// The object to copy deserialised data into. - static void Deserialise(YAML::Node& yamlNode, Object^ object); + static void Deserialise(System::Object^ object, YAML::Node& yamlNode); + private: /*-----------------------------------------------------------------------------*/ /* Serialization Helper Functions */ /*-----------------------------------------------------------------------------*/ - static void writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Emitter& yaml); + static void writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode); template - static bool fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Emitter& emitter); + static bool fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode); static void writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); template static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index b41ffef4..f04cbf4b 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -91,4 +91,68 @@ namespace SHADE /// Managed copy of a native std::string. static System::String^ ToCLI(const std::string& str); }; + + /// + /// Type Transformer for managed types to native types. + /// + /// + /// Managed type to get the native type for. + /// + template + struct ToNativeType + { + public: + using Value = void; + }; + template<> struct ToNativeType { using Value = int16_t; }; + template<> struct ToNativeType { using Value = int32_t; }; + template<> struct ToNativeType { using Value = int64_t; }; + template<> struct ToNativeType { using Value = uint16_t; }; + template<> struct ToNativeType { using Value = uint32_t; }; + template<> struct ToNativeType { using Value = uint64_t; }; + template<> struct ToNativeType { using Value = int8_t; }; + template<> struct ToNativeType { using Value = bool; }; + template<> struct ToNativeType { using Value = double; }; + template<> struct ToNativeType { using Value = float; }; + + /// + /// Alias for ToNativeType::Value + /// + /// + /// Managed type to get the native type for. + /// + template + using ToNativeType_T = typename ToNativeType::Value; + + /// + /// Type Transformer for native types to managed types. + /// + /// + /// Managed type to get the native type for. + /// + template + struct ToManagedType + { + public: + using Value = void; + }; + template<> struct ToManagedType { using Value = System::Byte; }; + template<> struct ToManagedType { using Value = System::Int16; }; + template<> struct ToManagedType { using Value = System::Int32; }; + template<> struct ToManagedType { using Value = System::Int64; }; + template<> struct ToManagedType { using Value = System::UInt16; }; + template<> struct ToManagedType { using Value = System::UInt32; }; + template<> struct ToManagedType { using Value = System::UInt64; }; + template<> struct ToManagedType { using Value = bool; }; + template<> struct ToManagedType { using Value = double; }; + template<> struct ToManagedType { using Value = float; }; + + /// + /// Alias for ToManagedType::Value + /// + /// + /// Managed type to get the native type for. + /// + template + using ToManagedType_T = typename ToManagedType::Value; }