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)
|
||||
{
|
||||
SerializedObject object = new SerializedObject(allObjects, script.EntityId);
|
||||
SerializedObject object = new SerializedObject(allObjects, script.ScriptClass.FullName, script.EntityId);
|
||||
object.Serialize(script);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,13 +550,17 @@ static class ScriptGlue
|
||||
}
|
||||
|
||||
[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;
|
||||
|
||||
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);
|
||||
newId = newObject.Id;
|
||||
@@ -576,6 +580,31 @@ static class ScriptGlue
|
||||
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
|
||||
|
||||
private static void RegisterCall<T>(String name, T method) where T : var
|
||||
|
||||
@@ -70,16 +70,24 @@ public enum SerializationType : int32
|
||||
|
||||
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 String TypeName ~ delete:append _;
|
||||
|
||||
public Dictionary<UUID, SerializedObject> AllObjects;
|
||||
|
||||
private List<String> _ownedString = new List<String>() ~ DeleteContainerAndItems!(_);
|
||||
|
||||
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;
|
||||
|
||||
if (id == null)
|
||||
@@ -97,6 +105,8 @@ class SerializedObject
|
||||
}
|
||||
|
||||
AllObjects.Add(Id, this);
|
||||
|
||||
TypeName = typeNameCopy;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
[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)]
|
||||
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
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -70,7 +71,7 @@ public static class EntitySerializer
|
||||
if (SerializedClasses.TryGetValue(o, out context))
|
||||
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);
|
||||
|
||||
@@ -264,29 +265,72 @@ public static class EntitySerializer
|
||||
|
||||
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;
|
||||
_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))
|
||||
return (context, false);
|
||||
if (type != null)
|
||||
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)
|
||||
@@ -377,6 +421,8 @@ public static class EntitySerializer
|
||||
|
||||
public void Deserialize(Entity entity)
|
||||
{
|
||||
_instance = entity;
|
||||
|
||||
DeserializeFields(entity);
|
||||
}
|
||||
|
||||
@@ -401,25 +447,15 @@ public static class EntitySerializer
|
||||
{
|
||||
Type fieldType = field.FieldType;
|
||||
|
||||
object newFieldValue = null;
|
||||
|
||||
if (fieldType.IsPrimitive)
|
||||
{
|
||||
object value = DeserializePrimitive(field.Name, fieldType);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
field.SetValue(targetInstance, value);
|
||||
return true;
|
||||
}
|
||||
newFieldValue = DeserializePrimitive(field.Name, fieldType);
|
||||
}
|
||||
else if (fieldType == typeof(string))
|
||||
{
|
||||
object value = GetFieldValue(field.Name, SerializationType.String);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
field.SetValue(targetInstance, value);
|
||||
return true;
|
||||
}
|
||||
newFieldValue = GetFieldValue(field.Name, SerializationType.String);
|
||||
}
|
||||
else if (fieldType.IsEnum)
|
||||
{
|
||||
@@ -450,24 +486,23 @@ public static class EntitySerializer
|
||||
{
|
||||
object structValue = field.GetValue(targetInstance);
|
||||
|
||||
bool changed = DeserializeStruct(field.Name, structValue);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
field.SetValue(targetInstance, structValue);
|
||||
return true;
|
||||
}
|
||||
newFieldValue = DeserializeStruct(field.Name, structValue);
|
||||
}
|
||||
else if (fieldType.IsClass)
|
||||
{
|
||||
//DeserializeClass(fieldName, fieldValue, fieldType);
|
||||
Log.Error("Class is not yet implemented.");
|
||||
newFieldValue = DeserializeClass(field.Name, fieldType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Encountered unhandled type \"{fieldType}\" while serializing.");
|
||||
}
|
||||
|
||||
if (newFieldValue != null)
|
||||
{
|
||||
field.SetValue(targetInstance, newFieldValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -511,12 +546,12 @@ public static class EntitySerializer
|
||||
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());
|
||||
}
|
||||
|
||||
private bool DeserializeStruct(string fieldName, object targetInstance)
|
||||
private object DeserializeStruct(string fieldName, object targetInstance)
|
||||
{
|
||||
PushScope(fieldName);
|
||||
|
||||
@@ -524,37 +559,53 @@ public static class EntitySerializer
|
||||
|
||||
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))
|
||||
//{
|
||||
// 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 (typeof(Entity).IsAssignableFrom(fieldType))
|
||||
{
|
||||
UUID id = (UUID)GetFieldValue(fieldName, SerializationType.EntityReference);
|
||||
|
||||
// if (newContext)
|
||||
// {
|
||||
// context.SerializeFields(fieldValue);
|
||||
// }
|
||||
if (id == UUID.Zero)
|
||||
return null;
|
||||
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user