ScriptEngine: Serialize static fields

This commit is contained in:
Simon Lübeß
2024-04-13 00:10:35 +02:00
parent df13aa8596
commit 949ab4ebb0
16 changed files with 504 additions and 244 deletions
@@ -0,0 +1,105 @@
using System;
using Mono;
using GlitchyEngine.Core;
using GlitchyEngine.Serialization;
namespace GlitchyEngine.Scripting;
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);
private SerializeMethod _serializeMethod;
private DeserializeMethod _deserializeMethod;
private SerializeStaticMethod _serializeStaticMethod;
private DeserializeStaticMethod _deserializeStaticMethod;
[AllowAppend]
public this(StringView classNamespace, StringView className, MonoImage* image) : base(classNamespace, className, image)
{
_serializeMethod = (SerializeMethod)GetMethodThunk("Serialize", 2);
if (_serializeMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"Serialize\" method.");
}
_deserializeMethod = (DeserializeMethod)GetMethodThunk("Deserialize", 2);
if (_serializeMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"Deserialize\" method.");
}
_serializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("SerializeStaticFields", 2);
if (_serializeStaticMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"SerializeStaticStatic\" method.");
}
_deserializeStaticMethod = (SerializeStaticMethod)GetMethodThunk("DeserializeStaticFields", 2);
if (_deserializeStaticMethod == null)
{
Log.EngineLogger.Error("EntitySerializer has no \"DeserializeStaticStatic\" method.");
}
}
public void Serialize(ScriptInstance instance, SerializedObject context)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
MonoException* exception = null;
_serializeMethod(instance.[Friend]_instance, thisPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, instance);
}
public void SerializeStatic(ScriptClass @class, SerializedObject context)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
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);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
public void Deserialize(ScriptInstance instance, SerializedObject context)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
MonoException* exception = null;
_deserializeMethod(instance.[Friend]_instance, thisPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, instance);
}
public void DeserializeStatic(ScriptClass @class, SerializedObject context)
{
void* thisPtr = Internal.UnsafeCastToPtr(context);
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);
_deserializeStaticMethod(reflectionType, thisPtr, &exception);
if (exception != null)
ScriptEngine.[Friend]HandleMonoException(exception, null);
}
}
@@ -231,23 +231,6 @@ class ScriptClass : SharpClass
return *(T*)Mono.mono_object_unbox(object);
}
public T GetFieldValue<T>(MonoObject* instance, MonoClassField* field)
{
T value = default;
Mono.mono_field_get_value(instance, field, &value);
return value;
}
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value)
{
Mono.mono_field_set_value(instance, field, &value);
}
public void SetFieldValue<T>(MonoObject* instance, MonoClassField* field, in T value) where T : struct*
{
Mono.mono_field_set_value(instance, field, value);
}
public MonoObject* BoxValue<T>(in T value)
{
return Mono.mono_value_box(ScriptEngine.[Friend]s_AppDomain, _monoClass, &value);
+4 -4
View File
@@ -22,7 +22,7 @@ class EngineClasses
private EntityEditorWrapper s_EntityEditor ~ _?.ReleaseRef();
private ScriptClass s_EntitySerializer ~ _?.ReleaseRef();
private EntitySerializerWrapper s_EntitySerializer ~ _?.ReleaseRef();
private ScriptClass s_SerializationContext ~ _?.ReleaseRef();
private ScriptClass s_Collision2D ~ _?.ReleaseRef();
@@ -35,7 +35,7 @@ class EngineClasses
public EntityEditorWrapper EntityEditor => s_EntityEditor;
public ScriptClass EntitySerializer => s_EntitySerializer;
public EntitySerializerWrapper EntitySerializer => s_EntitySerializer;
public ScriptClass Collision2D => s_Collision2D;
@@ -68,7 +68,7 @@ class EngineClasses
// Editor classes
s_EntityEditor = new EntityEditorWrapper("GlitchyEngine.Editor", "EntityEditor", image);
s_EntitySerializer = new ScriptClass("GlitchyEngine.Serialization", "EntitySerializer", image);
s_EntitySerializer = new EntitySerializerWrapper("GlitchyEngine.Serialization", "EntitySerializer", image);
s_Collision2D = new ScriptClass("GlitchyEngine.Physics", "Collision2D", image);
@@ -116,7 +116,7 @@ static class ScriptEngine
private static FileSystemWatcher _userAssemblyWatcher ~ delete _;
// TODO: This should be a global setting somewhere
private static bool _debuggingEnabled = false;
private static bool _debuggingEnabled = true;
private static String _appAssemblyPath = new .() ~ delete _;
+2 -2
View File
@@ -1143,7 +1143,7 @@ static class ScriptGlue
}
[RegisterCall("ScriptGlue::Serialization_CreateObject")]
static void Serialization_CreateObject(void* currentContext, MonoString* typeName, out void* newContext, out UUID newId)
static void Serialization_CreateObject(void* currentContext, bool isStatic, MonoString* typeName, out void* newContext, out UUID newId)
{
SerializedObject context = Internal.UnsafeCastToObject(currentContext) as SerializedObject;
@@ -1151,7 +1151,7 @@ static class ScriptGlue
char8* rawTypeName = Mono.mono_string_to_utf8(typeName);
SerializedObject newObject = new SerializedObject(context.Serializer, StringView(rawTypeName));
SerializedObject newObject = new SerializedObject(context.Serializer, isStatic, StringView(rawTypeName));
Mono.mono_free(rawTypeName);
@@ -31,19 +31,31 @@ public class ScriptInstanceSerializer
{
Debug.Profiler.ProfileFunction!();
for (let (id, script) in ScriptEngine._entityScriptInstances)
for (let (id, scriptInstance) in ScriptEngine._entityScriptInstances)
{
SerializeScriptInstance(script);
SerializeScriptInstance(scriptInstance);
}
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
{
SerializeStaticScriptClassFields(scriptClass);
}
}
/// Serializes the given script instance.
public void SerializeScriptInstance(ScriptInstance script)
{
SerializedObject object = new SerializedObject(this, script.ScriptClass.FullName, script.EntityId);
SerializedObject object = new SerializedObject(this, false, script.ScriptClass.FullName, script.EntityId);
object.Serialize(script);
}
/// Serializes the given script instance.
public void SerializeStaticScriptClassFields(ScriptClass scriptClass)
{
SerializedObject object = new SerializedObject(this, true, scriptClass.FullName, null);
object.SerializeStaticFields(scriptClass);
}
/// Deserializes this context into the instances currently managed by the script engine.
public void DeserializeScriptInstances()
{
@@ -53,6 +65,11 @@ public class ScriptInstanceSerializer
{
DeserializeScriptInstance(id, script);
}
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
{
DeserializeStaticScriptClassFields(scriptClass);
}
}
/// Deserializes the data into the given script instance, if there is data available.
@@ -69,6 +86,25 @@ public class ScriptInstanceSerializer
return false;
}
public bool DeserializeStaticScriptClassFields(ScriptClass scriptClass)
{
for (let object in _serializedData.Values)
{
if (object.IsStatic && object.TypeName == scriptClass.FullName)
{
// No data anyway, save some time.
if (object.Fields.Count == 0)
return false;
object.DeserializeStaticFields(scriptClass);
return true;
}
}
return false;
}
/// Replaces Entity references in the given serialized data using the specified translation table.
public void FixupSerializedIds(Dictionary<UUID, UUID> originalToCopyIds)
{