diff --git a/Source/Engine/Core/Types/Variant.h b/Source/Engine/Core/Types/Variant.h index a9544899f..503ab94a0 100644 --- a/Source/Engine/Core/Types/Variant.h +++ b/Source/Engine/Core/Types/Variant.h @@ -192,6 +192,8 @@ public: Variant(Variant&& other) noexcept; explicit Variant(decltype(nullptr)); + explicit Variant(const VariantType& type); + explicit Variant(VariantType&& type); Variant(bool v); Variant(int16 v); Variant(uint16 v); diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 006bd3e3e..4510d783f 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -180,6 +180,19 @@ ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* modul Struct.SetField = setField; } +ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, EnumItem* items) + : ManagedClass(nullptr) + , Module(module) + , InitRuntime(DefaultInitRuntime) + , Fullname(fullname) + , Type(ScriptingTypes::Enum) + , BaseTypePtr(nullptr) + , Interfaces(nullptr) + , Size(size) +{ + Enum.Items = items; +} + ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, InitRuntimeHandler initRuntime, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable, GetInterfaceWrapper getInterfaceWrapper) : ManagedClass(nullptr) , Module(module) @@ -232,6 +245,7 @@ ScriptingType::ScriptingType(const ScriptingType& other) Class.Dtor = other.Class.Dtor; break; case ScriptingTypes::Enum: + Enum.Items = other.Enum.Items; break; case ScriptingTypes::Interface: Interface.SetupScriptVTable = other.Interface.SetupScriptVTable; @@ -284,6 +298,7 @@ ScriptingType::ScriptingType(ScriptingType&& other) Class.Dtor = other.Class.Dtor; break; case ScriptingTypes::Enum: + Enum.Items = other.Enum.Items; break; case ScriptingTypes::Interface: Interface.SetupScriptVTable = other.Interface.SetupScriptVTable; @@ -317,6 +332,15 @@ ScriptingType::~ScriptingType() } } +void ScriptingType::DefaultInitRuntime() +{ +} + +ScriptingObject* ScriptingType::DefaultSpawn(const ScriptingObjectSpawnParams& params) +{ + return nullptr; +} + ScriptingTypeHandle ScriptingType::GetHandle() const { int32 typeIndex; @@ -544,9 +568,7 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, initRuntime, spawn, baseType, setupScriptVTable, setupScriptObjectVTable, interfaces); #if BUILD_DEBUG if (module->TypeNameToTypeIndex.ContainsKey(fullname)) - { LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName())); - } #endif module->TypeNameToTypeIndex[fullname] = TypeIndex; } @@ -559,9 +581,7 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, initRuntime, ctor, dtor, baseType, interfaces); #if BUILD_DEBUG if (module->TypeNameToTypeIndex.ContainsKey(fullname)) - { LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName())); - } #endif module->TypeNameToTypeIndex[fullname] = TypeIndex; } @@ -574,9 +594,20 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, initRuntime, ctor, dtor, copy, box, unbox, getField, setField, baseType, interfaces); #if BUILD_DEBUG if (module->TypeNameToTypeIndex.ContainsKey(fullname)) - { LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName())); - } +#endif + module->TypeNameToTypeIndex[fullname] = TypeIndex; +} + +ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::EnumItem* items) + : ScriptingTypeHandle(module, module->Types.Count()) +{ + // Enum + module->Types.AddUninitialized(); + new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, items); +#if BUILD_DEBUG + if (module->TypeNameToTypeIndex.ContainsKey(fullname)) + LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName())); #endif module->TypeNameToTypeIndex[fullname] = TypeIndex; } @@ -589,9 +620,7 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, initRuntime, setupScriptVTable, setupScriptObjectVTable, getInterfaceWrapper); #if BUILD_DEBUG if (module->TypeNameToTypeIndex.ContainsKey(fullname)) - { LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName())); - } #endif module->TypeNameToTypeIndex[fullname] = TypeIndex; } diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp index 4b5a3d82d..49f67da05 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp @@ -571,7 +571,7 @@ MonoObject* MUtils::BoxVariant(const Variant& value) else if (mono_class_is_valuetype(elementClass)) { // Array of Structures - VariantType elementType = UnboxVariantType(mono_class_get_type(elementClass)); + const VariantType elementType = UnboxVariantType(mono_class_get_type(elementClass)); switch (elementType.Type) { case VariantType::Bool: diff --git a/Source/Engine/Scripting/ScriptingType.h b/Source/Engine/Scripting/ScriptingType.h index 45bd92bef..58713fcee 100644 --- a/Source/Engine/Scripting/ScriptingType.h +++ b/Source/Engine/Scripting/ScriptingType.h @@ -116,6 +116,7 @@ struct FLAXENGINE_API ScriptingType typedef void (*GetField)(void* ptr, const String& name, Variant& value); typedef void (*SetField)(void* ptr, const String& name, const Variant& value); typedef void* (*GetInterfaceWrapper)(ScriptingObject* obj); + typedef struct { uint64 Value; const char* Name; } EnumItem; struct InterfaceImplementation { @@ -246,6 +247,12 @@ struct FLAXENGINE_API ScriptingType SetField SetField; } Struct; + struct + { + // Enum items table (the last item name is null) + EnumItem* Items; + } Enum; + struct { // Class constructor method pointer @@ -268,6 +275,7 @@ struct FLAXENGINE_API ScriptingType ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime = DefaultInitRuntime, SpawnHandler spawn = DefaultSpawn, ScriptingTypeInitializer* baseType = nullptr, SetupScriptVTableHandler setupScriptVTable = nullptr, SetupScriptObjectVTableHandler setupScriptObjectVTable = nullptr, const InterfaceImplementation* interfaces = nullptr); ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, ScriptingTypeInitializer* baseType, const InterfaceImplementation* interfaces = nullptr); ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, Copy copy, Box box, Unbox unbox, GetField getField, SetField setField, ScriptingTypeInitializer* baseType, const InterfaceImplementation* interfaces = nullptr); + ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, EnumItem* items); ScriptingType(const StringAnsiView& fullname, BinaryModule* module, InitRuntimeHandler initRuntime, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable, GetInterfaceWrapper getInterfaceWrapper); ScriptingType(const ScriptingType& other); ScriptingType(ScriptingType&& other); @@ -275,25 +283,17 @@ struct FLAXENGINE_API ScriptingType ScriptingType& operator=(const ScriptingType& other) = delete; ~ScriptingType(); - static void DefaultInitRuntime() - { - } - - static ScriptingObject* DefaultSpawn(const ScriptingObjectSpawnParams& params) - { - return nullptr; - } + static void DefaultInitRuntime(); + static ScriptingObject* DefaultSpawn(const ScriptingObjectSpawnParams& params); /// /// Gets the handle to this type. /// - /// This type handle. ScriptingTypeHandle GetHandle() const; /// /// Gets the handle to the base type of this type. /// - /// The base type handle (might be empty). ScriptingTypeHandle GetBaseType() const { return BaseTypePtr ? *BaseTypePtr : BaseTypeHandle; @@ -323,6 +323,7 @@ struct FLAXENGINE_API ScriptingTypeInitializer : ScriptingTypeHandle ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime = ScriptingType::DefaultInitRuntime, ScriptingType::SpawnHandler spawn = ScriptingType::DefaultSpawn, ScriptingTypeInitializer* baseType = nullptr, ScriptingType::SetupScriptVTableHandler setupScriptVTable = nullptr, ScriptingType::SetupScriptObjectVTableHandler setupScriptObjectVTable = nullptr, const ScriptingType::InterfaceImplementation* interfaces = nullptr); ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingTypeInitializer* baseType = nullptr, const ScriptingType::InterfaceImplementation* interfaces = nullptr); ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingType::Copy copy, ScriptingType::Box box, ScriptingType::Unbox unbox, ScriptingType::GetField getField, ScriptingType::SetField setField, ScriptingTypeInitializer* baseType = nullptr, const ScriptingType::InterfaceImplementation* interfaces = nullptr); + ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::EnumItem* items); ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::SetupScriptVTableHandler setupScriptVTable, ScriptingType::SetupScriptObjectVTableHandler setupScriptObjectVTable, ScriptingType::GetInterfaceWrapper getInterfaceWrapper); }; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 28f2e3a7b..c7f8a892f 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1952,6 +1952,35 @@ namespace Flax.Build.Bindings } } + private static void GenerateCppEnum(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, EnumInfo enumInfo) + { + var enumTypeNameNative = enumInfo.FullNameNative; + var enumTypeNameManaged = enumInfo.FullNameManaged; + var enumTypeNameInternal = enumInfo.NativeName; + if (enumInfo.Parent != null && !(enumInfo.Parent is FileInfo)) + enumTypeNameInternal = enumInfo.Parent.FullNameNative + '_' + enumTypeNameInternal; + + contents.AppendLine(); + contents.AppendFormat("class {0}Internal", enumTypeNameInternal).AppendLine(); + contents.Append('{').AppendLine(); + contents.AppendLine("public:"); + contents.AppendLine(" static ScriptingType::EnumItem Items[];"); + contents.Append('}').Append(';').AppendLine(); + contents.AppendLine(); + + // Items + contents.AppendFormat("ScriptingType::EnumItem {0}Internal::Items[] = {{", enumTypeNameInternal).AppendLine(); + foreach (var entry in enumInfo.Entries) + contents.AppendFormat(" {{ (uint64){0}::{1}, \"{1}\" }},", enumTypeNameNative, entry.Name).AppendLine(); + contents.AppendLine(" { 0, nullptr }"); + contents.AppendLine("};").AppendLine(); + + contents.Append($"ScriptingTypeInitializer {enumTypeNameInternal}_TypeInitializer((BinaryModule*)GetBinaryModule{moduleInfo.Name}(), "); + contents.Append($"StringAnsiView(\"{enumTypeNameManaged}\", {enumTypeNameManaged.Length}), "); + contents.Append($"sizeof({enumTypeNameNative}), "); + contents.Append($"{enumTypeNameInternal}Internal::Items);").AppendLine(); + } + private static void GenerateCppInterface(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, InterfaceInfo interfaceInfo) { var interfaceTypeNameNative = interfaceInfo.FullNameNative; @@ -2072,6 +2101,8 @@ namespace Flax.Build.Bindings GenerateCppClass(buildData, contents, moduleInfo, classInfo); else if (type is StructureInfo structureInfo) GenerateCppStruct(buildData, contents, moduleInfo, structureInfo); + else if (type is EnumInfo enumInfo) + GenerateCppEnum(buildData, contents, moduleInfo, enumInfo); else if (type is InterfaceInfo interfaceInfo) GenerateCppInterface(buildData, contents, moduleInfo, interfaceInfo); else if (type is InjectCppCodeInfo injectCppCodeInfo)