mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Serialize and Deserialize Lists and 1D-Arrays
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Extensions;
|
using GlitchyEngine.Extensions;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.Tracing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -82,20 +84,6 @@ internal class DeserializationObject
|
|||||||
|
|
||||||
DeserializedClasses.Add(id, context);
|
DeserializedClasses.Add(id, context);
|
||||||
|
|
||||||
ScriptGlue.Serialization_GetObjectTypeName(context._internalContext, out string fullTypeName);
|
|
||||||
|
|
||||||
Type type = GetTypeFromName(fullTypeName);
|
|
||||||
|
|
||||||
if (type == null)
|
|
||||||
return context;
|
|
||||||
|
|
||||||
context._instance = ActivatorExtension.CreateInstanceSafe(type);
|
|
||||||
|
|
||||||
if (context._instance == null)
|
|
||||||
return context;
|
|
||||||
|
|
||||||
context.DeserializeFields(context._instance);
|
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +115,11 @@ internal class DeserializationObject
|
|||||||
public EngineObjectReferenceHelper EngineObjectReference;
|
public EngineObjectReferenceHelper EngineObjectReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private T GetFieldValue<T>(string fieldName, SerializationType serializationType)
|
||||||
|
{
|
||||||
|
return (T)GetFieldValue(fieldName, serializationType);
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe object GetFieldValue(string fieldName, SerializationType serializationType)
|
private unsafe object GetFieldValue(string fieldName, SerializationType serializationType)
|
||||||
{
|
{
|
||||||
string completeFieldName = $"{_structScopeName}{fieldName}";
|
string completeFieldName = $"{_structScopeName}{fieldName}";
|
||||||
@@ -218,40 +211,43 @@ internal class DeserializationObject
|
|||||||
if (!EntitySerializer.SerializeField(field))
|
if (!EntitySerializer.SerializeField(field))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
changed |= DeserializeField(obj, field);
|
object currentValue = field.GetValue(obj);
|
||||||
|
|
||||||
|
object deserializeValue = DeserializeField(currentValue, field.FieldType, field.Name);
|
||||||
|
|
||||||
|
if (deserializeValue != NoValueDeserialized)
|
||||||
|
{
|
||||||
|
field.SetValue(obj, deserializeValue);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeserializeField(object targetInstance, FieldInfo field)
|
private object DeserializeField(object fieldValue, Type fieldType, string fieldName)
|
||||||
{
|
{
|
||||||
Type fieldType = field.FieldType;
|
|
||||||
|
|
||||||
object newFieldValue = NoValueDeserialized;
|
|
||||||
|
|
||||||
if (fieldType.IsPrimitive)
|
if (fieldType.IsPrimitive)
|
||||||
{
|
{
|
||||||
newFieldValue = DeserializePrimitive(field.Name, fieldType);
|
return DeserializePrimitive(fieldName, fieldType);
|
||||||
}
|
}
|
||||||
else if (fieldType == typeof(string))
|
else if (fieldType == typeof(string))
|
||||||
{
|
{
|
||||||
newFieldValue = GetFieldValue(field.Name, SerializationType.String);
|
return GetFieldValue(fieldName, SerializationType.String);
|
||||||
}
|
}
|
||||||
else if (fieldType.IsEnum)
|
else if (fieldType.IsEnum)
|
||||||
{
|
{
|
||||||
newFieldValue = DeserializeEnum(field.Name, fieldType);
|
return DeserializeEnum(fieldName, fieldType);
|
||||||
}
|
}
|
||||||
else if (fieldType.IsArray)
|
else if (fieldType.IsArray)
|
||||||
{
|
{
|
||||||
// Log.Error($"Array serialization not yet implemented");
|
return DeserializeList(fieldName, fieldType, fieldType.GetElementType());
|
||||||
}
|
}
|
||||||
else if (fieldType.IsGenericType)
|
else if (fieldType.IsGenericType)
|
||||||
{
|
{
|
||||||
if (fieldType.GetGenericTypeDefinition() == typeof(List<>))
|
if (fieldType.GetGenericTypeDefinition() == typeof(List<>))
|
||||||
{
|
{
|
||||||
//SerializeList(fieldName, type, o);
|
return DeserializeList(fieldName, fieldType, fieldType.GetGenericArguments()[0]);
|
||||||
Log.Error($"List serialization not yet implemented");
|
|
||||||
}
|
}
|
||||||
//else if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
//else if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||||
//{
|
//{
|
||||||
@@ -265,26 +261,18 @@ internal class DeserializationObject
|
|||||||
}
|
}
|
||||||
else if (fieldType.IsValueType)
|
else if (fieldType.IsValueType)
|
||||||
{
|
{
|
||||||
object structValue = field.GetValue(targetInstance);
|
return DeserializeStruct(fieldName, fieldValue);
|
||||||
|
|
||||||
newFieldValue = DeserializeStruct(field.Name, structValue);
|
|
||||||
}
|
}
|
||||||
else if (fieldType.IsClass)
|
else if (fieldType.IsClass)
|
||||||
{
|
{
|
||||||
newFieldValue = DeserializeClass(field.Name, fieldType);
|
return DeserializeClass(fieldName, fieldType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFieldValue != NoValueDeserialized)
|
return NoValueDeserialized;
|
||||||
{
|
|
||||||
field.SetValue(targetInstance, newFieldValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DeserializePrimitive(string fieldName, Type fieldType)
|
private object DeserializePrimitive(string fieldName, Type fieldType)
|
||||||
@@ -327,6 +315,89 @@ internal class DeserializationObject
|
|||||||
return GetFieldValue(fieldName, expectedType);
|
return GetFieldValue(fieldName, expectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type that was originally stored in the container, or null, if the type doesn't exist.
|
||||||
|
/// </summary>
|
||||||
|
public Type StoredType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ScriptGlue.Serialization_GetObjectTypeName(_internalContext, out string fullTypeName);
|
||||||
|
|
||||||
|
return GetTypeFromName(fullTypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object DeserializeList(string fieldName, Type fieldType, Type elementType)
|
||||||
|
{
|
||||||
|
UUID id = (UUID)GetFieldValue(fieldName, SerializationType.ObjectReference);
|
||||||
|
|
||||||
|
if (id == UUID.Zero)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Get serialization container for the instance
|
||||||
|
DeserializationObject deserializedObject = GetDeserializedObject(id);
|
||||||
|
|
||||||
|
Type type = deserializedObject.StoredType;
|
||||||
|
|
||||||
|
if (type == null || !type.IsAssignableTo(fieldType))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int count = deserializedObject.GetFieldValue<int>("Count", SerializationType.Int32);
|
||||||
|
|
||||||
|
Array array = null;
|
||||||
|
IList list = null;
|
||||||
|
|
||||||
|
if (type.IsArray)
|
||||||
|
{
|
||||||
|
array = Array.CreateInstance(elementType, count);
|
||||||
|
|
||||||
|
deserializedObject._instance = array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Assert(fieldType.IsAssignableTo(typeof(IList)));
|
||||||
|
|
||||||
|
if (type.GetGenericTypeDefinition() == typeof(List<>))
|
||||||
|
{
|
||||||
|
list = (IList)ActivatorExtension.CreateInstanceSafe(type, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list = (IList)ActivatorExtension.CreateInstanceSafe(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (list.IsFixedSize)
|
||||||
|
{
|
||||||
|
Log.Error("Cannot deserialize fixed length lists.");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializedObject._instance = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
object elementValue = ActivatorExtension.CreateInstanceSafe(elementType);
|
||||||
|
|
||||||
|
object newValue = deserializedObject.DeserializeField(elementValue, elementType, $"{i}");
|
||||||
|
|
||||||
|
if (newValue == NoValueDeserialized)
|
||||||
|
newValue = elementValue;
|
||||||
|
|
||||||
|
if (array != null)
|
||||||
|
array.SetValue(newValue, i);
|
||||||
|
else
|
||||||
|
list.Add(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserializedObject._instance;
|
||||||
|
}
|
||||||
|
|
||||||
private object DeserializeEnum(string fieldName, Type enumType)
|
private object DeserializeEnum(string fieldName, Type enumType)
|
||||||
{
|
{
|
||||||
if (GetFieldValue(fieldName, SerializationType.Enum) is not string valueName)
|
if (GetFieldValue(fieldName, SerializationType.Enum) is not string valueName)
|
||||||
@@ -399,7 +470,17 @@ internal class DeserializationObject
|
|||||||
if (id == UUID.Zero)
|
if (id == UUID.Zero)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
// Get serialization container for the instance
|
||||||
DeserializationObject deserializedObject = GetDeserializedObject(id);
|
DeserializationObject deserializedObject = GetDeserializedObject(id);
|
||||||
|
|
||||||
|
Type type = deserializedObject.StoredType;
|
||||||
|
|
||||||
|
if (type == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
deserializedObject._instance = ActivatorExtension.CreateInstanceSafe(type);
|
||||||
|
|
||||||
|
deserializedObject.DeserializeFields(deserializedObject._instance);
|
||||||
|
|
||||||
return deserializedObject._instance;
|
return deserializedObject._instance;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -12,31 +13,31 @@ internal class SerializedObject
|
|||||||
|
|
||||||
private UUID _id;
|
private UUID _id;
|
||||||
|
|
||||||
|
private Dictionary<object, SerializedObject> _serializedClasses;
|
||||||
|
|
||||||
private Stack<string> _structScope = new();
|
private Stack<string> _structScope = new();
|
||||||
|
|
||||||
private string _structScopeName;
|
private string _structScopeName;
|
||||||
|
|
||||||
public Dictionary<object, SerializedObject> SerializedClasses;
|
|
||||||
|
|
||||||
public SerializedObject(IntPtr internalContext, UUID id, Dictionary<object, SerializedObject> serializedClasses)
|
public SerializedObject(IntPtr internalContext, UUID id, Dictionary<object, SerializedObject> serializedClasses)
|
||||||
{
|
{
|
||||||
_internalContext = internalContext;
|
_internalContext = internalContext;
|
||||||
_id = id;
|
_id = id;
|
||||||
SerializedClasses = serializedClasses;
|
_serializedClasses = serializedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (SerializedObject context, bool newContext) GetSerializedObject(object o)
|
private (SerializedObject context, bool newContext) GetSerializedObject(object o)
|
||||||
{
|
{
|
||||||
SerializedObject context;
|
SerializedObject context;
|
||||||
|
|
||||||
if (SerializedClasses.TryGetValue(o, out context))
|
if (_serializedClasses.TryGetValue(o, out context))
|
||||||
return (context, false);
|
return (context, false);
|
||||||
|
|
||||||
ScriptGlue.Serialization_CreateObject(_internalContext, o.GetType().FullName, out IntPtr contextPtr, out UUID id);
|
ScriptGlue.Serialization_CreateObject(_internalContext, o.GetType().FullName, out IntPtr contextPtr, out UUID id);
|
||||||
|
|
||||||
context = new SerializedObject(contextPtr, id, SerializedClasses);
|
context = new SerializedObject(contextPtr, id, _serializedClasses);
|
||||||
|
|
||||||
SerializedClasses.Add(o, context);
|
_serializedClasses.Add(o, context);
|
||||||
|
|
||||||
return (context, true);
|
return (context, true);
|
||||||
}
|
}
|
||||||
@@ -98,14 +99,20 @@ internal class SerializedObject
|
|||||||
}
|
}
|
||||||
else if (fieldType.IsArray)
|
else if (fieldType.IsArray)
|
||||||
{
|
{
|
||||||
Log.Error($"Array serialization not yet implemented");
|
Array myArray = fieldValue as Array;
|
||||||
|
|
||||||
|
if (myArray?.Rank > 1)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Serializing multidimensional arrays is not yet supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializeList(fieldName, fieldValue, fieldType, fieldType.GetElementType());
|
||||||
}
|
}
|
||||||
else if (fieldType.IsGenericType)
|
else if (fieldType.IsGenericType)
|
||||||
{
|
{
|
||||||
if (fieldType.GetGenericTypeDefinition() == typeof(List<>))
|
if (fieldType.GetGenericTypeDefinition() == typeof(List<>))
|
||||||
{
|
{
|
||||||
//SerializeList(fieldName, type, o);
|
SerializeList(fieldName, fieldValue, fieldType, fieldType.GetGenericArguments()[0]);
|
||||||
Log.Error($"List serialization not yet implemented");
|
|
||||||
}
|
}
|
||||||
//else if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
//else if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||||
//{
|
//{
|
||||||
@@ -131,6 +138,36 @@ internal class SerializedObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SerializeList(string fieldName, object listObject, Type fieldType, Type elementType)
|
||||||
|
{
|
||||||
|
if (listObject == null)
|
||||||
|
{
|
||||||
|
AddField(fieldName, SerializationType.ObjectReference, UUID.Zero);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Assert(listObject is IList);
|
||||||
|
|
||||||
|
var (context, newContext) = GetSerializedObject(listObject);
|
||||||
|
|
||||||
|
if (newContext)
|
||||||
|
{
|
||||||
|
IList list = (IList)listObject;
|
||||||
|
|
||||||
|
context.AddField("Count", SerializationType.Int32, list.Count);
|
||||||
|
|
||||||
|
for (int i = 0; i < list.Count; i++)
|
||||||
|
{
|
||||||
|
object element = list[i];
|
||||||
|
|
||||||
|
context.SerializeField($"{i}", element, element?.GetType() ?? elementType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddField(fieldName, SerializationType.ObjectReference, context._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SerializePrimitive(string fieldName, object fieldValue, Type fieldType)
|
private void SerializePrimitive(string fieldName, object fieldValue, Type fieldType)
|
||||||
{
|
{
|
||||||
Debug.Assert(fieldType.IsPrimitive, $"{fieldType} is not a primitive type.");
|
Debug.Assert(fieldType.IsPrimitive, $"{fieldType} is not a primitive type.");
|
||||||
@@ -214,4 +251,4 @@ internal class SerializedObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user