Serialization: Support sharing object references

This commit is contained in:
Simon Lübeß
2024-04-13 00:50:09 +02:00
parent 949ab4ebb0
commit a3de5ddc9c
5 changed files with 142 additions and 36 deletions
@@ -9,10 +9,18 @@ using internal GlitchyEngine.Scripting;
class EntitySerializerWrapper : ScriptClass
{
function MonoObject* SerializeMethod(MonoObject* entity, void* contextPtr, MonoException** exception);
function MonoObject* DeserializeMethod(MonoObject* entity, void* contextPtr, MonoException** exception);
function MonoObject* SerializeStaticMethod(MonoReflectionType* type, void* contextPtr, MonoException** exception);
function MonoObject* DeserializeStaticMethod(MonoReflectionType* type, void* contextPtr, MonoException** exception);
function void CreateSerializationContextMethod(void* serializerPtr, MonoException** exception);
function void ClearSerializationContextMethod(void* serializerPtr, MonoException** exception);
function void DestroySerializationContextMethod(void* serializerPtr, MonoException** exception);
function void SerializeMethod(MonoObject* entity, void* serializedObjPtr, void* serializerPtr, MonoException** exception);
function void DeserializeMethod(MonoObject* entity, void* serializedObjPtr, void* serializerPtr, MonoException** exception);
function void SerializeStaticMethod(MonoReflectionType* type, void* serializedObjPtr, void* serializerPtr, MonoException** exception);
function void DeserializeStaticMethod(MonoReflectionType* type, void* serializedObjPtr, void* serializerPtr, MonoException** exception);
private CreateSerializationContextMethod _createSerializationContextMethod;
private ClearSerializationContextMethod _clearSerializationContextMethod;
private DestroySerializationContextMethod _destroySerializationContextMethod;
private SerializeMethod _serializeMethod;
private DeserializeMethod _deserializeMethod;
@@ -22,82 +30,138 @@ class EntitySerializerWrapper : ScriptClass
[AllowAppend]
public this(StringView classNamespace, StringView className, MonoImage* image) : base(classNamespace, className, image)
{
_serializeMethod = (SerializeMethod)GetMethodThunk("Serialize", 2);
_serializeMethod = (SerializeMethod)GetMethodThunk("Serialize", 3);
if (_serializeMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"Serialize\" method.");
}
_deserializeMethod = (DeserializeMethod)GetMethodThunk("Deserialize", 2);
_deserializeMethod = (DeserializeMethod)GetMethodThunk("Deserialize", 3);
if (_serializeMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"Deserialize\" method.");
}
_serializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("SerializeStaticFields", 2);
_serializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("SerializeStaticFields", 3);
if (_serializeStaticMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"SerializeStaticStatic\" method.");
}
_deserializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("DeserializeStaticFields", 2);
_deserializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("DeserializeStaticFields", 3);
if (_deserializeStaticMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"DeserializeStaticStatic\" method.");
}
_createSerializationContextMethod = (CreateSerializationContextMethod)GetMethodThunk("CreateSerializationContext", 1);
if (_createSerializationContextMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"CreateSerializationContext\" method.");
}
_clearSerializationContextMethod = (ClearSerializationContextMethod)GetMethodThunk("ClearSerializationContext", 1);
if (_clearSerializationContextMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"ClearSerializationContext\" method.");
}
_destroySerializationContextMethod = (DestroySerializationContextMethod)GetMethodThunk("DestroySerializationContext", 1);
if (_destroySerializationContextMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"DestroySerializationContext\" method.");
}
}
public void Serialize(ScriptInstance instance, SerializedObject context)
public void CreateSerializationContext(ScriptInstanceSerializer serializer)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
void* serializerPtr = Internal.UnsafeCastToPtr(serializer);
MonoException* exception = null;
_serializeMethod(instance.[Friend]_instance, thisPtr, &exception);
_createSerializationContextMethod(serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, instance);
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
public void SerializeStatic(ScriptClass @class, SerializedObject context)
public void ClearSerializationContext(ScriptInstanceSerializer serializer)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
void* serializerPtr = Internal.UnsafeCastToPtr(serializer);
MonoException* exception = null;
MonoType* type = Mono.mono_class_get_type(@class.[Friend]_monoClass);
MonoReflectionType* reflectionType = Mono.mono_type_get_object(ScriptEngine.[Friend]s_AppDomain, type);
_serializeStaticMethod(reflectionType, thisPtr, &exception);
_clearSerializationContextMethod(serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
public void Deserialize(ScriptInstance instance, SerializedObject context)
public void DestroySerializationContext(ScriptInstanceSerializer serializer)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
void* serializerPtr = Internal.UnsafeCastToPtr(serializer);
MonoException* exception = null;
_deserializeMethod(instance.[Friend]_instance, thisPtr, &exception);
_destroySerializationContextMethod(serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
public void Serialize(ScriptInstance instance, SerializedObject serializedObject)
{
void* serializedObjectPtr = Internal.UnsafeCastToPtr(serializedObject);
void* serializerPtr = Internal.UnsafeCastToPtr(serializedObject.Serializer);
MonoException* exception = null;
_serializeMethod(instance.[Friend]_instance, serializedObjectPtr, serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, instance);
}
public void DeserializeStatic(ScriptClass @class, SerializedObject context)
public void SerializeStatic(ScriptClass @class, SerializedObject serializedObject)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
void* serializedObjectPtr = Internal.UnsafeCastToPtr(serializedObject);
void* serializerPtr = Internal.UnsafeCastToPtr(serializedObject.Serializer);
MonoType* type = Mono.mono_class_get_type(@class.[Friend]_monoClass);
MonoReflectionType* reflectionType = Mono.mono_type_get_object(ScriptEngine.[Friend]s_AppDomain, type);
MonoException* exception = null;
_serializeStaticMethod(reflectionType, serializedObjectPtr, serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
public void Deserialize(ScriptInstance instance, SerializedObject serializedObject)
{
void* serializedObjectPtr = Internal.UnsafeCastToPtr(serializedObject);
void* serializerPtr = Internal.UnsafeCastToPtr(serializedObject.Serializer);
MonoException* exception = null;
_deserializeMethod(instance.[Friend]_instance, serializedObjectPtr, serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, instance);
}
public void DeserializeStatic(ScriptClass @class, SerializedObject serializedObject)
{
void* serializedObjectPtr = Internal.UnsafeCastToPtr(serializedObject);
void* serializerPtr = Internal.UnsafeCastToPtr(serializedObject.Serializer);
MonoType* type = Mono.mono_class_get_type(@class.[Friend]_monoClass);
MonoReflectionType* reflectionType = Mono.mono_type_get_object(ScriptEngine.[Friend]s_AppDomain, type);
_deserializeStaticMethod(reflectionType, thisPtr, &exception);
MonoException* exception = null;
_deserializeStaticMethod(reflectionType, serializedObjectPtr, serializerPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
@@ -24,6 +24,12 @@ public class ScriptInstanceSerializer
public void Clear()
{
ClearDictionaryAndDeleteValues!(_serializedData);
ScriptEngine.Classes.EntitySerializer.DestroySerializationContext(this);
}
public void Init()
{
ScriptEngine.Classes.EntitySerializer.CreateSerializationContext(this);
}
/// Serializes all script instances that are currently managed by the ScriptEngine.
@@ -31,6 +37,8 @@ public class ScriptInstanceSerializer
{
Debug.Profiler.ProfileFunction!();
Init();
for (let (id, scriptInstance) in ScriptEngine._entityScriptInstances)
{
SerializeScriptInstance(scriptInstance);
@@ -61,6 +69,8 @@ public class ScriptInstanceSerializer
{
Debug.Profiler.ProfileFunction!();
Init();
for (let (id, script) in ScriptEngine._entityScriptInstances)
{
DeserializeScriptInstance(id, script);
+2 -2
View File
@@ -123,6 +123,7 @@ namespace GlitchyEngine.World
});
_font = new Font(@"C:\Windows\Fonts\arial.ttf", 24);
//_font = new Font(@"C:\Windows\Fonts\Cascadia Code.ttf", 24);
}
public ~this()
@@ -958,9 +959,8 @@ namespace GlitchyEngine.World
*/
public Entity CreateInstance(Entity entity)
{
//Dictionary<UUID, SerializedObject> serializedData = scope .();
ScriptInstanceSerializer scriptSerializer = scope .();
//defer { ClearDictionaryAndDeleteValues!(serializedData); }
scriptSerializer.Init();
List<Entity> newEntities = scope .();
Dictionary<EcsEntity, EcsEntity> sourceToTargetEntity = scope .();
@@ -603,6 +603,11 @@ public class DeserializationObject
if (type == null)
return NoValueDeserialized;
if (deserializedObject._instance != null)
{
return deserializedObject._instance;
}
deserializedObject._instance = ActivatorExtension.CreateInstanceSafe(type);
if (deserializedObject._instance == null)
+35 -8
View File
@@ -9,27 +9,54 @@ namespace GlitchyEngine.Serialization;
internal static class EntitySerializer
{
internal static void Serialize(Entity entity, IntPtr internalContext)
private static Dictionary<IntPtr, Dictionary<object, SerializedObject>> SerializationObjects = new();
private static Dictionary<IntPtr, Dictionary<UUID, DeserializationObject>> DeserializationObjects = new();
internal static void CreateSerializationContext(IntPtr engineSerializer)
{
SerializedObject obj = new SerializedObject(internalContext, false, UUID.Zero, new Dictionary<object, SerializedObject>());
if (SerializationObjects.ContainsKey(engineSerializer))
{
ClearSerializationContext(engineSerializer);
return;
}
SerializationObjects.Add(engineSerializer, new Dictionary<object, SerializedObject>());
DeserializationObjects.Add(engineSerializer, new Dictionary<UUID, DeserializationObject>());
}
internal static void ClearSerializationContext(IntPtr engineSerializer)
{
SerializationObjects[engineSerializer].Clear();
DeserializationObjects[engineSerializer].Clear();
}
internal static void DestroySerializationContext(IntPtr engineSerializer)
{
SerializationObjects.Remove(engineSerializer);
DeserializationObjects.Remove(engineSerializer);
}
internal static void Serialize(Entity entity, IntPtr engineObject, IntPtr engineSerializer)
{
SerializedObject obj = new SerializedObject(engineObject, false, UUID.Zero, SerializationObjects[engineSerializer]);
obj.Serialize(entity);
}
internal static void Deserialize(Entity entity, IntPtr internalContext)
internal static void Deserialize(Entity entity, IntPtr engineObject, IntPtr engineSerializer)
{
DeserializationObject obj = new DeserializationObject(internalContext, false, UUID.Zero, new Dictionary<UUID, DeserializationObject>());
DeserializationObject obj = new DeserializationObject(engineObject, false, UUID.Zero, DeserializationObjects[engineSerializer]);
obj.Deserialize(entity);
}
internal static void SerializeStaticFields(Type type, IntPtr internalContext)
internal static void SerializeStaticFields(Type type, IntPtr engineObject, IntPtr engineSerializer)
{
SerializedObject obj = new SerializedObject(internalContext, true, UUID.Zero, new Dictionary<object, SerializedObject>());
SerializedObject obj = new SerializedObject(engineObject, true, UUID.Zero, SerializationObjects[engineSerializer]);
obj.Serialize(type);
}
internal static void DeserializeStaticFields(Type type, IntPtr internalContext)
internal static void DeserializeStaticFields(Type type, IntPtr engineObject, IntPtr engineSerializer)
{
DeserializationObject obj = new DeserializationObject(internalContext, true, UUID.Zero, new Dictionary<UUID, DeserializationObject>());
DeserializationObject obj = new DeserializationObject(engineObject, true, UUID.Zero, DeserializationObjects[engineSerializer]);
obj.Deserialize(type);
}