Merge pull request #102 from SHADE-DP/SP3-6-c-scripting
Added Script Serialization and Deserialization
This commit is contained in:
commit
f5060ba0b0
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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<char> 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<CsScriptSerialiseFuncPtr>
|
||||
csScriptsSerialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||
"SerialiseScripts"
|
||||
);
|
||||
csScriptsSerialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
|
||||
csScriptsDeserialiseYaml = dotNet.GetFunctionPtr<CsScriptDeserialiseYamlFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||
"SerialiseScriptsYaml"
|
||||
"DeserialiseScripts"
|
||||
);
|
||||
csScriptDeserialise = dotNet.GetFunctionPtr<CsScriptDeserialiseFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||
"DeserialiseScript"
|
||||
);
|
||||
csScriptDeserialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||
"SerialiseScriptsYaml"
|
||||
);*/
|
||||
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
|
|
|
@ -13,7 +13,8 @@ of DigiPen Institute of Technology is prohibited.
|
|||
|
||||
// STL Includes
|
||||
#include <filesystem>
|
||||
|
||||
// External Dependencies
|
||||
#include <yaml-cpp/yaml.h>
|
||||
// Project Headers
|
||||
#include "SH_API.h"
|
||||
#include "SHDotNetRuntime.h"
|
||||
|
@ -141,23 +142,26 @@ namespace SHADE
|
|||
/* Script Serialisation Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="entity"> The Entity to Serialise.</param>
|
||||
/// <returns>
|
||||
/// String that represents the set of scripts attached to the specified Entity.
|
||||
/// </returns>
|
||||
std::string SerialiseScripts(EntityID entity) const;
|
||||
/// <param name="entity">The Entity to Serialise.</param>
|
||||
/// <param name="scriptsNode">
|
||||
/// YAML Node that will store the serialised scripts.
|
||||
/// </param>
|
||||
/// <return>True if successfully serialised.</return>
|
||||
bool SerialiseScripts(EntityID entity, YAML::Node& scriptsNode) const;
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="entity">The Entity to deserialise a Script on to.</param>
|
||||
/// <param name="yaml">
|
||||
/// The YAML string that represents the Script to load into the Entity.
|
||||
/// <param name="scriptsNode">
|
||||
/// YAML Node that contains the serialised script data.
|
||||
/// </param>
|
||||
void DeserialiseScript(EntityID entity, const std::string& yaml) const;
|
||||
/// <return>True if successfully deserialised.</return>
|
||||
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 */
|
||||
|
|
|
@ -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<SHScriptEngine>()->DeserialiseScripts(eid, node[ScriptsNode]);
|
||||
}
|
||||
|
||||
void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path)
|
||||
|
@ -179,6 +185,11 @@ namespace SHADE
|
|||
components[rttr::type::get<SHRigidBodyComponent>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(rigidbody);
|
||||
}
|
||||
node[ComponentsNode] = components;
|
||||
|
||||
YAML::Node scripts;
|
||||
SHSystemManager::GetSystem<SHScriptEngine>()->SerialiseScripts(eid, scripts);
|
||||
node[ScriptsNode] = scripts;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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<YAML::Node*>(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))
|
||||
return true;
|
||||
|
||||
// Serialise each script
|
||||
yamlNode->SetStyle(YAML::EmitterStyle::Block);
|
||||
System::Collections::Generic::List<Script^>^ 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<YAML::Node*>(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<std::string>());
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// <br/> <br/>
|
||||
/// This function should only be called from native unmanaged code.
|
||||
/// </summary>
|
||||
/// <param name="entity">The Entity to Serialise.</param>
|
||||
/// <param name="buffer">
|
||||
/// StringBuilder handle that maps to a native char array that will contain the
|
||||
/// serialised string.
|
||||
/// </param>
|
||||
/// <param name="bufferSize">
|
||||
/// The size of the char array.
|
||||
/// <param name="yamlNode">
|
||||
/// Pointer to a YAML::Node that will be populated with all of the serialised
|
||||
/// scripts and their associated fields.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if serialisation is successful. False if the buffer is too small for
|
||||
/// the serialised output.
|
||||
/// </returns>
|
||||
static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize);
|
||||
static bool SerialiseScripts(Entity entity, System::IntPtr yamlNode);
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// <br/> <br/>
|
||||
/// This function should only be called from native unmanaged code.
|
||||
/// </summary>
|
||||
|
@ -265,10 +262,10 @@ namespace SHADE
|
|||
/// The Entity to attach the deserialised Scripts to.
|
||||
/// </param>
|
||||
/// <param name="yaml">
|
||||
/// JSON string that describes the Script to serialise.
|
||||
/// Pointer to the YAML::Node that contains serialized script data.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
static bool DeserialiseScript(Entity entity, System::String^ yaml);
|
||||
static bool DeserialiseScripts(Entity entity, System::IntPtr yamlNode);
|
||||
|
||||
private:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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<FieldInfo^>^ 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 YAML Node
|
||||
YAML::Node fieldNode;
|
||||
|
||||
// Field Value
|
||||
yaml << YAML::Value;
|
||||
if (fieldInsertYaml<System::Int16> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::Int32> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::Int64> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::UInt16>(fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::UInt32>(fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::UInt64>(fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<System::Byte> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<bool> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<float> (fieldInfo, object, yaml) ||
|
||||
fieldInsertYaml<double> (fieldInfo, object, yaml))
|
||||
// Retrieve string for the YAML
|
||||
const bool PRIMITIVE_SERIALIZED = fieldInsertYaml<System::Int16>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::Int32>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::Int64>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::UInt16>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::UInt32>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::UInt64>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::Byte>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<bool>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<float>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<double>(fieldInfo, object, fieldNode);
|
||||
|
||||
// Serialization of more complex types
|
||||
if (!PRIMITIVE_SERIALIZED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid))
|
||||
{
|
||||
yaml << safe_cast<int>(fieldInfo->GetValue(object));
|
||||
}
|
||||
else if (fieldInfo->FieldType == System::String::typeid)
|
||||
{
|
||||
System::String^ str = safe_cast<System::String^>(fieldInfo->GetValue(object));
|
||||
yaml << Convert::ToNative(str);
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector2::typeid)
|
||||
{
|
||||
Vector2 vec = safe_cast<Vector2>(fieldInfo->GetValue(object));
|
||||
yaml << YAML::BeginSeq << YAML::Flow << vec.x << vec.y << YAML::EndSeq;
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector3::typeid)
|
||||
{
|
||||
Vector3 vec = safe_cast<Vector3>(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<int>(fieldInfo->GetValue(object)));
|
||||
}
|
||||
else if (fieldInfo->FieldType == System::String::typeid)
|
||||
{
|
||||
System::String^ str = safe_cast<System::String^>(fieldInfo->GetValue(object));
|
||||
fieldNode = Convert::ToNative(str);
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector2::typeid)
|
||||
{
|
||||
Vector2 vec = safe_cast<Vector2>(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<Vector3>(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)
|
||||
|
|
|
@ -23,11 +23,12 @@ namespace SHADE
|
|||
/* Serialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename FieldType>
|
||||
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<FieldType>(fieldInfo->GetValue(object));
|
||||
const FieldType VALUE = safe_cast<FieldType>(fieldInfo->GetValue(object));
|
||||
fieldNode = static_cast<FieldType>(VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,7 @@ namespace SHADE
|
|||
template<typename FieldType>
|
||||
bool ReflectionUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
return fieldAssignYaml<FieldType, FieldType>(fieldInfo, object, node);
|
||||
return fieldAssignYaml<FieldType, ToNativeType_T<FieldType>>(fieldInfo, object, node);
|
||||
}
|
||||
|
||||
template<typename FieldType, typename CastType>
|
||||
|
|
|
@ -52,24 +52,24 @@ namespace SHADE
|
|||
/// attribute will be serialised.
|
||||
/// </summary>
|
||||
/// <param name="object">The object to serialise.</param>
|
||||
static void Serialise(System::Object^ object, YAML::Emitter& yaml);
|
||||
static void Serialise(System::Object^ object, YAML::Node& yamlNode);
|
||||
/// <summary>
|
||||
/// Deserialises a YAML node that contains a map of Scripts and copies the
|
||||
/// deserialised data into the specified object if there are matching fields.
|
||||
/// </summary>
|
||||
/// <param name="yamlNode">
|
||||
/// 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.
|
||||
/// </param>
|
||||
/// <param name="object">The object to copy deserialised data into.</param>
|
||||
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<typename FieldType>
|
||||
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<typename FieldType>
|
||||
static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node);
|
||||
|
|
|
@ -91,4 +91,68 @@ namespace SHADE
|
|||
/// <returns>Managed copy of a native std::string.</returns>
|
||||
static System::String^ ToCLI(const std::string& str);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Type Transformer for managed types to native types.
|
||||
/// </summary>
|
||||
/// <typeparam name="ManagedType">
|
||||
/// Managed type to get the native type for.
|
||||
/// </typeparam>
|
||||
template<typename ManagedType>
|
||||
struct ToNativeType
|
||||
{
|
||||
public:
|
||||
using Value = void;
|
||||
};
|
||||
template<> struct ToNativeType<System::Int16> { using Value = int16_t; };
|
||||
template<> struct ToNativeType<System::Int32> { using Value = int32_t; };
|
||||
template<> struct ToNativeType<System::Int64> { using Value = int64_t; };
|
||||
template<> struct ToNativeType<System::UInt16> { using Value = uint16_t; };
|
||||
template<> struct ToNativeType<System::UInt32> { using Value = uint32_t; };
|
||||
template<> struct ToNativeType<System::UInt64> { using Value = uint64_t; };
|
||||
template<> struct ToNativeType<System::Byte> { using Value = int8_t; };
|
||||
template<> struct ToNativeType<bool> { using Value = bool; };
|
||||
template<> struct ToNativeType<double> { using Value = double; };
|
||||
template<> struct ToNativeType<float> { using Value = float; };
|
||||
|
||||
/// <summary>
|
||||
/// Alias for ToNativeType::Value
|
||||
/// </summary>
|
||||
/// <typeparam name="ManagedType">
|
||||
/// Managed type to get the native type for.
|
||||
/// </typeparam>
|
||||
template<typename ManagedType>
|
||||
using ToNativeType_T = typename ToNativeType<ManagedType>::Value;
|
||||
|
||||
/// <summary>
|
||||
/// Type Transformer for native types to managed types.
|
||||
/// </summary>
|
||||
/// <typeparam name="ManagedType">
|
||||
/// Managed type to get the native type for.
|
||||
/// </typeparam>
|
||||
template<typename NativeType>
|
||||
struct ToManagedType
|
||||
{
|
||||
public:
|
||||
using Value = void;
|
||||
};
|
||||
template<> struct ToManagedType<int8_t> { using Value = System::Byte; };
|
||||
template<> struct ToManagedType<int16_t> { using Value = System::Int16; };
|
||||
template<> struct ToManagedType<int32_t> { using Value = System::Int32; };
|
||||
template<> struct ToManagedType<int64_t> { using Value = System::Int64; };
|
||||
template<> struct ToManagedType<uint16_t> { using Value = System::UInt16; };
|
||||
template<> struct ToManagedType<uint32_t> { using Value = System::UInt32; };
|
||||
template<> struct ToManagedType<uint64_t> { using Value = System::UInt64; };
|
||||
template<> struct ToManagedType<bool> { using Value = bool; };
|
||||
template<> struct ToManagedType<double> { using Value = double; };
|
||||
template<> struct ToManagedType<float> { using Value = float; };
|
||||
|
||||
/// <summary>
|
||||
/// Alias for ToManagedType::Value
|
||||
/// </summary>
|
||||
/// <typeparam name="ManagedType">
|
||||
/// Managed type to get the native type for.
|
||||
/// </typeparam>
|
||||
template<typename NativeType>
|
||||
using ToManagedType_T = typename ToManagedType<NativeType>::Value;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue