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
5 changed files with 172 additions and 88 deletions
Showing only changes of commit d98deda63d - Show all commits

View File

@ -41,7 +41,12 @@ namespace SHADE
bool ReflectionUtilities::FieldIsList(System::Reflection::FieldInfo^ fieldInfo) bool ReflectionUtilities::FieldIsList(System::Reflection::FieldInfo^ fieldInfo)
{ {
return fieldInfo->FieldType->IsGenericType return IsList(fieldInfo->FieldType);
&& fieldInfo->FieldType->GetGenericTypeDefinition() == System::Collections::Generic::List<int>::typeid->GetGenericTypeDefinition(); }
bool ReflectionUtilities::IsList(System::Type^ type)
{
return type->IsGenericType
&& type->GetGenericTypeDefinition() == System::Collections::Generic::List<int>::typeid->GetGenericTypeDefinition();
} }
} }

View File

@ -45,5 +45,11 @@ namespace SHADE
/// <param name="fieldInfo">The field to check.</param> /// <param name="fieldInfo">The field to check.</param>
/// <returns>True if fieldInfo is describing a generic List.</returns> /// <returns>True if fieldInfo is describing a generic List.</returns>
static bool FieldIsList(System::Reflection::FieldInfo^ fieldInfo); static bool FieldIsList(System::Reflection::FieldInfo^ fieldInfo);
/// <summary>
/// Checks if the specified type is a generic List type.
/// </summary>
/// <param name="type">The type to check.</param>
/// <returns>True if type is a generic List.</returns>
static bool IsList(System::Type^ type);
}; };
} }

View File

@ -173,79 +173,88 @@ namespace SHADE
varInsertYamlInternal<GameObject >(object, fieldNode); varInsertYamlInternal<GameObject >(object, fieldNode);
return INSERTED; return INSERTED;
} }
void SerialisationUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) /*---------------------------------------------------------------------------------*/
/* Deserialization Helper Functions */
/*---------------------------------------------------------------------------------*/
bool SerialisationUtilities::writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
{ {
if (fieldAssignYaml<System::Int16> (fieldInfo, object, node) || const bool ASSIGNED =
fieldAssignYaml<System::Int32> (fieldInfo, object, node) || fieldAssignYaml<System::Int16> (fieldInfo, object, node) ||
fieldAssignYaml<System::Int64> (fieldInfo, object, node) || fieldAssignYaml<System::Int32> (fieldInfo, object, node) ||
fieldAssignYaml<System::UInt16>(fieldInfo, object, node) || fieldAssignYaml<System::Int64> (fieldInfo, object, node) ||
fieldAssignYaml<System::UInt32>(fieldInfo, object, node) || fieldAssignYaml<System::UInt16>(fieldInfo, object, node) ||
fieldAssignYaml<System::UInt64>(fieldInfo, object, node) || fieldAssignYaml<System::UInt32>(fieldInfo, object, node) ||
fieldAssignYaml<System::Byte> (fieldInfo, object, node) || fieldAssignYaml<System::UInt64>(fieldInfo, object, node) ||
fieldAssignYaml<bool> (fieldInfo, object, node) || fieldAssignYaml<System::Byte> (fieldInfo, object, node) ||
fieldAssignYaml<float> (fieldInfo, object, node) || fieldAssignYaml<bool> (fieldInfo, object, node) ||
fieldAssignYaml<double> (fieldInfo, object, node)) fieldAssignYaml<float> (fieldInfo, object, node) ||
fieldAssignYaml<double> (fieldInfo, object, node) ||
fieldAssignYaml<System::Enum> (fieldInfo, object, node) ||
fieldAssignYaml<System::String>(fieldInfo, object, node) ||
fieldAssignYaml<Vector2> (fieldInfo, object, node) ||
fieldAssignYaml<Vector3> (fieldInfo, object, node) ||
fieldAssignYaml<GameObject> (fieldInfo, object, node);
if (!ASSIGNED)
{ {
return; if (ReflectionUtilities::FieldIsList(fieldInfo))
}
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; System::Type^ elemType = fieldInfo->FieldType->GenericTypeArguments[0];
vec.x = node[0].as<float>(); System::Collections::IList^ iList = safe_cast<System::Collections::IList^>(fieldInfo->GetValue(object));
vec.y = node[1].as<float>(); if (node.IsSequence())
fieldInfo->SetValue(object, vec); {
} // Get list size
else const int LIST_SIZE = static_cast<int>(node.size());
{ if (LIST_SIZE > 0)
Debug::LogWarning {
( // Get list type
System::String::Format("[SerialisationUtilities] Invalid YAML Node provided for deserialization of a Vector2 \"{0}\" field in \"{1}\" script.", array<System::Type^>^ typeList = gcnew array<System::Type^>{ elemType };
fieldInfo->Name, object->GetType()->FullName) System::Type^ listType = System::Collections::Generic::List<int>::typeid->GetGenericTypeDefinition()->MakeGenericType(typeList);
); // Create a list of the specified type
array<int>^ params = gcnew array<int>{ node.size() };
object = System::Activator::CreateInstance(listType, params);
System::Collections::IList^ list = safe_cast<System::Collections::IList^>(object);
// Populate the list
for (int i = 0; i < LIST_SIZE; ++i)
{
// Create the object
System::Object^ obj = System::Activator::CreateInstance(elemType);
// Set it's value
if (varAssignYaml(obj, node[i]))
{
list->Add(obj);
}
}
}
}
return true;
} }
} }
else if (fieldInfo->FieldType == Vector3::typeid)
{ return ASSIGNED;
if (node.IsSequence() && node.size() == 3) }
{
Vector3 vec; bool SerialisationUtilities::varAssignYaml(System::Object^% object, YAML::Node& node)
vec.x = node[0].as<float>(); {
vec.y = node[1].as<float>(); const bool DESERIALISED =
vec.z = node[2].as<float>(); varAssignYamlInternal<System::Int16> (object, node) ||
fieldInfo->SetValue(object, vec); varAssignYamlInternal<System::Int32> (object, node) ||
} varAssignYamlInternal<System::Int64> (object, node) ||
else varAssignYamlInternal<System::UInt16>(object, node) ||
{ varAssignYamlInternal<System::UInt32>(object, node) ||
Debug::LogWarning varAssignYamlInternal<System::UInt64>(object, node) ||
( varAssignYamlInternal<System::Byte> (object, node) ||
System::String::Format("[SerialisationUtilities] Invalid YAML Node provided for deserialization of a Vector3 \"{0}\" field in \"{1}\" script.", varAssignYamlInternal<bool> (object, node) ||
fieldInfo->Name, object->GetType()->FullName) varAssignYamlInternal<float> (object, node) ||
); varAssignYamlInternal<double> (object, node) ||
} varAssignYamlInternal<System::Enum> (object, node) ||
} varAssignYamlInternal<System::String>(object, node) ||
else if (fieldInfo->FieldType == GameObject::typeid) varAssignYamlInternal<Vector2> (object, node) ||
{ varAssignYamlInternal<Vector3> (object, node) ||
const uint32_t EID = node.as<uint32_t>(); varAssignYamlInternal<GameObject> (object, node);
fieldInfo->SetValue(object, EID == MAX_EID ? GameObject() : GameObject(EID)); return DESERIALISED;
}
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

