mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
ScriptEngine: Serialize static fields
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 _;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ class SerializedObject
|
||||
/// 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 bool IsStatic;
|
||||
|
||||
public String TypeName ~ delete:append _;
|
||||
|
||||
public ScriptInstanceSerializer Serializer;
|
||||
@@ -42,12 +44,14 @@ class SerializedObject
|
||||
public append Dictionary<StringView, (SerializationType PrimitiveType, FieldData Data)> Fields = .();
|
||||
|
||||
[AllowAppend]
|
||||
public this(ScriptInstanceSerializer serializer, StringView? typeName, UUID? id = null)
|
||||
public this(ScriptInstanceSerializer serializer, bool isStatic, StringView? typeName, UUID? id = null)
|
||||
{
|
||||
String typeNameCopy = append String(typeName.Value);
|
||||
|
||||
Serializer = serializer;
|
||||
|
||||
IsStatic = isStatic;
|
||||
|
||||
if (id == null)
|
||||
{
|
||||
// Make sure we have no duplicate keys
|
||||
@@ -200,33 +204,24 @@ class SerializedObject
|
||||
}
|
||||
}
|
||||
|
||||
typealias SerializeMethod = function MonoObject*(MonoObject* entity, void* contextPtr, MonoException** exception);
|
||||
typealias DeserializeMethod = function MonoObject*(MonoObject* entity, void* contextPtr, MonoException** exception);
|
||||
|
||||
public void Serialize(ScriptInstance scriptInstance)
|
||||
{
|
||||
SerializeMethod serialize = (SerializeMethod)ScriptEngine.Classes.EntitySerializer.GetMethodThunk("Serialize", 2);
|
||||
|
||||
void* thisPtr = Internal.UnsafeCastToPtr(this);
|
||||
|
||||
MonoException* exception = null;
|
||||
serialize(scriptInstance.[Friend]_instance, thisPtr, &exception);
|
||||
|
||||
if (exception != null)
|
||||
ScriptEngine.[Friend]HandleMonoException(exception, scriptInstance);
|
||||
ScriptEngine.Classes.EntitySerializer.Serialize(scriptInstance, this);
|
||||
}
|
||||
|
||||
public void Deserialize(ScriptInstance scriptInstance)
|
||||
{
|
||||
DeserializeMethod deserialize = (DeserializeMethod)ScriptEngine.Classes.EntitySerializer.GetMethodThunk("Deserialize", 2);
|
||||
ScriptEngine.Classes.EntitySerializer.Deserialize(scriptInstance, this);
|
||||
}
|
||||
|
||||
void* thisPtr = Internal.UnsafeCastToPtr(this);
|
||||
public void SerializeStaticFields(ScriptClass scriptClass)
|
||||
{
|
||||
ScriptEngine.Classes.EntitySerializer.SerializeStatic(scriptClass, this);
|
||||
}
|
||||
|
||||
MonoException* exception = null;
|
||||
deserialize(scriptInstance.[Friend]_instance, thisPtr, &exception);
|
||||
|
||||
if (exception != null)
|
||||
ScriptEngine.[Friend]HandleMonoException(exception, scriptInstance);
|
||||
public void DeserializeStaticFields(ScriptClass scriptClass)
|
||||
{
|
||||
ScriptEngine.Classes.EntitySerializer.DeserializeStatic(scriptClass, this);
|
||||
}
|
||||
|
||||
static this
|
||||
@@ -374,7 +369,7 @@ class SerializedObject
|
||||
|
||||
Try!(Deserialize.Value<UUID>(reader, "ID", let objectId, environment));
|
||||
|
||||
SerializedObject object = new SerializedObject(scriptSerializer, type, objectId);
|
||||
SerializedObject object = new SerializedObject(scriptSerializer, false, type, objectId);
|
||||
|
||||
while (reader.ObjectHasMore())
|
||||
{
|
||||
|
||||
@@ -64,9 +64,6 @@ class SceneSerializer
|
||||
|
||||
using (writer.ObjectBlock())
|
||||
{
|
||||
// TODO: Scene name goes here!
|
||||
Serialize.Value(writer, "Name", "Scene name here pls!!!");
|
||||
|
||||
Serialize.Value(writer, "Version", FileVersion);
|
||||
|
||||
writer.Identifier("Entities");
|
||||
@@ -93,7 +90,30 @@ class SceneSerializer
|
||||
{
|
||||
for (UUID id in _objectsNotWritten)
|
||||
{
|
||||
Serialize.Value(writer, _scriptSerializer.GetSerializedObject(id));
|
||||
SerializedObject object = _scriptSerializer.GetSerializedObject(id);
|
||||
|
||||
if (object.IsStatic)
|
||||
continue;
|
||||
|
||||
Serialize.Value(writer, object);
|
||||
}
|
||||
}
|
||||
|
||||
writer.EntryEnd();
|
||||
|
||||
writer.Identifier("StaticFields");
|
||||
|
||||
// Write all objects that don't belong to an entity. (referenced Arrays, Classes, etc...)
|
||||
using (writer.ArrayBlock())
|
||||
{
|
||||
for (UUID id in _objectsNotWritten)
|
||||
{
|
||||
SerializedObject object = _scriptSerializer.GetSerializedObject(id);
|
||||
|
||||
if (!object.IsStatic || object.Fields.Count == 0)
|
||||
continue;
|
||||
|
||||
Serialize.Value(writer, object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +366,9 @@ class SceneSerializer
|
||||
case "Entities":
|
||||
Try!(DeserializeEntities(reader, loadAsPrefab));
|
||||
case "ReferencedObjects":
|
||||
Try!(DeserializeReferencedObjects(reader));
|
||||
Try!(DeserializeReferencedObjects(reader, false));
|
||||
case "StaticFields":
|
||||
Try!(DeserializeReferencedObjects(reader, true));
|
||||
default:
|
||||
Log.EngineLogger.Warning($"Encountered unexpected Identifier \"{identifier}\".");
|
||||
}
|
||||
@@ -390,14 +412,16 @@ class SceneSerializer
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
private Result<void> DeserializeReferencedObjects(BonReader reader)
|
||||
private Result<void> DeserializeReferencedObjects(BonReader reader, bool isStatic)
|
||||
{
|
||||
Try!(reader.ArrayBlock());
|
||||
|
||||
while (reader.ArrayHasMore())
|
||||
{
|
||||
Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer, _fileVersion, gBonEnv));
|
||||
|
||||
SerializedObject object = Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer, _fileVersion, gBonEnv));
|
||||
|
||||
object.IsStatic = isStatic;
|
||||
|
||||
TryEndEntry(reader);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user