List Serialization and Editor for Scripts #193

Merged
Pycorax merged 21 commits from SP3-6-ArraySerialization into main 2022-11-13 11:58:06 +08:00
8 changed files with 462 additions and 317 deletions
Showing only changes of commit 889d3dac4c - Show all commits

View File

@ -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);

View File

@ -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
{

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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++"
}

View File

@ -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)
));
}
}
}

View File

@ -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;
}
}

View File

@ -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++"