@ -36,7 +36,6 @@ namespace SHADE
{ {
if constexpr (std::is_same_v<FieldType, System::Enum>) if constexpr (std::is_same_v<FieldType, System::Enum>)
{ {
Debug::Log("Enum Specialization");
if (object->GetType()->IsSubclassOf(System::Enum::typeid)) if (object->GetType()->IsSubclassOf(System::Enum::typeid))
{ {
fieldNode = std::to_string(safe_cast<int>(object)); fieldNode = std::to_string(safe_cast<int>(object));
@ -45,7 +44,6 @@ namespace SHADE
} }
else if constexpr (std::is_same_v<FieldType, System::String>) else if constexpr (std::is_same_v<FieldType, System::String>)
{ {
Debug::Log("String Specialization");
if (object->GetType() == System::String::typeid) if (object->GetType() == System::String::typeid)
{ {
System::String^ str = safe_cast<System::String^>(object); System::String^ str = safe_cast<System::String^>(object);
@ -55,7 +53,6 @@ namespace SHADE
} }
else if constexpr (std::is_same_v<FieldType, Vector2>) else if constexpr (std::is_same_v<FieldType, Vector2>)
{ {
Debug::Log("Vec2 Specialization");
if (object->GetType() == Vector2::typeid) if (object->GetType() == Vector2::typeid)
{ {
Vector2 vec = safe_cast<Vector2>(object); Vector2 vec = safe_cast<Vector2>(object);
@ -67,7 +64,6 @@ namespace SHADE
} }
else if constexpr (std::is_same_v<FieldType, Vector3>) else if constexpr (std::is_same_v<FieldType, Vector3>)
{ {
Debug::Log("Vec3 Specialization");
if (object->GetType() == Vector3::typeid) if (object->GetType() == Vector3::typeid)
{ {
Vector3 vec = safe_cast<Vector3>(object); Vector3 vec = safe_cast<Vector3>(object);
@ -80,7 +76,6 @@ namespace SHADE
} }
else if constexpr (std::is_same_v<FieldType, GameObject>) else if constexpr (std::is_same_v<FieldType, GameObject>)
{ {
Debug::Log("GameObject Specialization");
if (object->GetType() == GameObject::typeid) if (object->GetType() == GameObject::typeid)
{ {
GameObject gameObj = safe_cast<GameObject>(object); GameObject gameObj = safe_cast<GameObject>(object);
@ -90,7 +85,6 @@ namespace SHADE
} }
else else
{ {
Debug::Log("No Specialization");
if (object->GetType() == FieldType::typeid) if (object->GetType() == FieldType::typeid)
{ {
FieldType value = safe_cast<FieldType>(object); FieldType value = safe_cast<FieldType>(object);
@ -108,18 +102,87 @@ namespace SHADE
template<typename FieldType> template<typename FieldType>
bool SerialisationUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node) bool SerialisationUtilities::fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node)
{ {
return fieldAssignYaml<FieldType, ToNativeType_T<FieldType>>(fieldInfo, object, node); System::Object^ valueObj = fieldInfo->GetValue(object);
} if (varAssignYamlInternal<FieldType>(valueObj, 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>()); fieldInfo->SetValue(object, valueObj);
return true; return true;
} }
return false; return false;
} }
template<typename FieldType, typename CastType>
bool SerialisationUtilities::varAssignYamlInternal(System::Object^% object, YAML::Node& node)
{
if constexpr (std::is_same_v<FieldType, System::Enum>)
{
if (object->GetType()->IsSubclassOf(System::Enum::typeid))
{
object = node.as<int>();
return true;
}
}
else if constexpr (std::is_same_v<FieldType, System::Collections::IList>)
{
if (ReflectionUtilities::FieldIsList(fieldInfo))
{
System::Collections::IList^ iList = safe_cast<System::Collections::IList^>(object);
object = gcnew
if (node.IsSequence() )
}
}
else
{
if (object->GetType() == FieldType::typeid)
{
if constexpr (std::is_same_v<FieldType, System::String>)
{
object = Convert::ToCLI(node.as<std::string>());
}
else if constexpr (std::is_same_v<FieldType, Vector2>)
{
if (node.IsSequence() && node.size() == 2)
{
Vector2 vec;
vec.x = node[0].as<float>();
vec.y = node[1].as<float>();
object = vec;
}
else
{
return false;
}
}
else if constexpr (std::is_same_v<FieldType, Vector3>)
{
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>();
object = vec;
}
else
{
return false;
}
}
else if constexpr (std::is_same_v<FieldType, GameObject>)
{
const uint32_t EID = node.as<uint32_t>();
object = (EID == MAX_EID ? GameObject() : GameObject(EID));
}
else
{
object = node.as<CastType>();
}
return true;
}
}
return false;
}
} }

View File

@ -63,11 +63,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Deserialization Helper Functions */ /* Deserialization Helper Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
static void writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); static bool writeYamlIntoField(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node);
template<typename FieldType> template<typename FieldType>
static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node);
template<typename FieldType, typename CastType> static bool varAssignYaml(System::Object^% object, YAML::Node& node);
static bool fieldAssignYaml(System::Reflection::FieldInfo^ fieldInfo, Object^ object, YAML::Node& node); template<typename FieldType, typename CastType = ToNativeType_T<FieldType>>
static bool varAssignYamlInternal(System::Object^% object, YAML::Node& node);
}; };
} }