List Serialization and Editor for Scripts #193
|
@ -172,7 +172,7 @@ namespace SHADE
|
|||
if (!MODIFIED_PRIMITIVE)
|
||||
{
|
||||
// Any List
|
||||
if (field->FieldType->IsGenericType && field->FieldType->GetGenericTypeDefinition() == System::Collections::Generic::List<int>::typeid->GetGenericTypeDefinition())
|
||||
if (ReflectionUtilities::FieldIsList(field))
|
||||
{
|
||||
System::Type^ listType = field->FieldType->GenericTypeArguments[0];
|
||||
RangeAttribute^ rangeAttrib = hasAttribute<RangeAttribute^>(field);
|
||||
|
|
|
@ -26,7 +26,7 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Utility/Convert.hxx"
|
||||
#include "Script.hxx"
|
||||
#include "Engine/Entity.hxx"
|
||||
#include "Serialisation/ReflectionUtilities.hxx"
|
||||
#include "Serialisation/SerialisationUtilities.hxx"
|
||||
#include "Engine/Application.hxx"
|
||||
#include "Physics/SHPhysicsSystemInterface.h"
|
||||
#include "Physics/SHPhysicsUtils.h"
|
||||
|
@ -613,7 +613,7 @@ namespace SHADE
|
|||
System::Collections::Generic::List<Script^>^ scriptList = scripts[entity];
|
||||
for each (Script^ script in scriptList)
|
||||
{
|
||||
ReflectionUtilities::Serialise(script, *yamlNode);
|
||||
SerialisationUtilities::Serialise(script, *yamlNode);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -658,7 +658,7 @@ namespace SHADE
|
|||
if (AddScriptViaNameWithRef(entity, typeName, script))
|
||||
{
|
||||
// Copy the data in
|
||||
ReflectionUtilities::Deserialise(script, node);
|
||||
SerialisationUtilities::Deserialise(script, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -18,31 +18,6 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Serialisation/ReflectionUtilities.hxx"
|
||||
// Project Includes
|
||||
#include "SerializeFieldAttribute.hxx"
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Math/Vector2.hxx"
|
||||
#include "Math/Vector3.hxx"
|
||||
#include "Utility/Debug.hxx"
|
||||
#include "Engine/GameObject.hxx"
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Macro Functions */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Macro expansion that is used in RapidJsonValueToField() to retrieve the specified
|
||||
/// member of a Vector type that is stored into a Vector named "vec".
|
||||
/// </summary>
|
||||
/// <param name="MEMBER">The name of the member to retrieve.</param>
|
||||
#define PRIMITIVE_VECTOR_FIELD_ASSIGN(MEMBER) \
|
||||
iter = jsonValue.FindMember(#MEMBER); \
|
||||
if (iter != jsonValue.MemberEnd()) \
|
||||
{ \
|
||||
vec.MEMBER = iter->value.GetDouble(); \
|
||||
} \
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* File-Level Constants */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
static const std::string_view SCRIPT_TYPE_YAMLTAG = "Type";
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Function Definitions */
|
||||
|
@ -64,202 +39,9 @@ namespace SHADE
|
|||
return fieldInfo->IsPublic || fieldInfo->GetCustomAttributes(SerializeField::typeid, true)->Length > 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialisation Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void ReflectionUtilities::Serialise(System::Object^ object, YAML::Node& scriptListNode)
|
||||
bool ReflectionUtilities::FieldIsList(System::Reflection::FieldInfo^ fieldInfo)
|
||||
{
|
||||
using namespace System::Reflection;
|
||||
|
||||
// Create YAML object
|
||||
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);
|
||||
for each (FieldInfo^ field in fields)
|
||||
{
|
||||
// Ignore private and non-SerialiseField
|
||||
if (!FieldIsSerialisable(field))
|
||||
continue;
|
||||
|
||||
// Serialise
|
||||
writeFieldIntoYaml(field, object, scriptNode);
|
||||
}
|
||||
|
||||
scriptListNode.push_back(scriptNode);
|
||||
}
|
||||
void ReflectionUtilities::Deserialise(Object^ object, YAML::Node& yamlNode)
|
||||
{
|
||||
using namespace System::Reflection;
|
||||
|
||||
// Load the YAML
|
||||
if (!yamlNode.IsMap())
|
||||
{
|
||||
// Invalid
|
||||
Debug::LogError
|
||||
(
|
||||
System::String::Format("[ReflectionUtilities] Invalid YAML Node provided for deserialization of \"{0}\" script.",
|
||||
object->GetType()->FullName)
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Get all fields
|
||||
System::Collections::Generic::IEnumerable<FieldInfo^>^ fields = GetInstanceFields(object);
|
||||
for each (FieldInfo^ field in fields)
|
||||
{
|
||||
// Ignore private and non-SerialiseField
|
||||
if (!FieldIsSerialisable(field))
|
||||
continue;
|
||||
|
||||
// Deserialise
|
||||
const std::string FIELD_NAME = Convert::ToNative(field->Name);
|
||||
if (yamlNode[FIELD_NAME])
|
||||
{
|
||||
writeYamlIntoField(field, object, yamlNode[FIELD_NAME]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void ReflectionUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode)
|
||||
{
|
||||
// Field YAML Node
|
||||
YAML::Node fieldNode;
|
||||
|
||||
// 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)
|
||||
{
|
||||
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 if (fieldInfo->FieldType == GameObject::typeid)
|
||||
{
|
||||
GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object));
|
||||
fieldNode = gameObj ? gameObj.GetEntity() : MAX_EID;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (fieldAssignYaml<System::Int16> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Int32> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Int64> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt16>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt32>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt64>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Byte> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<bool> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<float> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<double> (fieldInfo, object, node))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid))
|
||||
{
|
||||
fieldInfo->SetValue(object, node.as<int>());
|
||||
}
|
||||
else if (fieldInfo->FieldType == System::String::typeid)
|
||||
{
|
||||
fieldInfo->SetValue(object, Convert::ToCLI(node.as<std::string>()));
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector2::typeid)
|
||||
{
|
||||
if (node.IsSequence() && node.size() == 2)
|
||||
{
|
||||
Vector2 vec;
|
||||
vec.x = node[0].as<float>();
|
||||
vec.y = node[1].as<float>();
|
||||
fieldInfo->SetValue(object, vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::LogWarning
|
||||
(
|
||||
System::String::Format("[ReflectionUtilities] Invalid YAML Node provided for deserialization of a Vector2 \"{0}\" field in \"{1}\" script.",
|
||||
fieldInfo->Name, object->GetType()->FullName)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector3::typeid)
|
||||
{
|
||||
if (node.IsSequence() && node.size() == 3)
|
||||
{
|
||||
Vector3 vec;
|
||||
vec.x = node[0].as<float>();
|
||||
vec.y = node[1].as<float>();
|
||||
vec.z = node[2].as<float>();
|
||||
fieldInfo->SetValue(object, vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::LogWarning
|
||||
(
|
||||
System::String::Format("[ReflectionUtilities] Invalid YAML Node provided for deserialization of a Vector3 \"{0}\" field in \"{1}\" script.",
|
||||
fieldInfo->Name, object->GetType()->FullName)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (fieldInfo->FieldType == GameObject::typeid)
|
||||
{
|
||||
const uint32_t EID = node.as<uint32_t>();
|
||||
fieldInfo->SetValue(object, EID == MAX_EID ? GameObject() : GameObject(EID));
|
||||
}
|
||||
else // Not any of the supported types
|
||||
{
|
||||
Debug::LogWarning(Convert::ToNative(System::String::Format
|
||||
(
|
||||
"[ReflectionUtilities] Failed to parse \"{0}\" of \"{1}\" type for deserialisation.",
|
||||
fieldInfo->Name, fieldInfo->FieldType)
|
||||
));
|
||||
}
|
||||
return fieldInfo->FieldType->IsGenericType
|
||||
&& fieldInfo->FieldType->GetGenericTypeDefinition() == System::Collections::Generic::List<int>::typeid->GetGenericTypeDefinition();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/************************************************************************************//*!
|
||||
\file ReflectionUtilities.h++
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Sep 16, 2022
|
||||
\brief Contains the definition of the template functions of the managed
|
||||
ReflectionUtilities static class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// Primary Header
|
||||
#include "ReflectionUtilities.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename FieldType>
|
||||
bool ReflectionUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode)
|
||||
{
|
||||
if (fieldInfo->FieldType == FieldType::typeid)
|
||||
{
|
||||
const FieldType VALUE = safe_cast<FieldType>(fieldInfo->GetValue(object));
|
||||
fieldNode = static_cast<FieldType>(VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename FieldType>
|
||||
bool ReflectionUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
return fieldAssignYaml<FieldType, ToNativeType_T<FieldType>>(fieldInfo, object, node);
|
||||
}
|
||||
|
||||
template<typename FieldType, typename CastType>
|
||||
bool ReflectionUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
if (fieldInfo->FieldType == FieldType::typeid)
|
||||
{
|
||||
fieldInfo->SetValue(object, node.as<CastType>());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -13,9 +13,6 @@ of DigiPen Institute of Technology is prohibited.
|
|||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// External Dependencies
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -42,40 +39,11 @@ namespace SHADE
|
|||
/// True if the specified field is a candidate for serialisation.
|
||||
/// </returns>
|
||||
static bool FieldIsSerialisable(System::Reflection::FieldInfo^ fieldInfo);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Serialisation Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Creates a JSON node that represents the specified object and its associated
|
||||
/// serialisable fields. Public fields and fields marked with the SerialiseField
|
||||
/// attribute will be serialised.
|
||||
/// Checks if the specified field is a generic List.
|
||||
/// </summary>
|
||||
/// <param name="object">The object to serialise.</param>
|
||||
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 Script object.
|
||||
/// </param>
|
||||
/// <param name="object">The object to copy deserialised data into.</param>
|
||||
static void Deserialise(System::Object^ object, YAML::Node& yamlNode);
|
||||
|
||||
private:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
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::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);
|
||||
template<typename FieldType, typename CastType>
|
||||
static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node);
|
||||
/// <param name="fieldInfo">The field to check.</param>
|
||||
/// <returns>True if fieldInfo is describing a generic List.</returns>
|
||||
static bool FieldIsList(System::Reflection::FieldInfo^ fieldInfo);
|
||||
};
|
||||
}
|
||||
|
||||
#include "ReflectionUtilities.h++"
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/************************************************************************************//*!
|
||||
\file SerialisationUtilities.cxx
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Nov 6, 2021
|
||||
\brief Contains the definition of the functions for the SerialisationUtilities
|
||||
managed static class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2021 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
// Precompiled Headers
|
||||
#include "SHpch.h"
|
||||
// Primary Header
|
||||
#include "Serialisation/SerialisationUtilities.hxx"
|
||||
// Project Includes
|
||||
#include "ReflectionUtilities.hxx"
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* File-Level Constants */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
static const std::string_view SCRIPT_TYPE_YAMLTAG = "Type";
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Function Definitions */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
namespace SHADE
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialisation Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void SerialisationUtilities::Serialise(System::Object^ object, YAML::Node& scriptListNode)
|
||||
{
|
||||
using namespace System::Reflection;
|
||||
|
||||
// Create YAML object
|
||||
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 = ReflectionUtilities::GetInstanceFields(object);
|
||||
for each (FieldInfo^ field in fields)
|
||||
{
|
||||
// Ignore private and non-SerialiseField
|
||||
if (!ReflectionUtilities::FieldIsSerialisable(field))
|
||||
continue;
|
||||
|
||||
// Serialise
|
||||
writeFieldIntoYaml(field, object, scriptNode);
|
||||
}
|
||||
|
||||
scriptListNode.push_back(scriptNode);
|
||||
}
|
||||
void SerialisationUtilities::Deserialise(Object^ object, YAML::Node& yamlNode)
|
||||
{
|
||||
using namespace System::Reflection;
|
||||
|
||||
// Load the YAML
|
||||
if (!yamlNode.IsMap())
|
||||
{
|
||||
// Invalid
|
||||
Debug::LogError
|
||||
(
|
||||
System::String::Format("[SerialisationUtilities] Invalid YAML Node provided for deserialization of \"{0}\" script.",
|
||||
object->GetType()->FullName)
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Get all fields
|
||||
System::Collections::Generic::IEnumerable<FieldInfo^>^ fields = ReflectionUtilities::GetInstanceFields(object);
|
||||
for each (FieldInfo^ field in fields)
|
||||
{
|
||||
// Ignore private and non-SerialiseField
|
||||
if (!ReflectionUtilities::FieldIsSerialisable(field))
|
||||
continue;
|
||||
|
||||
// Deserialise
|
||||
const std::string FIELD_NAME = Convert::ToNative(field->Name);
|
||||
if (yamlNode[FIELD_NAME])
|
||||
{
|
||||
writeYamlIntoField(field, object, yamlNode[FIELD_NAME]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void SerialisationUtilities::writeFieldIntoYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& yamlNode)
|
||||
{
|
||||
// Field YAML Node
|
||||
YAML::Node fieldNode;
|
||||
|
||||
// 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) ||
|
||||
fieldInsertYaml<System::Enum >(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<System::String>(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<Vector2 >(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<Vector3 >(fieldInfo, object, fieldNode) ||
|
||||
fieldInsertYaml<GameObject >(fieldInfo, object, fieldNode);
|
||||
|
||||
// Serialization of more complex types
|
||||
if (!PRIMITIVE_SERIALIZED)
|
||||
{
|
||||
if (ReflectionUtilities::FieldIsList(fieldInfo))
|
||||
{
|
||||
System::Type^ listType = fieldInfo->FieldType->GenericTypeArguments[0];
|
||||
System::Collections::IList^ iList = safe_cast<System::Collections::IList^>(fieldInfo->GetValue(object));
|
||||
|
||||
|
||||
fieldNode.SetStyle(YAML::EmitterStyle::Block);
|
||||
for (int i = 0; i < iList->Count; ++i)
|
||||
{
|
||||
YAML::Node elemNode;
|
||||
if (varInsertYaml(iList[i], elemNode))
|
||||
{
|
||||
fieldNode.push_back(elemNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::LogWarning(Convert::ToNative(System::String::Format
|
||||
(
|
||||
"[SerialisationUtilities] Failed to parse element # {2} of \"{0}\" of \"{1}\" type for serialization.",
|
||||
fieldInfo->Name, fieldInfo->FieldType, i)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Not any of the supported types
|
||||
{
|
||||
Debug::LogWarning(Convert::ToNative(System::String::Format
|
||||
(
|
||||
"[SerialisationUtilities] 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;
|
||||
}
|
||||
|
||||
bool SerialisationUtilities::varInsertYaml(System::Object^ object, YAML::Node& fieldNode)
|
||||
{
|
||||
const bool INSERTED =
|
||||
varInsertYamlInternal<System::Int16 >(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::Int32 >(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::Int64 >(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::UInt16>(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::UInt32>(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::UInt64>(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::Byte >(object, fieldNode) ||
|
||||
varInsertYamlInternal<bool >(object, fieldNode) ||
|
||||
varInsertYamlInternal<float >(object, fieldNode) ||
|
||||
varInsertYamlInternal<double >(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::Enum >(object, fieldNode) ||
|
||||
varInsertYamlInternal<System::String>(object, fieldNode) ||
|
||||
varInsertYamlInternal<Vector2 >(object, fieldNode) ||
|
||||
varInsertYamlInternal<Vector3 >(object, fieldNode) ||
|
||||
varInsertYamlInternal<GameObject >(object, fieldNode);
|
||||
return INSERTED;
|
||||
}
|
||||
|
||||
void SerialisationUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
if (fieldAssignYaml<System::Int16> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Int32> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Int64> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt16>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt32>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::UInt64>(fieldInfo, object, node) ||
|
||||
fieldAssignYaml<System::Byte> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<bool> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<float> (fieldInfo, object, node) ||
|
||||
fieldAssignYaml<double> (fieldInfo, object, node))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (fieldInfo->FieldType->IsSubclassOf(System::Enum::typeid))
|
||||
{
|
||||
fieldInfo->SetValue(object, node.as<int>());
|
||||
}
|
||||
else if (fieldInfo->FieldType == System::String::typeid)
|
||||
{
|
||||
fieldInfo->SetValue(object, Convert::ToCLI(node.as<std::string>()));
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector2::typeid)
|
||||
{
|
||||
if (node.IsSequence() && node.size() == 2)
|
||||
{
|
||||
Vector2 vec;
|
||||
vec.x = node[0].as<float>();
|
||||
vec.y = node[1].as<float>();
|
||||
fieldInfo->SetValue(object, vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::LogWarning
|
||||
(
|
||||
System::String::Format("[SerialisationUtilities] Invalid YAML Node provided for deserialization of a Vector2 \"{0}\" field in \"{1}\" script.",
|
||||
fieldInfo->Name, object->GetType()->FullName)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (fieldInfo->FieldType == Vector3::typeid)
|
||||
{
|
||||
if (node.IsSequence() && node.size() == 3)
|
||||
{
|
||||
Vector3 vec;
|
||||
vec.x = node[0].as<float>();
|
||||
vec.y = node[1].as<float>();
|
||||
vec.z = node[2].as<float>();
|
||||
fieldInfo->SetValue(object, vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::LogWarning
|
||||
(
|
||||
System::String::Format("[SerialisationUtilities] Invalid YAML Node provided for deserialization of a Vector3 \"{0}\" field in \"{1}\" script.",
|
||||
fieldInfo->Name, object->GetType()->FullName)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (fieldInfo->FieldType == GameObject::typeid)
|
||||
{
|
||||
const uint32_t EID = node.as<uint32_t>();
|
||||
fieldInfo->SetValue(object, EID == MAX_EID ? GameObject() : GameObject(EID));
|
||||
}
|
||||
else // Not any of the supported types
|
||||
{
|
||||
Debug::LogWarning(Convert::ToNative(System::String::Format
|
||||
(
|
||||
"[SerialisationUtilities] Failed to parse \"{0}\" of \"{1}\" type for deserialisation.",
|
||||
fieldInfo->Name, fieldInfo->FieldType)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/************************************************************************************//*!
|
||||
\file SerialisationUtilities.h++
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Sep 16, 2022
|
||||
\brief Contains the definition of the template functions of the managed
|
||||
ReflectionUtilities static class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// Primary Header
|
||||
#include "SerialisationUtilities.hxx"
|
||||
// Project Includes
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Utility/Debug.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename FieldType>
|
||||
bool SerialisationUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode)
|
||||
{
|
||||
Debug::Log(FieldType::typeid->Name);
|
||||
return varInsertYamlInternal<FieldType>(fieldInfo->GetValue(object), fieldNode);
|
||||
}
|
||||
template<typename FieldType>
|
||||
bool SerialisationUtilities::varInsertYamlInternal(System::Object^ object, YAML::Node& fieldNode)
|
||||
{
|
||||
if constexpr (std::is_same_v<FieldType, System::Enum>)
|
||||
{
|
||||
Debug::Log("Enum Specialization");
|
||||
if (object->GetType()->IsSubclassOf(System::Enum::typeid))
|
||||
{
|
||||
fieldNode = std::to_string(safe_cast<int>(object));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, System::String>)
|
||||
{
|
||||
Debug::Log("String Specialization");
|
||||
if (object->GetType() == System::String::typeid)
|
||||
{
|
||||
System::String^ str = safe_cast<System::String^>(object);
|
||||
fieldNode = Convert::ToNative(str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, Vector2>)
|
||||
{
|
||||
Debug::Log("Vec2 Specialization");
|
||||
if (object->GetType() == Vector2::typeid)
|
||||
{
|
||||
Vector2 vec = safe_cast<Vector2>(object);
|
||||
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
|
||||
fieldNode.push_back(vec.x);
|
||||
fieldNode.push_back(vec.y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, Vector3>)
|
||||
{
|
||||
Debug::Log("Vec3 Specialization");
|
||||
if (object->GetType() == Vector3::typeid)
|
||||
{
|
||||
Vector3 vec = safe_cast<Vector3>(object);
|
||||
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
|
||||
fieldNode.push_back(vec.x);
|
||||
fieldNode.push_back(vec.y);
|
||||
fieldNode.push_back(vec.z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, GameObject>)
|
||||
{
|
||||
Debug::Log("GameObject Specialization");
|
||||
if (object->GetType() == GameObject::typeid)
|
||||
{
|
||||
GameObject gameObj = safe_cast<GameObject>(object);
|
||||
fieldNode = gameObj ? gameObj.GetEntity() : MAX_EID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::Log("No Specialization");
|
||||
if (object->GetType() == FieldType::typeid)
|
||||
{
|
||||
FieldType value = safe_cast<FieldType>(object);
|
||||
fieldNode = static_cast<FieldType>(value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Deserialization Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename FieldType>
|
||||
bool SerialisationUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
return fieldAssignYaml<FieldType, ToNativeType_T<FieldType>>(fieldInfo, object, node);
|
||||
}
|
||||
|
||||
template<typename FieldType, typename CastType>
|
||||
bool SerialisationUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
|
||||
{
|
||||
if (fieldInfo->FieldType == FieldType::typeid)
|
||||
{
|
||||
fieldInfo->SetValue(object, node.as<CastType>());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/************************************************************************************//*!
|
||||
\file SerialisationUtilities.hxx
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Nov 6, 2021
|
||||
\brief Contains the definition of the managed SerialisationUtilities static
|
||||
class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2021 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// External Dependencies
|
||||
#include <yaml-cpp/yaml.h>
|
||||
// Project Includes
|
||||
#include "Math/Vector2.hxx"
|
||||
#include "Math/Vector3.hxx"
|
||||
#include "Engine/GameObject.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains useful static functions for working with Serialisation of Managed data.
|
||||
/// </summary>
|
||||
private ref class SerialisationUtilities abstract sealed
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Serialisation Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Creates a JSON node that represents the specified object and its associated
|
||||
/// serialisable fields. Public fields and fields marked with the SerialiseField
|
||||
/// attribute will be serialised.
|
||||
/// </summary>
|
||||
/// <param name="object">The object to serialise.</param>
|
||||
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 Script object.
|
||||
/// </param>
|
||||
/// <param name="object">The object to copy deserialised data into.</param>
|
||||
static void Deserialise(System::Object^ object, YAML::Node& yamlNode);
|
||||
|
||||
private:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Serialization Helper Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
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::Node& fieldNode);
|
||||
static bool varInsertYaml(System::Object^ object, YAML::Node& fieldNode);
|
||||
template<typename FieldType>
|
||||
static bool varInsertYamlInternal(System::Object^ object, YAML::Node& fieldNode);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Deserialization Helper Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
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);
|
||||
template<typename FieldType, typename CastType>
|
||||
static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node);
|
||||
};
|
||||
}
|
||||
|
||||
#include "SerialisationUtilities.h++"
|
Loading…
Reference in New Issue