From 525bb050ef263ebb12549a3df4788c2cda9b3707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Thu, 25 Jan 2024 23:35:40 +0100 Subject: [PATCH] ScriptEngine cleanup --- GlitchyEngine/src/Scripting/ScriptClass.bf | 258 ++---------------- GlitchyEngine/src/Scripting/ScriptEngine.bf | 239 +--------------- .../src/Scripting/ScriptFieldType.bf | 92 ------- GlitchyEngine/src/Scripting/ScriptInstance.bf | 17 -- 4 files changed, 31 insertions(+), 575 deletions(-) diff --git a/GlitchyEngine/src/Scripting/ScriptClass.bf b/GlitchyEngine/src/Scripting/ScriptClass.bf index c46efd6..6fd0f02 100644 --- a/GlitchyEngine/src/Scripting/ScriptClass.bf +++ b/GlitchyEngine/src/Scripting/ScriptClass.bf @@ -8,77 +8,6 @@ namespace GlitchyEngine.Scripting; using internal GlitchyEngine.Scripting; -public struct ScriptField -{ - public StringView Name; - internal MonoClassField* _monoField; - public bool IsStatic; - public ScriptFieldType FieldType; - public SharpType SharpType; - public int SizeInBytes; - - internal this(StringView name, MonoClassField* monoField, bool isStatic, ScriptFieldType fieldType, int sizeInBytes, SharpType sharpType) - { - Name = name; - _monoField = monoField; - IsStatic = isStatic; - FieldType = fieldType; - SharpType = sharpType; - SizeInBytes = sizeInBytes; - } - - public bool IsType(SharpClass otherClass, bool checkIfSubtype) - { - return IsType(otherClass.GetMonoType(), checkIfSubtype); - } - - public bool IsType(MonoType* otherType, bool checkIfSubtype) - { - MonoType* myType = GetMonoType(); - - if (checkIfSubtype) - { - MonoClass* myClass = Mono.mono_type_get_class(myType); - MonoClass* otherClass = Mono.mono_type_get_class(otherType); - - return Mono.mono_class_is_subclass_of(myClass, otherClass, false); - } - else - { - return myType == otherType; - } - } - - public MonoType* GetMonoType() - { - return Mono.mono_field_get_type(_monoField); - } -} - -public struct ScriptFieldInstance -{ - public ScriptFieldType Type; - // TODO: I hate this, but we need to be able to store an entire matrix - internal uint8[sizeof(GlitchyEngine.Math.Matrix)] _data; - - public this(ScriptFieldType type) - { - Type = type; - _data = default; - } - - public T GetData() - { -#unwarn - return *(T*)&_data; - } - - public void SetData(T value) mut - { - *(T*)&_data = value; - } -} - abstract class SharpType : RefCounter { protected String _namespace ~ delete _; @@ -86,15 +15,11 @@ abstract class SharpType : RefCounter protected String _fullName ~ delete _; protected ScriptFieldType _scriptType; - protected Dictionary _monoFields ~ delete _; - public StringView Namespace => _namespace; public StringView ClassName => _className; public StringView FullName => _fullName; public ScriptFieldType ScriptType => _scriptType; - public Dictionary Fields => _monoFields; - public this(StringView classNamespace, StringView className, ScriptFieldType scriptType) { _namespace = new String(classNamespace); @@ -116,8 +41,6 @@ class SharpClass : SharpType _monoClass = Mono.mono_class_from_name(image, _namespace, _className); Log.EngineLogger.AssertDebug(_monoClass != null); - - ExtractFields(); } internal this(MonoClass* monoClass, ScriptFieldType fieldType = .Class) : @@ -126,8 +49,6 @@ class SharpClass : SharpType _monoClass = monoClass; Log.EngineLogger.AssertDebug(_monoClass != null); - - ExtractFields(); } internal MonoType* GetMonoType() @@ -144,135 +65,6 @@ class SharpClass : SharpType { return Mono.mono_class_is_subclass_of(_monoClass, @class, false); } - - private void ExtractFields() - { - //_monoFields = new List();ยด - _monoFields = new Dictionary(); - - void* iterator = null; - MonoClassField* currentField = null; - while ((currentField = Mono.mono_class_get_fields(_monoClass, &iterator)) != null) - { - StringView name = StringView(Mono.mono_field_get_name(currentField)); - - MonoType* type = Mono.mono_field_get_type(currentField); - - ScriptFieldType fieldType = ScriptEngineHelper.GetScriptFieldType(type); - - SharpType sharpType = null; - - // If field type is none the field might be a struct, class or enum - if (fieldType == .None) - { - sharpType = ScriptEngine.GetSharpType(type); - fieldType = sharpType?.ScriptType ?? .None; - - if (sharpType == null) - continue; - - sharpType.ReleaseRef(); - } - - //Mono.MonoTypeEnum fieldType = Mono.Mono.mono_type_get_type(type); - - FieldAttribute flags = (.)Mono.mono_field_get_flags(currentField); - - MonoCustomAttrInfo* attributes = Mono.mono_custom_attrs_from_field(_monoClass, currentField); - - if (flags.HasFlag(.Public) || - (attributes != null && - Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Attributes.s_ShowInEditorAttribute))) - { - MonoClass* fieldClass = Mono.mono_type_get_class(type); - - int sizeInBytes = 8; - - if (fieldClass != null) - { - sizeInBytes = Mono.mono_class_instance_size(fieldClass); - } - else - { - - } - - _monoFields[name] = .(name, currentField, flags.HasFlag(.Static), fieldType, sizeInBytes, sharpType); - } - } - } -} - -struct EnumValue -{ - public StringView Name; - - public uint64 Value; - - public this(StringView name, uint64 value) - { - Name = name; - Value = value; - } -} - -class SharpEnum : SharpClass -{ - private append Dictionary _values = .(); - - public Dictionary Values => _values; - - private int _underlyingSize = 0; - - public this(StringView classNamespace, StringView className, MonoImage* image) - : base(classNamespace, className, image, .Enum) - { - ExtractEnumValues(); - } - - private void ExtractEnumValues() - { - _underlyingSize = Mono.mono_class_instance_size(_monoClass); - Log.EngineLogger.Assert(_underlyingSize != 0); - - var vtable = Mono.mono_class_vtable(ScriptEngine.[Friend]s_AppDomain, _monoClass); - - void* iterator = null; - MonoClassField* currentField = null; - while ((currentField = Mono.mono_class_get_fields(_monoClass, &iterator)) != null) - { - MonoType* fieldType = Mono.mono_field_get_type(currentField); - MonoClass* fieldClass = Mono.mono_type_get_class(fieldType); - - FieldAttribute fieldFlags = (.)Mono.mono_field_get_flags(currentField); - - if (fieldFlags.HasFlag(.Public) && fieldFlags.HasFlag(.Static) && - fieldClass != null && Mono.mono_class_is_subclass_of(fieldClass, _monoClass, false)) - { - StringView fieldName = StringView(Mono.mono_field_get_name(currentField)); - - uint64 value = 0; - Mono.mono_field_static_get_value(vtable, currentField, &value); - - EnumValue enumValue = .(fieldName, value); - - _values.Add(value, enumValue); - } - } - } -} - -class SharpStruct : SharpClass -{ - protected int _size; - - public int Size => _size; - - public this(StringView classNamespace, StringView className, MonoImage* image) - : base(classNamespace, className, image) - { - - } } class ScriptClass : SharpClass @@ -289,16 +81,11 @@ class ScriptClass : SharpClass private OnUpdateMethod _onUpdate; private OnDestroyMethod _onDestroy; - private function [CallingConvention(.Cdecl)] MonoObject*(MonoObject* instance, Collision2D collision, MonoException** exception) _onCollisionEnter2D; - private function [CallingConvention(.Cdecl)] MonoObject*(MonoObject* instance, Collision2D collision, MonoException** exception) _onCollisionLeave2D; + private function [CallingConvention(.Cdecl)] MonoObject*(MonoObject* instance, MonoObject* collision2d, MonoException** exception) _onCollisionEnter2D; + private function [CallingConvention(.Cdecl)] MonoObject*(MonoObject* instance, MonoObject* collision2d, MonoException** exception) _onCollisionLeave2D; - //private OnCollisionEnter2DMethod _onCollisionEnter2D; - //private OnDestroyMethod _onCollisionLeave2D; - private MonoMethod* _onCollisionEnter2DMethod; - private MonoMethod* _onCollisionLeave2DMethod; - - public bool HasCollisionEnter2D => _onCollisionEnter2DMethod != null; - public bool HasCollisionLeave2D => _onCollisionLeave2DMethod != null; + public bool HasCollisionEnter2D => _onCollisionEnter2D != null; + public bool HasCollisionLeave2D => _onCollisionLeave2D != null; public bool RunInEditMode => _runInEditMode; @@ -311,9 +98,6 @@ class ScriptClass : SharpClass _onUpdate = (OnUpdateMethod)GetMethodThunk("OnUpdate", 1); _onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy"); - _onCollisionEnter2D = (.)GetMethodThunk("OnCollisionEnter2D", 1); - _onCollisionLeave2D = (.)GetMethodThunk("OnCollisionLeave2D", 1); - _onCollisionEnter2DMethod = GetMethod("OnCollisionEnter2D", 1); _onCollisionLeave2DMethod = GetMethod("OnCollisionLeave2D", 1); @@ -392,32 +176,22 @@ class ScriptClass : SharpClass { exception = null; - // TODO: use method thunk - if (_onCollisionEnter2DMethod != null) + if (_onCollisionEnter2D != null) { -#unwarn - void*[1] args = .(&collision); - - Invoke(_onCollisionEnter2DMethod, instance, (.)&args); + MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision); + _onCollisionEnter2D(instance, monoObject, &exception); } - // if (_onCollisionEnter2D != null) - // _onCollisionEnter2D(instance, collision, &exception); } public void OnCollisionLeave2D(MonoObject* instance, Collision2D collision, out MonoException* exception) { exception = null; - - // TODO: use method thunk - if (_onCollisionLeave2DMethod != null) + + if (_onCollisionEnter2D != null) { -#unwarn - void*[1] args = .(&collision); - - Invoke(_onCollisionLeave2DMethod, instance, (.)&args); + MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision); + _onCollisionLeave2D(instance, monoObject, &exception); } - // if (_onCollisionEnter2D != null) - // _onCollisionEnter2D(instance, collision, &exception); } public MonoObject* CreateInstance(UUID uuid, out MonoException* exception) @@ -505,4 +279,14 @@ class ScriptClass : SharpClass { Mono.mono_field_set_value(instance, field, value); } + + public MonoObject* BoxValue(in T value) + { + return Mono.mono_value_box(ScriptEngine.[Friend]s_AppDomain, _monoClass, &value); + } + + public MonoObject* BoxValue(void* value) + { + return Mono.mono_value_box(ScriptEngine.[Friend]s_AppDomain, _monoClass, value); + } } diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index dd84f5e..750d337 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -12,45 +12,10 @@ namespace GlitchyEngine.Scripting; using internal GlitchyEngine.Scripting; -static sealed class ScriptEngineHelper -{ - private static Dictionary _scriptFieldTypes = new Dictionary() - { - ("System.String", .String), - - ("System.Boolean", .Bool), - ("System.Char", .Char), - - ("System.SByte", .SByte), - ("System.Int16", .Short), - ("System.Int32", .Int), - ("System.Int64", .Long), - - ("System.Byte", .Byte), - ("System.UInt16", .UShort), - ("System.UInt32", .UInt), - ("System.UInt64", .ULong), - - ("System.Single", .Float), - ("GlitchyEngine.Math.float2", .float2), - ("GlitchyEngine.Math.float3", .float3), - ("GlitchyEngine.Math.float4", .float4), - - ("System.Double", .Double), - - ("GlitchyEngine.Entity", .Entity), - } ~ delete _; - - public static ScriptFieldType GetScriptFieldType(MonoType* monoType) - { - StringView typeName = StringView(Mono.mono_type_get_name(monoType)); - - return _scriptFieldTypes.TryGetValue(typeName, .. let scriptFieldType); - } -} - class EngineClasses { + // TODO: Not all of there are actually ScriptClasses (actually none of them are...) + private ScriptClass s_ComponentRoot ~ _?.ReleaseRef(); private ScriptClass s_EntityRoot ~ _?.ReleaseRef(); private ScriptClass s_EngineObject ~ _?.ReleaseRef(); @@ -60,6 +25,8 @@ class EngineClasses private ScriptClass s_EntitySerializer ~ _?.ReleaseRef(); private ScriptClass s_SerializationContext ~ _?.ReleaseRef(); + private ScriptClass s_Collision2D ~ _?.ReleaseRef(); + public ScriptClass ComponentRoot => s_ComponentRoot; public ScriptClass EntityRoot => s_EntityRoot; public ScriptClass EngineObject => s_EngineObject; @@ -67,7 +34,8 @@ class EngineClasses public ScriptClass EntityEditor => s_EntityEditor; public ScriptClass EntitySerializer => s_EntitySerializer; - //public ScriptClass SerializationContext => s_SerializationContext; + + public ScriptClass Collision2D => s_Collision2D; internal void ReleaseAndNullify() { @@ -79,6 +47,8 @@ class EngineClasses ReleaseRefAndNullify!(s_EntitySerializer); ReleaseRefAndNullify!(s_SerializationContext); + + ReleaseRefAndNullify!(s_Collision2D); } internal void LoadClasses(MonoImage* image) @@ -93,7 +63,8 @@ class EngineClasses s_EntityEditor = new ScriptClass("GlitchyEngine.Editor", "EntityEditor", image, .Class); s_EntitySerializer = new ScriptClass("GlitchyEngine.Serialization", "EntitySerializer", image, .Class); - //s_SerializationContext = new ScriptClass("GlitchyEngine.Serialization", "EntitySerializer.SerializationContext", image, .Class); + + s_Collision2D = new ScriptClass("GlitchyEngine.Physics", "Collision2D", image, .Struct); } } @@ -264,11 +235,6 @@ static class ScriptEngine String directory = scope .(); Path.GetDirectoryPath(_appAssemblyPath, directory); - /*if (_userAssemblyWatcher != null) // _userAssemblyWatcher.Directory != directory - { - delete _userAssemblyWatcher; - }*/ - String fileName = scope .("*/"); Path.GetFileName(_appAssemblyPath, fileName); @@ -336,8 +302,6 @@ static class ScriptEngine /// Starts the script runtime and sets the context scene. public static void StartRuntime(Scene context) { - /// At the moment only set the context. - Debug.Assert(s_Context == null, "StartRuntime was called twice without StopRuntime in between!"); Context = context; @@ -416,117 +380,6 @@ static class ScriptEngine _entityScriptInstances.Remove(entityId); } - /// Returns an instance that can be used as a reference to the entity with the given ID in Scripts - private static MonoObject* GetOrCreateScriptReferenceInstance(UUID entityId) - { - MonoObject* referencedEntity = GetManagedInstance(entityId); - - if (referencedEntity == null) - { - referencedEntity = Classes.EntityRoot.CreateInstance(entityId, let exception); - - if (exception != null) - ScriptEngine.HandleMonoException(exception, null); - } - - return referencedEntity; - } - - /// Creates an instance of the given component class referencing the specified entity instance. - private static MonoObject* CreateComponentReferenceInstance(ScriptClass componentClass, UUID id)//MonoObject* entityReferenceInstance) - { - MonoObject* componentInstance = componentClass.CreateInstance(); - - MonoClassField* idField = Mono.mono_class_get_field_from_name(componentClass.[Friend]_monoClass, "_uuid"); - - Classes.ComponentRoot.SetFieldValue(componentInstance, idField, id); - - /*// TODO: We could cache the property, but this might be fine - MonoProperty* entityProperty = Mono.mono_class_get_property_from_name(componentClass.[Friend]_monoClass, "Entity"); - - MonoObject* exception = null; - -//#unwarn - //Mono.mono_property_set_value(entityProperty, componentInstance, (void**)&entityReferenceInstance, &exception); -#unwarn - Mono.mono_property_set_value(entityProperty, componentInstance, (void**)&id, &exception); - - if (exception != null) - ScriptEngine.HandleMonoException((MonoException*)exception, null);*/ - - return componentInstance; - } - - public static void CopyFieldsToInstance(ScriptComponent* targetScript, ScriptComponent* sourceScript, Dictionary sourceIdToTargetId) - { - Debug.Profiler.ProfileFunction!(); - - Log.EngineLogger.AssertDebug(targetScript.Instance.ScriptClass == sourceScript.Instance.ScriptClass); - - for (let (name, scriptField) in sourceScript.Instance.ScriptClass.Fields) - { - Debug.Profiler.ProfileScope!("Copy Field"); - - targetScript.Instance.CopyFieldValue(scriptField, sourceScript.Instance); - switch (scriptField.FieldType) - { - case .Entity: - let sourceEntityReference = sourceScript.Instance.GetFieldValue(scriptField); - - MonoObject* referencedEntity = sourceEntityReference; - - if (sourceEntityReference != null) - { - let idField = Mono.mono_class_get_field_from_name(Classes.EntityRoot._monoClass, "_uuid"); - UUID sourceId = Classes.EntityRoot.GetFieldValue(sourceEntityReference, idField); - - // Check if we need to translate, copy otherwise - if (sourceIdToTargetId.TryGetValue(sourceId, let referencedId)) - { - // On the C# side we actually differentiate between an Entity and the Script - // in the sense that getting an entity and a script yields two different results (one creates a new Entity-Class instance, the other returns the actual instance). - // But here its just easier to always use the script instance. - // Obviously breaks once we support multiple scripts per entity. - referencedEntity = GetOrCreateScriptReferenceInstance(referencedId); - } - } - - targetScript.Instance.SetFieldValue(scriptField, referencedEntity); - case .Component: - - let sourceComponentReference = sourceScript.Instance.GetFieldValue(scriptField); - - MonoObject* componentInstance = sourceComponentReference; - - // Get or create entity reference - if (sourceComponentReference != null) - { - let idField = Mono.mono_class_get_field_from_name(Classes.EngineObject._monoClass, "_uuid"); - UUID sourceId = Classes.EntityRoot.GetFieldValue(sourceComponentReference, idField); - - MonoType* fieldMonoType = scriptField.GetMonoType(); - - SharpType componentType = ScriptEngine.GetSharpType(fieldMonoType); - - var componentClass = ComponentClasses[componentType.FullName]; - - if (sourceIdToTargetId.TryGetValue(sourceId, let targetId)) - { - // Create reference for translated id - componentInstance = CreateComponentReferenceInstance(componentClass, targetId); - } - - componentType.ReleaseRef(); - } - - targetScript.Instance.SetFieldValue(scriptField, componentInstance); - - default: - targetScript.Instance.CopyFieldValue(scriptField, sourceScript.Instance); - } - } - } - private static MonoAssembly* LoadCSharpAssembly(StringView assemblyPath, bool loadPDB = false) { Debug.Profiler.ProfileFunction!(); @@ -728,78 +581,6 @@ static class ScriptEngine _sharpClasses.Add(sharpType.FullName, sharpType..AddRef()); } - internal static SharpType GetSharpType(MonoType* monoType) - { - StringView typeName = StringView(Mono.mono_type_get_name(monoType)); - - if (_sharpClasses.TryGetValue(typeName, let sharpType)) - return sharpType..AddRef(); - - Mono.MonoTypeEnum fieldType = Mono.Mono.mono_type_get_type(monoType); - - MonoClass* monoClass = Mono.mono_class_from_mono_type(monoType); - - if (monoClass == null) - return null; - - StringView className = StringView(Mono.mono_class_get_name(monoClass)); - StringView classNamespace = StringView(Mono.mono_class_get_namespace(monoClass)); - - // TODO: at the moment only allow user-structs - //if (classNamespace.StartsWith("GlitchyEngine")) - // return null; - - ScriptFieldType scriptType = .None; - - if (Mono.mono_class_is_enum(monoClass)) - { - scriptType = .Enum; - - return new SharpEnum(classNamespace, className, Mono.mono_class_get_image(monoClass)); - } - else if (fieldType == .Class) - { - if (Mono.mono_class_is_subclass_of(monoClass, Classes.EntityRoot._monoClass, false)) - { - scriptType = .Entity; - } - else if (Mono.mono_class_is_subclass_of(monoClass, Classes.ComponentRoot._monoClass, false)) - { - scriptType = .Component; - } - else - { - scriptType = .Class; - } - } - else if (fieldType == .Valuetype) - { - scriptType = .Struct; - } - // TODO! ?! - else if (fieldType == .Genericinst) - { - scriptType = .GenericClass; - - return null; - //return new SharpClass(monoClass, scriptType); - } - else if (fieldType == .SzArray) - { - scriptType = .Array; - return null; - } - else if (fieldType == .Object) - { - // TODO: Help - return null; - } - - Log.EngineLogger.AssertDebug(scriptType != .None); - - return new SharpClass(classNamespace, className, Mono.mono_class_get_image(monoClass), scriptType); - } - /// Returns the script instance or null. public static MonoObject* GetManagedInstance(UUID entityId) { diff --git a/GlitchyEngine/src/Scripting/ScriptFieldType.bf b/GlitchyEngine/src/Scripting/ScriptFieldType.bf index 360fa93..6d2ad14 100644 --- a/GlitchyEngine/src/Scripting/ScriptFieldType.bf +++ b/GlitchyEngine/src/Scripting/ScriptFieldType.bf @@ -9,100 +9,8 @@ enum ScriptFieldType case None; case Class; - case Enum; case Struct; - case GenericClass; - case Array; - - case String; - - case Bool, Bool2, Bool3, Bool4; - case Char; - - case SByte; - case Short; - case Int, Int2, Int3, Int4; - case Long; - case Byte; - case UShort; - case UInt; // UInt2, UInt3, UInt4; - case ULong; - - case Float, float2, float3, float4; - case Double, Double2, Double3, Double4; - case Entity; case Component; - - public Type GetBeefType() - { - switch(this) - { - case .String: - return typeof(String); - - case .Bool: - return typeof(bool); - case .Bool2: - return typeof(bool2); - case .Bool3: - return typeof(bool3); - case .Bool4: - return typeof(bool4); - - case .Char: - return typeof(char16); - - case .SByte: - return typeof(int8); - case .Short: - return typeof(int16); - case .Int: - return typeof(int32); - case .Int2: - return typeof(int2); - case .Int3: - return typeof(int3); - case .Int4: - return typeof(int4); - case .Long: - return typeof(int64); - - case .Byte: - return typeof(uint8); - case .UShort: - return typeof(uint16); - case .UInt: - return typeof(uint32); - case .ULong: - return typeof(uint64); - - case .Float: - return typeof(float); - case .float2: - return typeof(float2); - case .float3: - return typeof(float3); - case .float4: - return typeof(float4); - - case .Double: - return typeof(double); - case .Double2: - return typeof(double2); - case .Double3: - return typeof(double3); - case .Double4: - return typeof(double4); - - case .Entity: - return typeof(UUID); - case .Component: - return typeof(UUID); - - default: - return null; - } - } } \ No newline at end of file diff --git a/GlitchyEngine/src/Scripting/ScriptInstance.bf b/GlitchyEngine/src/Scripting/ScriptInstance.bf index b6b2254..4dabab6 100644 --- a/GlitchyEngine/src/Scripting/ScriptInstance.bf +++ b/GlitchyEngine/src/Scripting/ScriptInstance.bf @@ -116,23 +116,6 @@ class ScriptInstance : RefCounter ScriptEngine.HandleMonoException(exception, this); } - public T GetFieldValue(ScriptField field) - { - return _scriptClass.GetFieldValue(_instance, field.[Friend]_monoField); - } - - public void SetFieldValue(ScriptField field, in T value) - { - _scriptClass.SetFieldValue(_instance, field.[Friend]_monoField, value); - } - - public void CopyFieldValue(ScriptField field, ScriptInstance sourceInstance) - { - // TODO: I hate this! - var data = sourceInstance.GetFieldValue(field); - SetFieldValue(field, data); - } - /// Creates a new instance of the given component class and initializes it for the current entity. public MonoObject* CreateComponentInstance(ScriptClass componentClassType) {