mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Serialize/Deserialize simple classes
This commit is contained in:
@@ -857,7 +857,7 @@ static class ScriptEngine
|
|||||||
|
|
||||||
for (let (id, script) in _entityScriptInstances)
|
for (let (id, script) in _entityScriptInstances)
|
||||||
{
|
{
|
||||||
SerializedObject object = new SerializedObject(allObjects, script.EntityId);
|
SerializedObject object = new SerializedObject(allObjects, script.ScriptClass.FullName, script.EntityId);
|
||||||
object.Serialize(script);
|
object.Serialize(script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -550,13 +550,17 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Serialization_CreateObject")]
|
[RegisterCall("ScriptGlue::Serialization_CreateObject")]
|
||||||
static void Serialization_CreateObject(void* currentContext, out void* newContext, out UUID newId)
|
static void Serialization_CreateObject(void* currentContext, MonoString* typeName, out void* newContext, out UUID newId)
|
||||||
{
|
{
|
||||||
SerializedObject context = Internal.UnsafeCastToObject(currentContext) as SerializedObject;
|
SerializedObject context = Internal.UnsafeCastToObject(currentContext) as SerializedObject;
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(context != null);
|
Log.EngineLogger.AssertDebug(context != null);
|
||||||
|
|
||||||
SerializedObject newObject = new SerializedObject(context.AllObjects);
|
char8* rawTypeName = Mono.mono_string_to_utf8(typeName);
|
||||||
|
|
||||||
|
SerializedObject newObject = new SerializedObject(context.AllObjects, StringView(rawTypeName));
|
||||||
|
|
||||||
|
Mono.mono_free(rawTypeName);
|
||||||
|
|
||||||
newContext = Internal.UnsafeCastToPtr(newObject);
|
newContext = Internal.UnsafeCastToPtr(newObject);
|
||||||
newId = newObject.Id;
|
newId = newObject.Id;
|
||||||
@@ -576,6 +580,31 @@ static class ScriptGlue
|
|||||||
Mono.mono_free(name);
|
Mono.mono_free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RegisterCall("ScriptGlue::Serialization_GetObject")]
|
||||||
|
public static void Serialization_GetObject(void* internalContext, UUID id, out void* objectContext)
|
||||||
|
{
|
||||||
|
SerializedObject context = Internal.UnsafeCastToObject(internalContext) as SerializedObject;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(context != null);
|
||||||
|
|
||||||
|
objectContext = null;
|
||||||
|
|
||||||
|
if (!context.AllObjects.TryGetValue(id, let foundObject))
|
||||||
|
return;
|
||||||
|
|
||||||
|
objectContext = Internal.UnsafeCastToPtr(foundObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RegisterCall("ScriptGlue::Serialization_GetObjectTypeName")]
|
||||||
|
public static void Serialization_GetObjectTypeName(void* internalContext, out MonoString* fullTypeName)
|
||||||
|
{
|
||||||
|
SerializedObject context = Internal.UnsafeCastToObject(internalContext) as SerializedObject;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(context != null);
|
||||||
|
|
||||||
|
fullTypeName = Mono.mono_string_new(ScriptEngine.[Friend]s_AppDomain, context.TypeName);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private static void RegisterCall<T>(String name, T method) where T : var
|
private static void RegisterCall<T>(String name, T method) where T : var
|
||||||
|
|||||||
@@ -70,16 +70,24 @@ public enum SerializationType : int32
|
|||||||
|
|
||||||
class SerializedObject
|
class SerializedObject
|
||||||
{
|
{
|
||||||
|
/// ID used to identify the object represented by this SerializedObject. In case that the represented object is a
|
||||||
|
/// Script Instance, the ID is the UUID of the Entity, random otherwise.
|
||||||
|
/// Todo: This sucks because we don't know all UUIDs beforehand and might accidentally assign the ID of an Entity to some class
|
||||||
public UUID Id;
|
public UUID Id;
|
||||||
|
|
||||||
|
public String TypeName ~ delete:append _;
|
||||||
|
|
||||||
public Dictionary<UUID, SerializedObject> AllObjects;
|
public Dictionary<UUID, SerializedObject> AllObjects;
|
||||||
|
|
||||||
private List<String> _ownedString = new List<String>() ~ DeleteContainerAndItems!(_);
|
private List<String> _ownedString = new List<String>() ~ DeleteContainerAndItems!(_);
|
||||||
|
|
||||||
public append Dictionary<StringView, (SerializationType PrimitiveType, uint8[16] Data)> Fields = .();
|
public append Dictionary<StringView, (SerializationType PrimitiveType, uint8[16] Data)> Fields = .();
|
||||||
|
|
||||||
public this(Dictionary<UUID, SerializedObject> allObjects, UUID? id = null)
|
[AllowAppend]
|
||||||
|
public this(Dictionary<UUID, SerializedObject> allObjects, StringView? typeName, UUID? id = null)
|
||||||
{
|
{
|
||||||
|
String typeNameCopy = append String(typeName.Value);
|
||||||
|
|
||||||
AllObjects = allObjects;
|
AllObjects = allObjects;
|
||||||
|
|
||||||
if (id == null)
|
if (id == null)
|
||||||
@@ -97,6 +105,8 @@ class SerializedObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
AllObjects.Add(Id, this);
|
AllObjects.Add(Id, this);
|
||||||
|
|
||||||
|
TypeName = typeNameCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddField(StringView name, SerializationType primitiveType, MonoObject* value)
|
public void AddField(StringView name, SerializationType primitiveType, MonoObject* value)
|
||||||
|
|||||||
@@ -143,10 +143,16 @@ internal static class ScriptGlue
|
|||||||
internal static extern void Serialization_SerializeField(IntPtr serializationContext, SerializationType type, string name, object value);
|
internal static extern void Serialization_SerializeField(IntPtr serializationContext, SerializationType type, string name, object value);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal static extern void Serialization_CreateObject(IntPtr currentContext, out IntPtr context, out UUID id);
|
internal static extern void Serialization_CreateObject(IntPtr currentContext, string fullTypeName, out IntPtr context, out UUID id);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
public static extern unsafe void Serialization_DeserializeField(IntPtr internalContext, SerializationType expectedType, string fieldName, byte* value);
|
public static extern unsafe void Serialization_DeserializeField(IntPtr internalContext, SerializationType expectedType, string fieldName, byte* value);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
public static extern void Serialization_GetObject(IntPtr internalContext, UUID id, out IntPtr objectContext);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
public static extern void Serialization_GetObjectTypeName(IntPtr internalContext, out string fullTypeName);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -70,7 +71,7 @@ public static class EntitySerializer
|
|||||||
if (SerializedClasses.TryGetValue(o, out context))
|
if (SerializedClasses.TryGetValue(o, out context))
|
||||||
return (context, false);
|
return (context, false);
|
||||||
|
|
||||||
ScriptGlue.Serialization_CreateObject(_internalContext, 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);
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ public static class EntitySerializer
|
|||||||
}
|
}
|
||||||
else if (typeof(Component).IsAssignableFrom(fieldType))
|
else if (typeof(Component).IsAssignableFrom(fieldType))
|
||||||
{
|
{
|
||||||
AddField(fieldName, SerializationType.ComponentReference, ((Component)fieldValue)?.UUID ?? UUID.Zero);
|
AddField(fieldName, SerializationType.ComponentReference, ((Component)fieldValue)?.UUID ?? UUID.Zero);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -264,29 +265,72 @@ public static class EntitySerializer
|
|||||||
|
|
||||||
private string _structScopeName;
|
private string _structScopeName;
|
||||||
|
|
||||||
public Dictionary<object, SerializedObject> SerializedClasses;
|
public Dictionary<UUID, DeserializationObject> DeserializedClasses;
|
||||||
|
|
||||||
public DeserializationObject(IntPtr internalContext, UUID id, Dictionary<object, SerializedObject> serializedClasses)
|
private object _instance;
|
||||||
|
|
||||||
|
public DeserializationObject(IntPtr internalContext, UUID id, Dictionary<UUID, DeserializationObject> deserializedClasses)
|
||||||
{
|
{
|
||||||
_internalContext = internalContext;
|
_internalContext = internalContext;
|
||||||
_id = id;
|
_id = id;
|
||||||
SerializedClasses = serializedClasses;
|
DeserializedClasses = deserializedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (SerializedObject context, bool newContext) GetSerializedObject(object o)
|
private Dictionary<string, Type> _fullNameToType = new();
|
||||||
|
|
||||||
|
private Type FindType(string fullName)
|
||||||
{
|
{
|
||||||
SerializedObject context;
|
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().Reverse())
|
||||||
|
{
|
||||||
|
Type type = assembly.GetType(fullName);
|
||||||
|
|
||||||
if (SerializedClasses.TryGetValue(o, out context))
|
if (type != null)
|
||||||
return (context, false);
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
ScriptGlue.Serialization_CreateObject(_internalContext, out IntPtr contextPtr, out UUID id);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
context = new SerializedObject(contextPtr, id, SerializedClasses);
|
private Type GetTypeFromName(string fullName)
|
||||||
|
{
|
||||||
|
if (_fullNameToType.TryGetValue(fullName, out Type storedType))
|
||||||
|
return storedType;
|
||||||
|
|
||||||
SerializedClasses.Add(o, context);
|
Type type = FindType(fullName);
|
||||||
|
|
||||||
return (context, true);
|
_fullNameToType.Add(fullName, type);
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeserializationObject GetDeserializedObject(UUID id)
|
||||||
|
{
|
||||||
|
DeserializationObject context;
|
||||||
|
|
||||||
|
if (DeserializedClasses.TryGetValue(id, out context))
|
||||||
|
return context;
|
||||||
|
|
||||||
|
ScriptGlue.Serialization_GetObject(_internalContext, id, out IntPtr contextPtr);
|
||||||
|
|
||||||
|
context = new DeserializationObject(contextPtr, id, DeserializedClasses);
|
||||||
|
|
||||||
|
DeserializedClasses.Add(id, context);
|
||||||
|
|
||||||
|
ScriptGlue.Serialization_GetObjectTypeName(context._internalContext, out string fullTypeName);
|
||||||
|
|
||||||
|
Type type = GetTypeFromName(fullTypeName);
|
||||||
|
|
||||||
|
if (type == null)
|
||||||
|
return context;
|
||||||
|
|
||||||
|
context._instance = Activator.CreateInstance(type);
|
||||||
|
|
||||||
|
if (context._instance == null)
|
||||||
|
return context;
|
||||||
|
|
||||||
|
context.DeserializeFields(context._instance);
|
||||||
|
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PushScope(string name)
|
private void PushScope(string name)
|
||||||
@@ -377,6 +421,8 @@ public static class EntitySerializer
|
|||||||
|
|
||||||
public void Deserialize(Entity entity)
|
public void Deserialize(Entity entity)
|
||||||
{
|
{
|
||||||
|
_instance = entity;
|
||||||
|
|
||||||
DeserializeFields(entity);
|
DeserializeFields(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,25 +447,15 @@ public static class EntitySerializer
|
|||||||
{
|
{
|
||||||
Type fieldType = field.FieldType;
|
Type fieldType = field.FieldType;
|
||||||
|
|
||||||
|
object newFieldValue = null;
|
||||||
|
|
||||||
if (fieldType.IsPrimitive)
|
if (fieldType.IsPrimitive)
|
||||||
{
|
{
|
||||||
object value = DeserializePrimitive(field.Name, fieldType);
|
newFieldValue = DeserializePrimitive(field.Name, fieldType);
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
field.SetValue(targetInstance, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (fieldType == typeof(string))
|
else if (fieldType == typeof(string))
|
||||||
{
|
{
|
||||||
object value = GetFieldValue(field.Name, SerializationType.String);
|
newFieldValue = GetFieldValue(field.Name, SerializationType.String);
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
field.SetValue(targetInstance, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (fieldType.IsEnum)
|
else if (fieldType.IsEnum)
|
||||||
{
|
{
|
||||||
@@ -450,24 +486,23 @@ public static class EntitySerializer
|
|||||||
{
|
{
|
||||||
object structValue = field.GetValue(targetInstance);
|
object structValue = field.GetValue(targetInstance);
|
||||||
|
|
||||||
bool changed = DeserializeStruct(field.Name, structValue);
|
newFieldValue = DeserializeStruct(field.Name, structValue);
|
||||||
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
field.SetValue(targetInstance, structValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (fieldType.IsClass)
|
else if (fieldType.IsClass)
|
||||||
{
|
{
|
||||||
//DeserializeClass(fieldName, fieldValue, fieldType);
|
newFieldValue = DeserializeClass(field.Name, fieldType);
|
||||||
Log.Error("Class is not yet implemented.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newFieldValue != null)
|
||||||
|
{
|
||||||
|
field.SetValue(targetInstance, newFieldValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,12 +546,12 @@ public static class EntitySerializer
|
|||||||
return GetFieldValue(fieldName, expectedType);
|
return GetFieldValue(fieldName, expectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SerializeEnum(string fieldName, object fieldValue, Type fieldType)
|
private void DeserializeEnum(string fieldName, object fieldValue, Type fieldType)
|
||||||
{
|
{
|
||||||
//AddField(fieldName, SerializationType.Enum, fieldValue.ToString());
|
//AddField(fieldName, SerializationType.Enum, fieldValue.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeserializeStruct(string fieldName, object targetInstance)
|
private object DeserializeStruct(string fieldName, object targetInstance)
|
||||||
{
|
{
|
||||||
PushScope(fieldName);
|
PushScope(fieldName);
|
||||||
|
|
||||||
@@ -524,37 +559,53 @@ public static class EntitySerializer
|
|||||||
|
|
||||||
PopScope();
|
PopScope();
|
||||||
|
|
||||||
return changed;
|
return changed ? targetInstance : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SerializeClass(string fieldName, object fieldValue, Type fieldType)
|
private object DeserializeClass(string fieldName, Type fieldType)
|
||||||
{
|
{
|
||||||
//if (typeof(Entity).IsAssignableFrom(fieldType))
|
if (typeof(Entity).IsAssignableFrom(fieldType))
|
||||||
//{
|
{
|
||||||
// AddField(fieldName, SerializationType.EntityReference, ((Entity)fieldValue)?.UUID ?? UUID.Zero);
|
UUID id = (UUID)GetFieldValue(fieldName, SerializationType.EntityReference);
|
||||||
//}
|
|
||||||
//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)
|
if (id == UUID.Zero)
|
||||||
// {
|
return null;
|
||||||
// context.SerializeFields(fieldValue);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// AddField(fieldName, SerializationType.ObjectReference, context._id);
|
Entity reference = new Entity(id);
|
||||||
// }
|
|
||||||
//}
|
if (fieldType.IsSubclassOf(typeof(Entity)))
|
||||||
|
return reference.As<Entity>();
|
||||||
|
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
else if (typeof(Component).IsAssignableFrom(fieldType))
|
||||||
|
{
|
||||||
|
UUID id = (UUID)GetFieldValue(fieldName, SerializationType.ComponentReference);
|
||||||
|
|
||||||
|
if (id == UUID.Zero)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// TODO: Get class
|
||||||
|
|
||||||
|
//Entity reference = new Entity(id);
|
||||||
|
|
||||||
|
//if (fieldType.IsSubclassOf(typeof(Entity)))
|
||||||
|
// return reference.As<Entity>();
|
||||||
|
|
||||||
|
//return reference;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UUID id = (UUID)GetFieldValue(fieldName, SerializationType.ObjectReference);
|
||||||
|
|
||||||
|
if (id == UUID.Zero)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
DeserializationObject deserializedObject = GetDeserializedObject(id);
|
||||||
|
|
||||||
|
return deserializedObject._instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +618,7 @@ public static class EntitySerializer
|
|||||||
|
|
||||||
public static void Deserialize(Entity entity, IntPtr internalContext)
|
public static void Deserialize(Entity entity, IntPtr internalContext)
|
||||||
{
|
{
|
||||||
DeserializationObject obj = new DeserializationObject(internalContext, UUID.Zero, new Dictionary<object, SerializedObject>());
|
DeserializationObject obj = new DeserializationObject(internalContext, UUID.Zero, new Dictionary<UUID, DeserializationObject>());
|
||||||
obj.Deserialize(entity);
|
obj.Deserialize(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user