From f39acdadb3b5a3c44934505833490f0870e1fd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Fri, 28 Jul 2023 00:07:10 +0200 Subject: [PATCH] Show enum fields in Edit mode --- .../Assets/Scripts/MyTestEntity.cs | 8 ++- .../src/EditWindows/ComponentEditWindow.bf | 30 +++++++- GlitchyEngine/src/Scripting/ScriptClass.bf | 69 ++++++++++++++++++- GlitchyEngine/src/Scripting/ScriptEngine.bf | 56 +++++++-------- GlitchyEngineHelper/src/Mono/Mono.bf | 16 +++++ 5 files changed, 143 insertions(+), 36 deletions(-) diff --git a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs index 4432357..4a5b317 100644 --- a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs +++ b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs @@ -11,9 +11,9 @@ namespace Sandbox public enum MyEnum { - Yes, + Yes = 1, No, - Maybe + Maybe = 1337 } public struct MyStruct @@ -53,7 +53,9 @@ namespace Sandbox [ShowInEditor] private int MyNumber = 1337; //[ShowInEditor] public double MyDouble = 1000.0f; - //public MyStruct AStruct; + public MyStruct AStruct; + + public MyEnum AEnum = MyEnum.Maybe; public Camera Camera; diff --git a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf index 560bd9a..9a03817 100644 --- a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf +++ b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf @@ -693,8 +693,7 @@ namespace GlitchyEditor.EditWindows field.SetData(value); case .Enum: - // TODO! - + ShowEnumSelector(field, fieldName, scriptClass); //case .String: // TODO! @@ -716,6 +715,33 @@ namespace GlitchyEditor.EditWindows } } + private static void ShowEnumSelector(ScriptFieldInstance* field, StringView fieldName, ScriptClass scriptClass) + { + ScriptField scriptField = scriptClass.Fields[fieldName]; + SharpEnum enumType = scriptField.SharpType as SharpEnum; + + Log.EngineLogger.Assert(enumType != null, "Enum must have a SharpEnum!"); + + // Simply get Enum as a uint64 + var fieldValue = field.GetData(); + + StringView valueName = ""; + + if (enumType.Values.TryGetValue(fieldValue, let enumValue)) + valueName = enumValue.Name; + + if (ImGui.BeginCombo(fieldName.Ptr, valueName.Ptr)) + { + for (let (entryValue, enumEntry) in enumType.Values) + { + if (ImGui.Selectable(enumEntry.Name.Ptr, fieldValue == entryValue)) + field.SetData(entryValue); + } + + ImGui.EndCombo(); + } + } + private static Entity? ShowEntitySelector() { static char8[128] entitySearch = .(); diff --git a/GlitchyEngine/src/Scripting/ScriptClass.bf b/GlitchyEngine/src/Scripting/ScriptClass.bf index 53908de..20ef6ae 100644 --- a/GlitchyEngine/src/Scripting/ScriptClass.bf +++ b/GlitchyEngine/src/Scripting/ScriptClass.bf @@ -13,13 +13,15 @@ public struct ScriptField internal MonoClassField* _monoField; public bool IsStatic; public ScriptFieldType FieldType; + public SharpType SharpType; - internal this(StringView name, MonoClassField* monoField, bool isStatic, ScriptFieldType fieldType) + internal this(StringView name, MonoClassField* monoField, bool isStatic, ScriptFieldType fieldType, SharpType sharpType) { Name = name; _monoField = monoField; IsStatic = isStatic; FieldType = fieldType; + SharpType = sharpType; } public bool IsType(SharpClass otherClass, bool checkIfSubtype) @@ -147,10 +149,12 @@ class SharpClass : SharpType 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 sharpType = ScriptEngine.GetSharpType(type); + sharpType = ScriptEngine.GetSharpType(type); fieldType = sharpType?.ScriptType ?? .None; if (sharpType == null) @@ -169,7 +173,66 @@ class SharpClass : SharpType (attributes != null && Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Attributes.s_ShowInEditorAttribute))) { - _monoFields[name] = .(name, currentField, flags.HasFlag(.Static), fieldType); + _monoFields[name] = .(name, currentField, flags.HasFlag(.Static), fieldType, 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); } } } diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index 21a58ec..1e088cb 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -460,38 +460,38 @@ static class ScriptEngine // TODO: at the moment only allow user-structs //if (classNamespace.StartsWith("GlitchyEngine")) // return null; + + ScriptFieldType scriptType = .None; - switch (fieldType) + if (Mono.mono_class_is_enum(monoClass)) { - case .Class, .Valuetype, .Enum: - ScriptFieldType scriptType = .None; + scriptType = .Enum; - if (fieldType == .Class) - { - if (Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot._monoClass, false)) - { - scriptType = .Entity; - } - else if (Mono.mono_class_is_subclass_of(monoClass, s_ComponentRoot._monoClass, false)) - { - scriptType = .Component; - } - else - { - scriptType = .Class; - } - } - else if (fieldType == .Enum) - scriptType = .Enum; - else if (fieldType == .Valuetype) - scriptType = .Struct; - - Log.EngineLogger.AssertDebug(scriptType != .None); - - return new SharpClass(classNamespace, className, Mono.mono_class_get_image(monoClass), scriptType); - default: - return null; + return new SharpEnum(classNamespace, className, Mono.mono_class_get_image(monoClass)); } + else if (fieldType == .Class) + { + if (Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot._monoClass, false)) + { + scriptType = .Entity; + } + else if (Mono.mono_class_is_subclass_of(monoClass, s_ComponentRoot._monoClass, false)) + { + scriptType = .Component; + } + else + { + scriptType = .Class; + } + } + else if (fieldType == .Valuetype) + { + scriptType = .Struct; + } + + Log.EngineLogger.AssertDebug(scriptType != .None); + + return new SharpClass(classNamespace, className, Mono.mono_class_get_image(monoClass), scriptType); } public static void CreateScriptFieldMap(Entity entity) diff --git a/GlitchyEngineHelper/src/Mono/Mono.bf b/GlitchyEngineHelper/src/Mono/Mono.bf index 72780f7..03fd712 100644 --- a/GlitchyEngineHelper/src/Mono/Mono.bf +++ b/GlitchyEngineHelper/src/Mono/Mono.bf @@ -91,6 +91,9 @@ static class Mono [LinkName(.C)] public static extern MonoType* mono_class_get_type(MonoClass* monoClass); + + [LinkName(.C)] + public static extern int32 mono_class_instance_size(MonoClass* @class); [LinkName(.C)] public static extern char8* mono_class_get_namespace(MonoClass* monoClass); @@ -181,6 +184,9 @@ static class Mono [LinkName(.C)] public static extern void mono_field_get_value(MonoObject* object, MonoClassField* field, void* value); + + [LinkName(.C)] + public static extern void mono_field_static_get_value(MonoVTable* vt, MonoClassField* field, void* value); /// Gets the field as object, boxes the value if it is a valuetype. [LinkName(.C)] @@ -251,6 +257,14 @@ static class Mono [LinkName(.C)] public static extern MonoClass* mono_object_get_class(MonoObject* obj); + + + [LinkName(.C)] + public static extern mono_bool mono_class_is_enum(MonoClass* @class); + + + [LinkName(.C)] + public static extern MonoVTable* mono_class_vtable(MonoDomain* domain, MonoClass* @class); } struct MonoDomain; @@ -273,6 +287,8 @@ struct MonoProperty; struct MonoThread; +struct MonoVTable; + struct MonoException { void* _bla;