mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Serialize Data
This commit is contained in:
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Serialization;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
@@ -135,4 +136,14 @@ internal static class ScriptGlue
|
||||
internal static extern bool Application_IsInPlayMode();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Serialization
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Serialization_SerializeField(IntPtr serializationContext, SerializationType type, string name, object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Serialization_CreateObject(IntPtr currentContext, out IntPtr context, out UUID id);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -7,12 +7,251 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Extensions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace GlitchyEngine.Serialization;
|
||||
|
||||
public enum SerializationType : int
|
||||
{
|
||||
None,
|
||||
|
||||
Bool,
|
||||
|
||||
Char,
|
||||
String,
|
||||
|
||||
Int8,
|
||||
Int16,
|
||||
Int32,
|
||||
Int64,
|
||||
UInt8,
|
||||
UInt16,
|
||||
UInt32,
|
||||
UInt64,
|
||||
|
||||
Float,
|
||||
Double,
|
||||
Decimal,
|
||||
|
||||
Enum,
|
||||
|
||||
EntityReference,
|
||||
ComponentReference,
|
||||
|
||||
ObjectReference
|
||||
}
|
||||
|
||||
public static class EntitySerializer
|
||||
{
|
||||
public class SerializedObject
|
||||
{
|
||||
private IntPtr _internalContext;
|
||||
|
||||
private UUID _id;
|
||||
|
||||
private Stack<string> _structScope = new();
|
||||
|
||||
private string _structScopeName;
|
||||
|
||||
public Dictionary<object, SerializedObject> SerializedClasses;
|
||||
|
||||
public SerializedObject(IntPtr internalContext, UUID id, Dictionary<object, SerializedObject> serializedClasses)
|
||||
{
|
||||
_internalContext = internalContext;
|
||||
_id = id;
|
||||
SerializedClasses = serializedClasses;
|
||||
}
|
||||
|
||||
private (SerializedObject context, bool newContext) GetSerializedObject(object o)
|
||||
{
|
||||
SerializedObject context;
|
||||
|
||||
if (SerializedClasses.TryGetValue(o, out context))
|
||||
return (context, false);
|
||||
|
||||
ScriptGlue.Serialization_CreateObject(_internalContext, out IntPtr contextPtr, out UUID id);
|
||||
|
||||
context = new SerializedObject(contextPtr, id, SerializedClasses);
|
||||
|
||||
SerializedClasses.Add(o, context);
|
||||
|
||||
return (context, true);
|
||||
}
|
||||
|
||||
private void PushScope(string name)
|
||||
{
|
||||
_structScope.Push(name);
|
||||
|
||||
_structScopeName += $"{name}.";
|
||||
}
|
||||
|
||||
private void PopScope()
|
||||
{
|
||||
string scopeToRemove = _structScope.Pop();
|
||||
_structScopeName.Remove(_structScopeName.Length - scopeToRemove.Length - 1);
|
||||
}
|
||||
|
||||
private void AddField(string fieldName, SerializationType serializationType, object value)
|
||||
{
|
||||
string completeFieldName = $"{_structScopeName}{fieldName}";
|
||||
|
||||
ScriptGlue.Serialization_SerializeField(_internalContext, serializationType, completeFieldName, value);
|
||||
}
|
||||
|
||||
public void Serialize(Entity entity)
|
||||
{
|
||||
SerializeFields(entity);
|
||||
}
|
||||
|
||||
private void SerializeFields(object obj)
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
|
||||
foreach (FieldInfo field in type.GetFields())
|
||||
{
|
||||
if (!EntitySerializer.SerializeField(field))
|
||||
continue;
|
||||
|
||||
object fieldValue = field.GetValue(obj);
|
||||
Type fieldType = fieldValue?.GetType() ?? field.FieldType;
|
||||
|
||||
SerializeField(field.Name, fieldValue, fieldType);
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeField(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
if (fieldType.IsPrimitive)
|
||||
{
|
||||
SerializePrimitive(fieldName, fieldValue, fieldType);
|
||||
}
|
||||
else if (fieldType == typeof(string))
|
||||
{
|
||||
AddField(fieldName, SerializationType.String, fieldValue.ToString());
|
||||
}
|
||||
else if (fieldType.IsEnum)
|
||||
{
|
||||
SerializeEnum(fieldName, fieldValue, fieldType);
|
||||
}
|
||||
else if (fieldType.IsArray)
|
||||
{
|
||||
Log.Error($"Array serialization not yet implemented");
|
||||
}
|
||||
else if (fieldType.IsGenericType)
|
||||
{
|
||||
if (fieldType.GetGenericTypeDefinition() == typeof(List<>))
|
||||
{
|
||||
//SerializeList(fieldName, type, o);
|
||||
Log.Error($"List serialization not yet implemented");
|
||||
}
|
||||
//else if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
//{
|
||||
// ImGui.Text($"{fieldName} Dictionary");
|
||||
//}
|
||||
else
|
||||
{
|
||||
// TODO: what to do?
|
||||
Log.Error($"Generic class serialization not yet implemented");
|
||||
}
|
||||
}
|
||||
else if (fieldType.IsValueType)
|
||||
{
|
||||
SerializeStruct(fieldName, fieldValue, fieldType);
|
||||
}
|
||||
else if (fieldType.IsClass)
|
||||
{
|
||||
SerializeClass(fieldName, fieldValue, fieldType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializePrimitive(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
Debug.Assert(fieldType.IsPrimitive, $"{fieldType} is not a primitive type.");
|
||||
|
||||
SerializationType type = SerializationType.None;
|
||||
|
||||
if (fieldType == typeof(bool))
|
||||
type = SerializationType.Bool;
|
||||
else if (fieldType == typeof(char))
|
||||
type = SerializationType.Char;
|
||||
else if (fieldType == typeof(byte))
|
||||
type = SerializationType.UInt8;
|
||||
else if (fieldType == typeof(sbyte))
|
||||
type = SerializationType.Int8;
|
||||
else if (fieldType == typeof(ushort))
|
||||
type = SerializationType.UInt16;
|
||||
else if (fieldType == typeof(short))
|
||||
type = SerializationType.Int16;
|
||||
else if (fieldType == typeof(uint))
|
||||
type = SerializationType.UInt32;
|
||||
else if (fieldType == typeof(int))
|
||||
type = SerializationType.Int32;
|
||||
else if (fieldType == typeof(ulong))
|
||||
type = SerializationType.UInt64;
|
||||
else if (fieldType == typeof(long))
|
||||
type = SerializationType.Int64;
|
||||
else if (fieldType == typeof(float))
|
||||
type = SerializationType.Float;
|
||||
else if (fieldType == typeof(double))
|
||||
type = SerializationType.Double;
|
||||
else if (fieldType == typeof(decimal))
|
||||
type = SerializationType.Decimal;
|
||||
else
|
||||
{
|
||||
Log.Error($"The primitive {fieldType} is not implemented.");
|
||||
}
|
||||
|
||||
AddField(fieldName, type, fieldValue);
|
||||
}
|
||||
|
||||
private void SerializeEnum(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
AddField(fieldName, SerializationType.Enum, fieldValue.ToString());
|
||||
}
|
||||
|
||||
private void SerializeStruct(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
PushScope(fieldName);
|
||||
|
||||
SerializeFields(fieldValue);
|
||||
|
||||
PopScope();
|
||||
}
|
||||
|
||||
private void SerializeClass(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
if (typeof(Entity).IsAssignableFrom(fieldType))
|
||||
{
|
||||
AddField(fieldName, SerializationType.EntityReference, ((Entity)fieldValue)?.UUID ?? UUID.Zero);
|
||||
}
|
||||
else if (typeof(Component).IsAssignableFrom(fieldType))
|
||||
{
|
||||
AddField(fieldName, SerializationType.ComponentReference, ((Component)fieldValue)?.UUID ?? UUID.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fieldValue == null)
|
||||
{
|
||||
AddField(fieldName, SerializationType.ObjectReference, UUID.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
var (context, newContext) = GetSerializedObject(fieldValue);
|
||||
|
||||
if (newContext)
|
||||
{
|
||||
context.SerializeFields(fieldValue);
|
||||
}
|
||||
|
||||
AddField(fieldName, SerializationType.ObjectReference, context._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializationContext
|
||||
{
|
||||
StringBuilder _builder = new();
|
||||
@@ -257,11 +496,17 @@ public static class EntitySerializer
|
||||
}
|
||||
}
|
||||
|
||||
public static void Serialize(Entity entity, SerializationContext context)
|
||||
{
|
||||
context ??= new SerializationContext();
|
||||
//public static void Serialize(Entity entity, SerializationContext context)
|
||||
//{
|
||||
// context ??= new SerializationContext();
|
||||
|
||||
context.Serialize($"Entity: {entity.UUID}", typeof(Entity), entity, false);
|
||||
// context.Serialize($"Entity: {entity.UUID}", typeof(Entity), entity, false);
|
||||
//}
|
||||
|
||||
public static void Serialize(Entity entity, IntPtr internalContext)
|
||||
{
|
||||
SerializedObject obj = new SerializedObject(internalContext, UUID.Zero, new Dictionary<object, SerializedObject>());
|
||||
obj.Serialize(entity);
|
||||
}
|
||||
|
||||
public static bool SerializeField(FieldInfo fieldInfo)
|
||||
|
||||
Reference in New Issue
Block a user