From e5e7a795b14487e7eb0cfb011a8e0518769ce533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etcheverry?= Date: Tue, 28 Dec 2021 23:25:16 +0100 Subject: [PATCH] C#: Code cleanup and greatly reduce use of C# pointers --- modules/mono/.editorconfig | 29 + modules/mono/.gitignore | 3 + modules/mono/csharp_script.cpp | 2 +- .../GenerateGodotNupkgsVersions.targets | 4 +- .../GodotTools.Shared.csproj | 2 + .../GodotTools/Export/ExportPlugin.cs | 10 +- .../GodotTools/Internals/EditorProgress.cs | 14 +- .../GodotTools/Internals/Globals.cs | 22 +- .../GodotTools/Internals/GodotSharpDirs.cs | 14 +- .../GodotTools/Internals/Internal.cs | 10 +- .../editor/GodotTools/GodotTools/Utils/OS.cs | 6 +- modules/mono/editor/bindings_generator.cpp | 181 +++-- modules/mono/editor/bindings_generator.h | 23 +- modules/mono/glue/GodotSharp/.editorconfig | 8 + .../glue/GodotSharp/GodotSharp/Core/Array.cs | 142 ++-- .../glue/GodotSharp/GodotSharp/Core/Basis.cs | 8 +- .../Core/Bridge/CSharpInstanceBridge.cs | 31 +- .../Core/Bridge/ScriptManagerBridge.cs | 41 +- .../GodotSharp/GodotSharp/Core/Callable.cs | 66 +- .../glue/GodotSharp/GodotSharp/Core/Color.cs | 8 +- .../GodotSharp/Core/DebuggingUtils.cs | 14 +- .../GodotSharp/Core/DelegateUtils.cs | 6 +- .../GodotSharp/GodotSharp/Core/Dictionary.cs | 205 +++-- .../Core/Extensions/ObjectExtensions.cs | 15 +- .../Core/Extensions/SceneTreeExtensions.cs | 18 +- .../glue/GodotSharp/GodotSharp/Core/GD.cs | 115 ++- .../Core/NativeInterop/InteropStructs.cs | 718 +++++++++++++++--- .../Core/NativeInterop/InteropUtils.cs | 27 +- .../Core/NativeInterop/Marshaling.cs | 599 ++++++++------- .../Core/NativeInterop/NativeFuncs.cs | 364 +++++---- .../NativeInterop/NativeFuncs.extended.cs | 61 +- .../NativeInterop/NativeVariantPtrArgs.cs | 20 + .../Core/NativeInterop/VariantSpanHelpers.cs | 10 +- .../Core/NativeInterop/VariantUtils.cs | 350 ++++----- .../GodotSharp/GodotSharp/Core/NodePath.cs | 70 +- .../GodotSharp/GodotSharp/Core/Object.base.cs | 53 +- .../GodotSharp/GodotSharp/Core/Quaternion.cs | 4 +- .../GodotSharp/Core/SignalAwaiter.cs | 14 +- .../GodotSharp/GodotSharp/Core/SignalInfo.cs | 2 +- .../GodotSharp/Core/StringExtensions.cs | 75 +- .../GodotSharp/GodotSharp/Core/StringName.cs | 22 +- .../GodotSharp/GodotSharp/Core/Transform2D.cs | 4 +- .../GodotSharp/GodotSharp/Core/Transform3D.cs | 12 +- .../GodotSharp/GodotSharp/Core/Vector2.cs | 4 +- .../GodotSharp/GodotSharp/Core/Vector2i.cs | 4 +- .../GodotSharp/GodotSharp/Core/Vector3.cs | 4 +- .../GodotSharp/GodotSharp/Core/Vector3i.cs | 4 +- .../GodotSharp/GodotSharp/FodyWeavers.xml | 3 + .../GenerateGodotCustomUnsafe.targets | 93 +++ .../GodotSharp/GodotSharp/GodotSharp.csproj | 9 + modules/mono/glue/runtime_interop.cpp | 19 +- 51 files changed, 2195 insertions(+), 1347 deletions(-) create mode 100644 modules/mono/glue/GodotSharp/.editorconfig create mode 100644 modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs create mode 100644 modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml create mode 100644 modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets diff --git a/modules/mono/.editorconfig b/modules/mono/.editorconfig index c9dcd7724ed..9434d0693c0 100644 --- a/modules/mono/.editorconfig +++ b/modules/mono/.editorconfig @@ -12,3 +12,32 @@ insert_final_newline = true trim_trailing_whitespace = true max_line_length = 120 csharp_indent_case_contents_when_block = false + +[*.cs] +# CA1707: Identifiers should not contain underscores +# TODO: +# Maybe we could disable this selectively only +# where it's not desired and for generated code. +dotnet_diagnostic.CA1707.severity = none +# CA1711: Identifiers should not have incorrect suffix +# Disable warning for suffixes like EventHandler, Flags, Enum, etc. +dotnet_diagnostic.CA1711.severity = none +# CA1716: Identifiers should not match keywords +# TODO: We should look into this. +dotnet_diagnostic.CA1716.severity = warning +# CA1720: Identifiers should not contain type names +dotnet_diagnostic.CA1720.severity = none +# CA1805: Do not initialize unnecessarily +# Don't tell me what to do. +dotnet_diagnostic.CA1805.severity = none +# CA1304: Specify CultureInfo +# TODO: We should look into this. +dotnet_diagnostic.CA1304.severity = warning +# CA1305: Specify IFormatProvider +# TODO: We should look into this. Disabled for now because it's annoying. +dotnet_diagnostic.CA1305.severity = none +# CA1310: Specify StringComparison for correctness +# TODO: We should look into this. Disabled for now because it's annoying. +dotnet_diagnostic.CA1310.severity = none +# Diagnostics to prevent defensive copies of `in` struct parameters +resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error diff --git a/modules/mono/.gitignore b/modules/mono/.gitignore index fa6d00cbbba..69d5089e5d7 100644 --- a/modules/mono/.gitignore +++ b/modules/mono/.gitignore @@ -1,2 +1,5 @@ # Do not ignore solution files inside the mono module. Overrides Godot's global gitignore. !*.sln + +# Fody +FodyWeavers.xsd diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 772c7059816..80e127bbc2c 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) { return OK; } -extern void *godotsharp_pinvoke_funcs[176]; +extern void *godotsharp_pinvoke_funcs[178]; [[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs; #ifdef TOOLS_ENABLED extern void *godotsharp_editor_pinvoke_funcs[32]; diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets index aab2d73bdd8..4baae77b348 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets +++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets @@ -8,8 +8,8 @@ + DependsOnTargets="_GenerateGodotNupkgsVersionsFile" + BeforeTargets="PrepareForBuild;CompileDesignTime;BeforeCompile;CoreCompile"> diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj index 4b058a5daac..7d8b83d5f0f 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj @@ -1,6 +1,8 @@ net5.0 + + false diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 25c2e4ab596..d8ebe762e1f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -233,11 +233,11 @@ namespace GodotTools.Export } } - var initialAssemblies = assemblies.Duplicate(); - godot_dictionary initialAssembliesAux = ((Godot.Collections.Dictionary)initialAssemblies).NativeValue; - using godot_string buildConfigAux = Marshaling.mono_string_to_godot(buildConfig); - using godot_string bclDirAux = Marshaling.mono_string_to_godot(bclDir); - godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue; + // var initialAssemblies = assemblies.Duplicate(); + // godot_dictionary initialAssembliesAux = ((Godot.Collections.Dictionary)initialAssemblies).NativeValue; + // using godot_string buildConfigAux = Marshaling.ConvertStringToNative(buildConfig); + // using godot_string bclDirAux = Marshaling.ConvertStringToNative(bclDir); + // godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue; // TODO throw new NotImplementedException(); //internal_GetExportedAssemblyDependencies(initialAssembliesAux, buildConfigAux, bclDirAux, ref assembliesAux); diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs index 7d2eb2d8698..8f39ad063e8 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs @@ -12,8 +12,8 @@ namespace GodotTools.Internals public EditorProgress(string task, string label, int amount, bool canCancel = false) { Task = task; - using godot_string taskIn = Marshaling.mono_string_to_godot(task); - using godot_string labelIn = Marshaling.mono_string_to_godot(label); + using godot_string taskIn = Marshaling.ConvertStringToNative(task); + using godot_string labelIn = Marshaling.ConvertStringToNative(label); Internal.godot_icall_EditorProgress_Create(taskIn, labelIn, amount, canCancel); } @@ -27,22 +27,22 @@ namespace GodotTools.Internals public void Dispose() { - using godot_string taskIn = Marshaling.mono_string_to_godot(Task); + using godot_string taskIn = Marshaling.ConvertStringToNative(Task); Internal.godot_icall_EditorProgress_Dispose(taskIn); GC.SuppressFinalize(this); } public void Step(string state, int step = -1, bool forceRefresh = true) { - using godot_string taskIn = Marshaling.mono_string_to_godot(Task); - using godot_string stateIn = Marshaling.mono_string_to_godot(state); + using godot_string taskIn = Marshaling.ConvertStringToNative(Task); + using godot_string stateIn = Marshaling.ConvertStringToNative(state); Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh); } public bool TryStep(string state, int step = -1, bool forceRefresh = true) { - using godot_string taskIn = Marshaling.mono_string_to_godot(Task); - using godot_string stateIn = Marshaling.mono_string_to_godot(state); + using godot_string taskIn = Marshaling.ConvertStringToNative(Task); + using godot_string stateIn = Marshaling.ConvertStringToNative(state); return Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh); } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs index 3b65263aa99..acb7cc3ab0e 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs @@ -10,37 +10,37 @@ namespace GodotTools.Internals public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) { - using godot_string settingIn = Marshaling.mono_string_to_godot(setting); - using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue); + using godot_string settingIn = Marshaling.ConvertStringToNative(setting); + using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue); Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result); using (result) - return Marshaling.variant_to_mono_object(&result); + return Marshaling.ConvertVariantToManagedObject(result); } public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) { - using godot_string settingIn = Marshaling.mono_string_to_godot(setting); - using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue); + using godot_string settingIn = Marshaling.ConvertStringToNative(setting); + using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue); Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result); using (result) - return Marshaling.variant_to_mono_object(&result); + return Marshaling.ConvertVariantToManagedObject(result); } - public static unsafe object EditorShortcut(string setting) + public static object EditorShortcut(string setting) { - using godot_string settingIn = Marshaling.mono_string_to_godot(setting); + using godot_string settingIn = Marshaling.ConvertStringToNative(setting); Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result); using (result) - return Marshaling.variant_to_mono_object(&result); + return Marshaling.ConvertVariantToManagedObject(result); } [SuppressMessage("ReSharper", "InconsistentNaming")] public static string TTR(this string text) { - using godot_string textIn = Marshaling.mono_string_to_godot(text); + using godot_string textIn = Marshaling.ConvertStringToNative(text); Internal.godot_icall_Globals_TTR(textIn, out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs index 9011662248a..eca7da07c89 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs @@ -11,7 +11,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -21,7 +21,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -31,7 +31,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_MonoUserDir(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -41,7 +41,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -51,7 +51,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_ProjectSlnPath(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -61,7 +61,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_ProjectCsProjPath(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -71,7 +71,7 @@ namespace GodotTools.Internals { Internal.godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index 8e4eb031db6..7b39f8ecdb6 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -18,7 +18,7 @@ namespace GodotTools.Internals { godot_icall_Internal_FullExportTemplatesDir(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -26,7 +26,7 @@ namespace GodotTools.Internals public static bool IsMacOSAppBundleInstalled(string bundleId) { - using godot_string bundleIdIn = Marshaling.mono_string_to_godot(bundleId); + using godot_string bundleIdIn = Marshaling.ConvertStringToNative(bundleId); return godot_icall_Internal_IsMacOSAppBundleInstalled(bundleIdIn); } @@ -53,7 +53,7 @@ namespace GodotTools.Internals { godot_icall_Internal_MonoWindowsInstallRoot(out godot_string dest); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } } @@ -67,10 +67,10 @@ namespace GodotTools.Internals public static unsafe string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind, string scriptFile) { - using godot_string scriptFileIn = Marshaling.mono_string_to_godot(scriptFile); + using godot_string scriptFileIn = Marshaling.ConvertStringToNative(scriptFile); godot_icall_Internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res); using (res) - return Marshaling.PackedStringArray_to_mono_array(&res); + return Marshaling.ConvertNativePackedStringArrayToSystemArray(res); } #region Internal diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index d9b59422372..db77a71c2f2 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -63,7 +63,7 @@ namespace GodotTools.Utils Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest); using (dest) { - string platformName = Marshaling.mono_string_from_godot(dest); + string platformName = Marshaling.ConvertStringToManaged(dest); return name.Equals(platformName, StringComparison.OrdinalIgnoreCase); } } @@ -73,7 +73,7 @@ namespace GodotTools.Utils Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest); using (dest) { - string platformName = Marshaling.mono_string_from_godot(dest); + string platformName = Marshaling.ConvertStringToManaged(dest); return names.Any(p => p.Equals(platformName, StringComparison.OrdinalIgnoreCase)); } } @@ -185,7 +185,7 @@ namespace GodotTools.Utils return searchDirs.Select(dir => Path.Combine(dir, name)) .FirstOrDefault(path => { - using godot_string pathIn = Marshaling.mono_string_to_godot(path); + using godot_string pathIn = Marshaling.ConvertStringToNative(path); return File.Exists(path) && Internal.godot_icall_Utils_OS_UnixFileHasExecutableAccess(pathIn); }); } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 1d4750a2a5f..cce00a6ae13 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -101,12 +101,12 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) { #define C_METHOD_ENGINE_GET_SINGLETON C_NS_MONOUTILS ".EngineGetSingleton" #define C_NS_MONOMARSHAL "Marshaling" -#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL ".mono_object_to_variant" -#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL ".variant_to_mono_object" -#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL ".mono_string_to_godot" -#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL ".mono_string_from_godot" -#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL ".mono_array_to_" #m_type -#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "." #m_type "_to_mono_array" +#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL ".ConvertManagedObjectToVariant" +#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL ".ConvertVariantToManagedObject" +#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL ".ConvertStringToNative" +#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL ".ConvertStringToManaged" +#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL ".ConvertSystemArrayToNative" #m_type +#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL ".ConvertNative" #m_type "ToSystemArray" #define C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToNative" #define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToManaged" #define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToNative" @@ -122,7 +122,7 @@ void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::Ty // any of the changes done here to the 'uint32_t' type interface as well. r_enum_itype.cs_type = r_enum_itype.proxy_name; - r_enum_itype.cs_in = "(int)%s"; + r_enum_itype.cs_in_expr = "(int)%0"; r_enum_itype.cs_out = "%5return (%2)%0(%1);"; { @@ -391,23 +391,23 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(tag); xml_output.append(""); } else if (tag == "PackedByteArray") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedInt32Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedInt64Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedFloat32Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedFloat64Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedStringArray") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedVector2Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedVector3Array") { - xml_output.append(""); + xml_output.append("[]"); } else if (tag == "PackedColorArray") { - xml_output.append(""); + xml_output.append("[]"); } else { const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); @@ -1380,6 +1380,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str "#pragma warning disable CS1573 // Disable warning: " "'Parameter has no matching param tag in the XML comment'\n"); + output.append("\n#nullable disable\n"); + output.append("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); const DocData::ClassDoc *class_doc = itype.class_doc; @@ -1413,20 +1415,17 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } output.append(itype.proxy_name); - if (itype.is_singleton) { - output.append("\n"); - } else if (is_derived_type) { + if (is_derived_type && !itype.is_singleton) { if (obj_types.has(itype.base_name)) { output.append(" : "); output.append(obj_types[itype.base_name].proxy_name); - output.append("\n"); } else { ERR_PRINT("Base type '" + itype.base_name.operator String() + "' does not exist, for class '" + itype.name + "'."); return ERR_INVALID_DATA; } } - output.append(INDENT1 "{"); + output.append("\n" INDENT1 "{"); // Add constants @@ -1546,7 +1545,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add native constructor static field output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n" - << INDENT2 "private static unsafe readonly delegate* unmanaged " + << INDENT2 "private static readonly unsafe delegate* unmanaged " << CS_STATIC_FIELD_NATIVE_CTOR " = " ICALL_CLASSDB_GET_CONSTRUCTOR << "(" BINDINGS_NATIVE_NAME_FIELD ");\n"; } @@ -1608,7 +1607,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // TODO: string is ok for now. But should be replaced with StringName in the future for performance. output << MEMBER_BEGIN "internal " << (is_derived_type ? "override" : "virtual") - << " unsafe bool InternalGodotScriptCall(string method, godot_variant** args, " + << " bool InternalGodotScriptCall(string method, NativeVariantPtrArgs args, " << "int argCount, out godot_variant ret)\n" << INDENT2 "{\n"; @@ -1646,10 +1645,10 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) { String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); - output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args[" + output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args[" << itos(i) << "], typeof(" << arg_type->cs_type << ")))"; } else { - output << "(" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args[" + output << "(" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args[" << itos(i) << "], typeof(" << arg_type->cs_type << "))"; } } @@ -1658,7 +1657,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str if (imethod.return_type.cname != name_cache.type_void) { // TODO: static marshaling (no reflection, no runtime type checks) - output << INDENT4 "ret = Marshaling.mono_object_to_variant(retBoxed);\n"; + output << INDENT4 "ret = Marshaling.ConvertManagedObjectToVariant(retBoxed);\n"; output << INDENT4 "return true;\n"; } else { output << INDENT4 "ret = default;\n"; @@ -1858,11 +1857,17 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf String arguments_sig; StringBuilder cs_in_statements; - bool cs_in_is_unsafe = false; + bool cs_in_expr_is_unsafe = false; String icall_params = method_bind_field; + if (!p_imethod.is_static) { - icall_params += ", " + sformat(p_itype.cs_in, "this"); + if (p_itype.cs_in.size()) { + cs_in_statements << sformat(p_itype.cs_in, p_itype.c_type, "this", + String(), String(), String(), INDENT3); + } + + icall_params += ", " + sformat(p_itype.cs_in_expr, "this"); } StringBuilder default_args_doc; @@ -1924,10 +1929,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) { // The default value of an argument must be constant. Otherwise we make it Nullable and do the following: // Type arg_in = arg.HasValue ? arg.Value : ; - String arg_in = iarg.name; - arg_in += "_in"; + String arg_or_defval_local = iarg.name; + arg_or_defval_local += "OrDefVal"; - cs_in_statements << INDENT3 << arg_cs_type << " " << arg_in << " = " << iarg.name; + cs_in_statements << INDENT3 << arg_cs_type << " " << arg_or_defval_local << " = " << iarg.name; if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { cs_in_statements << ".HasValue ? "; @@ -1952,7 +1957,16 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf cs_in_statements << def_arg << ";\n"; - icall_params += arg_type->cs_in.is_empty() ? arg_in : sformat(arg_type->cs_in, arg_in); + if (arg_type->cs_in.size()) { + cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, arg_or_defval_local, + String(), String(), String(), INDENT3); + } + + if (arg_type->cs_in_expr.is_empty()) { + icall_params += arg_or_defval_local; + } else { + icall_params += sformat(arg_type->cs_in_expr, arg_or_defval_local, arg_type->c_type); + } // Apparently the name attribute must not include the @ String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name; @@ -1961,10 +1975,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf default_args_doc.append(MEMBER_BEGIN "/// If the parameter is null, then the default value is " + param_def_arg + "."); } else { - icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name); + if (arg_type->cs_in.size()) { + cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, iarg.name, + String(), String(), String(), INDENT3); + } + + icall_params += arg_type->cs_in_expr.is_empty() ? iarg.name : sformat(arg_type->cs_in_expr, iarg.name, arg_type->c_type); } - cs_in_is_unsafe |= arg_type->cs_in_is_unsafe; + cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe; } // Generate method @@ -2034,7 +2053,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append("virtual "); } - if (cs_in_is_unsafe) { + if (cs_in_expr_is_unsafe) { p_output.append("unsafe "); } @@ -2082,7 +2101,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf im_call += "."; im_call += im_icall->name; - if (p_imethod.arguments.size()) { + if (p_imethod.arguments.size() && cs_in_statements.get_string_length() > 0) { p_output.append(cs_in_statements.as_string()); } @@ -2319,8 +2338,6 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, auto generate_call_and_return_stmts = [&](const char *base_indent) { if (p_icall.is_vararg) { - r_output << base_indent << "godot_variant_call_error vcall_error;\n"; - // MethodBind Call r_output << base_indent; @@ -2341,12 +2358,12 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, r_output << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_call(" << CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE) << ", " << (p_icall.get_arguments_count() ? "(godot_variant**)" C_LOCAL_PTRCALL_ARGS : "null") - << ", total_length, &vcall_error);\n"; + << ", total_length, out _);\n"; if (!ret_void) { if (return_type->cname != name_cache.type_Variant) { if (return_type->cname == name_cache.enum_Error) { - r_output << base_indent << C_LOCAL_RET " = VariantUtils.ConvertToInt64(&" C_LOCAL_VARARG_RET ");\n"; + r_output << base_indent << C_LOCAL_RET " = VariantUtils.ConvertToInt64(" C_LOCAL_VARARG_RET ");\n"; } else { // TODO: Use something similar to c_in_vararg (see usage above, with error if not implemented) CRASH_NOW_MSG("Custom VarArg return type not implemented: " + return_type->name); @@ -2384,9 +2401,9 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, r_output << INDENT3 "int vararg_length = " << vararg_arg << ".Length;\n" << INDENT3 "int total_length = " << real_argc_str << " + vararg_length;\n"; - r_output << INDENT3 "Span varargs_span = vararg_length <= VarArgsSpanThreshold ?\n" - << INDENT4 "stackalloc godot_variant[VarArgsSpanThreshold].Cleared() :\n" - << INDENT4 "new godot_variant[vararg_length];\n"; + r_output << INDENT3 "Span varargs_span = vararg_length <= VarArgsSpanThreshold ?\n" + << INDENT4 "stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :\n" + << INDENT4 "new godot_variant.movable[vararg_length];\n"; r_output << INDENT3 "Span " C_LOCAL_PTRCALL_ARGS "_span = total_length <= VarArgsSpanThreshold ?\n" << INDENT4 "stackalloc IntPtr[VarArgsSpanThreshold] :\n" @@ -2394,7 +2411,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, r_output << INDENT3 "using var variantSpanDisposer = new VariantSpanDisposer(varargs_span);\n"; - r_output << INDENT3 "fixed (godot_variant* varargs = &MemoryMarshal.GetReference(varargs_span))\n" + r_output << INDENT3 "fixed (godot_variant* varargs = &MemoryMarshal.GetReference(varargs_span).DangerousSelfRef)\n" << INDENT3 "fixed (IntPtr* " C_LOCAL_PTRCALL_ARGS " = " "&MemoryMarshal.GetReference(" C_LOCAL_PTRCALL_ARGS "_span))\n" << OPEN_BLOCK_L3; @@ -2678,14 +2695,14 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.c_out = "%5return "; itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED; - itype.c_out += itype.is_ref_counted ? "(%1._reference);\n" : "(%1);\n"; + itype.c_out += itype.is_ref_counted ? "(%1.Reference);\n" : "(%1);\n"; itype.cs_type = itype.proxy_name; if (itype.is_singleton) { - itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")"; + itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")"; } else { - itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)"; + itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)"; } itype.cs_out = "%5return (%2)%0(%1);"; @@ -3128,8 +3145,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar case Variant::STRING_NAME: case Variant::NODE_PATH: if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) { - r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\""; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + if (r_iarg.default_argument.length() > 0) { + r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\""; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + } else { + // No need for a special `in` statement to change `null` to `""`. Marshaling takes care of this already. + r_iarg.default_argument = "null"; + } } else { CRASH_COND(r_iarg.type.cname != name_cache.type_String); r_iarg.default_argument = "\"" + r_iarg.default_argument + "\""; @@ -3175,8 +3197,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.default_argument = "null"; break; case Variant::DICTIONARY: - r_iarg.default_argument = "new %s()"; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + ERR_FAIL_COND_V_MSG(!p_val.operator Dictionary().is_empty(), false, + "Default value of type 'Dictionary' must be an empty dictionary."); + // The [cs_in] expression already interprets null values as empty dictionaries. + r_iarg.default_argument = "null"; + r_iarg.def_param_mode = ArgumentInterface::CONSTANT; break; case Variant::RID: ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_RID, false, @@ -3188,8 +3213,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.default_argument = "default"; break; case Variant::ARRAY: - r_iarg.default_argument = "new %s { }"; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + ERR_FAIL_COND_V_MSG(!p_val.operator Array().is_empty(), false, + "Default value of type 'Array' must be an empty array."); + // The [cs_in] expression already interprets null values as empty arrays. + r_iarg.default_argument = "null"; + r_iarg.def_param_mode = ArgumentInterface::CONSTANT; break; case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: @@ -3285,8 +3313,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface::create_value_type(String(#m_type)); \ itype.c_type_in = #m_type "*"; \ itype.c_type_out = itype.cs_type; \ - itype.cs_in = "&%s"; \ - itype.cs_in_is_unsafe = true; \ + itype.cs_in_expr = "&%0"; \ + itype.cs_in_expr_is_unsafe = true; \ builtin_types.insert(itype.cname, itype); \ } @@ -3311,7 +3339,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { // bool itype = TypeInterface::create_value_type(String("bool")); - itype.cs_in = "%s.ToGodotBool()"; + itype.cs_in_expr = "%0.ToGodotBool()"; itype.cs_out = "%5return %0(%1).ToBool();"; itype.c_type = "godot_bool"; itype.c_type_in = itype.c_type; @@ -3411,15 +3439,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "StringName"; itype.cs_type = itype.proxy_name; - itype.cs_in = "ref %0.NativeValue"; + itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)"; // Cannot pass null StringName to ptrcall - itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_string_name_new_copy(%1);\n"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; - itype.c_arg_in = "&%s_in"; + itype.c_arg_in = "&%s"; itype.c_type = "godot_string_name"; - itype.c_type_in = "ref " + itype.c_type; + itype.c_type_in = itype.c_type; itype.c_type_out = itype.cs_type; - itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(ref %1);\n"; + itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(%1);\n"; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; builtin_types.insert(itype.cname, itype); @@ -3430,13 +3457,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "NodePath"; itype.cs_type = itype.proxy_name; - itype.cs_in = "ref %0.NativeValue"; + itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)"; // Cannot pass null NodePath to ptrcall - itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_node_path_new_copy(%1);\n"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; - itype.c_arg_in = "&%s_in"; + itype.c_arg_in = "&%s"; itype.c_type = "godot_node_path"; - itype.c_type_in = "ref " + itype.c_type; + itype.c_type_in = itype.c_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; @@ -3461,7 +3487,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = "object"; itype.cs_type = itype.proxy_name; itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n"; - itype.c_out = "%5return " C_METHOD_MANAGED_FROM_VARIANT "(&%1);\n"; + itype.c_out = "%5return " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n"; itype.c_arg_in = "&%s_in"; itype.c_type = "godot_variant"; itype.c_type_in = itype.cs_type; @@ -3471,9 +3497,9 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { // Callable itype = TypeInterface::create_value_type(String("Callable")); - itype.cs_in = "ref %s"; + itype.cs_in_expr = "ref %0"; itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(ref %1);\n"; - itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(&%1);\n"; + itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(in %1);\n"; itype.c_arg_in = "&%s_in"; itype.c_type = "godot_callable"; itype.c_type_in = "ref " + itype.cs_type; @@ -3487,7 +3513,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "SignalInfo"; itype.cs_type = itype.proxy_name; - itype.cs_in = "ref %s"; + itype.cs_in_expr = "ref %0"; itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(ref %1);\n"; itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(&%1);\n"; itype.c_arg_in = "&%s_in"; @@ -3503,6 +3529,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "object[]"; itype.cs_type = "params object[]"; + itype.cs_in_expr = "%0 ?? Array.Empty()"; // c_type, c_in and c_arg_in are hard-coded in the generator. // c_out and c_type_out are not applicable to VarArg. itype.c_arg_in = "&%s_in"; @@ -3517,7 +3544,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = #m_proxy_t "[]"; \ itype.cs_type = itype.proxy_name; \ itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \ - itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(&%1);\n"; \ + itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \ itype.c_arg_in = "&%s_in"; \ itype.c_type = #m_managed_type; \ itype.c_type_in = itype.proxy_name; \ @@ -3550,12 +3577,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = itype.name; itype.type_parameter_count = 1; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; - itype.cs_in = "ref %0.NativeValue"; - itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_array_new_copy(%1);\n"; + itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; - itype.c_arg_in = "&%s_in"; + itype.c_arg_in = "&%s"; itype.c_type = "godot_array"; - itype.c_type_in = "ref " + itype.c_type; + itype.c_type_in = itype.c_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; @@ -3575,12 +3601,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = itype.name; itype.type_parameter_count = 2; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; - itype.cs_in = "ref %0.NativeValue"; - itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_dictionary_new_copy(%1);\n"; + itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue"; itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n"; - itype.c_arg_in = "&%s_in"; + itype.c_arg_in = "&%s"; itype.c_type = "godot_dictionary"; - itype.c_type_in = "ref " + itype.c_type; + itype.c_type_in = itype.c_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index c9eb8e63178..d53e67896ec 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -265,9 +265,9 @@ class BindingsGenerator { // --- C INTERFACE --- /** - * One or more statements that manipulate the parameter before being passed as argument of a ptrcall. + * One or more statements that transform the parameter before being passed as argument of a ptrcall. * If the statement adds a local that must be passed as the argument instead of the parameter, - * the name of that local must be specified with [c_arg_in]. + * the expression with the name of that local must be specified with [c_arg_in]. * Formatting elements: * %0: [c_type] of the parameter * %1: name of the parameter @@ -277,7 +277,7 @@ class BindingsGenerator { String c_in; /** - * One or more statements that manipulate the parameter before being passed as argument of a vararg call. + * One or more statements that transform the parameter before being passed as argument of a vararg call. * If the statement adds a local that must be passed as the argument instead of the parameter, * the name of that local must be specified with [c_arg_in]. * Formatting elements: @@ -348,10 +348,23 @@ class BindingsGenerator { * An expression that overrides the way the parameter is passed to the internal call. * If empty, the parameter is passed as is. * Formatting elements: - * %0 or %s: name of the parameter + * %0: name of the parameter + * %1: [c_type] of the parameter + */ + String cs_in_expr; + bool cs_in_expr_is_unsafe = false; + + /** + * One or more statements that transform the parameter before being passed to the internal call. + * If the statement adds a local that must be passed as the argument instead of the parameter, + * the expression with the name of that local must be specified with [cs_in_expr]. + * Formatting elements: + * %0: [c_type] of the parameter + * %1: name of the parameter + * %2-4: reserved + * %5: indentation text */ String cs_in; - bool cs_in_is_unsafe = false; /** * One or more statements that determine how a variable of this type is returned from a method. diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig new file mode 100644 index 00000000000..d4e71b1bd95 --- /dev/null +++ b/modules/mono/glue/GodotSharp/.editorconfig @@ -0,0 +1,8 @@ +[**/Generated/**.cs] +# Validate parameter is non-null before using it +# Useful for generated code, as it disables nullable +dotnet_diagnostic.CA1062.severity = error +# CA1069: Enums should not have duplicate values +dotnet_diagnostic.CA1069.severity = none +# CA1708: Identifiers should differ by more than case +dotnet_diagnostic.CA1708.severity = none diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 2aa2ece803b..9fa221a0cca 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot.Collections @@ -14,14 +15,14 @@ namespace Godot.Collections /// public sealed class Array : IList, IDisposable { - public godot_array NativeValue; + internal godot_array.movable NativeValue; /// /// Constructs a new empty . /// public Array() { - NativeValue = NativeFuncs.godotsharp_array_new(); + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); } /// @@ -32,7 +33,7 @@ namespace Godot.Collections public Array(IEnumerable collection) : this() { if (collection == null) - throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); + throw new ArgumentNullException(nameof(collection)); foreach (object element in collection) Add(element); @@ -47,9 +48,9 @@ namespace Godot.Collections public Array(params object[] array) : this() { if (array == null) - throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); + throw new ArgumentNullException(nameof(array)); - NativeValue = NativeFuncs.godotsharp_array_new(); + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); int length = array.Length; Resize(length); @@ -60,7 +61,9 @@ namespace Godot.Collections private Array(godot_array nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_array.movable)(nativeValueToOwn.IsAllocated ? + nativeValueToOwn : + NativeFuncs.godotsharp_array_new()); } // Explicit name to make it very clear @@ -84,7 +87,7 @@ namespace Godot.Collections public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } /// @@ -95,7 +98,8 @@ namespace Godot.Collections public Array Duplicate(bool deep = false) { godot_array newArray; - NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep.ToGodotBool(), out newArray); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_duplicate(ref self, deep.ToGodotBool(), out newArray); return CreateTakingOwnershipOfDisposableValue(newArray); } @@ -104,12 +108,20 @@ namespace Godot.Collections /// /// The new size of the array. /// if successful, or an error code. - public Error Resize(int newSize) => NativeFuncs.godotsharp_array_resize(ref NativeValue, newSize); + public Error Resize(int newSize) + { + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_resize(ref self, newSize); + } /// /// Shuffles the contents of this into a random order. /// - public void Shuffle() => NativeFuncs.godotsharp_array_shuffle(ref NativeValue); + public void Shuffle() + { + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_shuffle(ref self); + } /// /// Concatenates these two s. @@ -119,6 +131,17 @@ namespace Godot.Collections /// A new Godot Array with the contents of both arrays. public static Array operator +(Array left, Array right) { + if (left == null) + { + if (right == null) + return new Array(); + + return right.Duplicate(deep: false); + } + + if (right == null) + return left.Duplicate(deep: false); + int leftCount = left.Count; int rightCount = right.Count; @@ -146,14 +169,15 @@ namespace Godot.Collections get { GetVariantBorrowElementAt(index, out godot_variant borrowElem); - return Marshaling.variant_to_mono_object(&borrowElem); + return Marshaling.ConvertVariantToManagedObject(borrowElem); } set { if (index < 0 || index >= Count) - throw new IndexOutOfRangeException(); - godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref NativeValue); - ptrw[index] = Marshaling.mono_object_to_variant(value); + throw new ArgumentOutOfRangeException(nameof(index)); + var self = (godot_array)NativeValue; + godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self); + ptrw[index] = Marshaling.ConvertManagedObjectToVariant(value); } } @@ -163,10 +187,11 @@ namespace Godot.Collections /// /// The object to add. /// The new size after adding the object. - public unsafe int Add(object value) + public int Add(object value) { - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - return NativeFuncs.godotsharp_array_add(ref NativeValue, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_add(ref self, variantValue); } /// @@ -187,10 +212,11 @@ namespace Godot.Collections /// /// The object to search for. /// The index of the object, or -1 if not found. - public unsafe int IndexOf(object value) + public int IndexOf(object value) { - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - return NativeFuncs.godotsharp_array_index_of(ref NativeValue, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_index_of(ref self, variantValue); } /// @@ -201,13 +227,14 @@ namespace Godot.Collections /// /// The index to insert at. /// The object to insert. - public unsafe void Insert(int index, object value) + public void Insert(int index, object value) { if (index < 0 || index > Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_array_insert(ref NativeValue, index, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_insert(ref self, index, variantValue); } /// @@ -229,9 +256,10 @@ namespace Godot.Collections public void RemoveAt(int index) { if (index < 0 || index > Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); - NativeFuncs.godotsharp_array_remove_at(ref NativeValue, index); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_remove_at(ref self, index); } // ICollection @@ -241,7 +269,7 @@ namespace Godot.Collections /// This is also known as the size or length of the array. /// /// The number of elements. - public int Count => NativeValue.Size; + public int Count => NativeValue.DangerousSelfRef.Size; object ICollection.SyncRoot => this; @@ -252,21 +280,21 @@ namespace Godot.Collections /// untyped C# array, starting at the given index. /// /// The array to copy to. - /// The index to start at. - public void CopyTo(System.Array array, int destIndex) + /// The index to start at. + public void CopyTo(System.Array array, int index) { if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); - if (destIndex < 0) + if (index < 0) { - throw new ArgumentOutOfRangeException(nameof(destIndex), + throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension."); } int count = Count; - if (array.Length < (destIndex + count)) + if (array.Length < (index + count)) { throw new ArgumentException( "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -276,9 +304,9 @@ namespace Godot.Collections { for (int i = 0; i < count; i++) { - object obj = Marshaling.variant_to_mono_object(&(*NativeValue._p)._arrayVector._ptr[i]); - array.SetValue(obj, destIndex); - destIndex++; + object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]); + array.SetValue(obj, index); + index++; } } } @@ -303,11 +331,12 @@ namespace Godot.Collections /// Converts this to a string. /// /// A string representation of this array. - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_array_to_string(ref NativeValue, &str); - return Marshaling.mono_string_from_godot(str); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_to_string(ref self, out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } /// @@ -316,7 +345,7 @@ namespace Godot.Collections internal void GetVariantBorrowElementAt(int index, out godot_variant elem) { if (index < 0 || index >= Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); GetVariantBorrowElementAtUnchecked(index, out elem); } @@ -325,7 +354,7 @@ namespace Godot.Collections /// internal unsafe void GetVariantBorrowElementAtUnchecked(int index, out godot_variant elem) { - elem = (*NativeValue._p)._arrayVector._ptr[index]; + elem = NativeValue.DangerousSelfRef.Elements[index]; } } @@ -344,11 +373,16 @@ namespace Godot.Collections /// /// The type of the array. [SuppressMessage("ReSharper", "RedundantExtendsListEntry")] + [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")] public sealed class Array : IList, ICollection, IEnumerable, IGenericGodotArray { private readonly Array _underlyingArray; - internal ref godot_array NativeValue => ref _underlyingArray.NativeValue; + internal ref godot_array.movable NativeValue + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _underlyingArray.NativeValue; + } // ReSharper disable StaticMemberInGenericType // Warning is about unique static fields being created for each generic type combination: @@ -376,7 +410,7 @@ namespace Godot.Collections public Array(IEnumerable collection) { if (collection == null) - throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); + throw new ArgumentNullException(nameof(collection)); _underlyingArray = new Array(collection); } @@ -389,9 +423,7 @@ namespace Godot.Collections public Array(params T[] array) : this() { if (array == null) - { - throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); - } + throw new ArgumentNullException(nameof(array)); _underlyingArray = new Array(array); } @@ -415,7 +447,7 @@ namespace Godot.Collections /// The typed array to convert. public static explicit operator Array(Array from) { - return from._underlyingArray; + return from?._underlyingArray; } /// @@ -454,6 +486,17 @@ namespace Godot.Collections /// A new Godot Array with the contents of both arrays. public static Array operator +(Array left, Array right) { + if (left == null) + { + if (right == null) + return new Array(); + + return right.Duplicate(deep: false); + } + + if (right == null) + return left.Duplicate(deep: false); + return new Array(left._underlyingArray + right._underlyingArray); } @@ -468,10 +511,7 @@ namespace Godot.Collections get { _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem); - unsafe - { - return (T)Marshaling.variant_to_mono_object_of_type(&borrowElem, TypeOfElements); - } + return (T)Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, TypeOfElements); } set => _underlyingArray[index] = value; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 437878818c7..e1e2df199bc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -167,7 +167,7 @@ namespace Godot case 2: return Column2; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -184,7 +184,7 @@ namespace Godot Column2 = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } @@ -386,7 +386,7 @@ namespace Godot case 2: return Row2; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } @@ -413,7 +413,7 @@ namespace Godot Row2 = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs index db27989bdb5..6bb1ba27e93 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs @@ -18,22 +18,24 @@ namespace Godot.Bridge if (godotObject == null) { *ret = default; - (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL; + (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL; return false.ToGodotBool(); } - using godot_string dest = default; - NativeFuncs.godotsharp_string_name_as_string(&dest, method); - string methodStr = Marshaling.mono_string_from_godot(dest); + NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, CustomUnsafe.AsRef(method)); + string methodStr; + using (dest) + methodStr = Marshaling.ConvertStringToManaged(dest); - bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant retValue); + bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, new NativeVariantPtrArgs(args), + argCount, out godot_variant retValue); if (!methodInvoked) { *ret = default; // This is important, as it tells Object::call that no method was called. // Otherwise, it would prevent Object::call from calling native methods. - (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD; + (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD; return false.ToGodotBool(); } @@ -60,12 +62,15 @@ namespace Godot.Bridge throw new InvalidOperationException(); var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(name)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name))); - if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value)) + if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection( + nameManaged.ToString(), CustomUnsafe.AsRef(value))) + { return true.ToGodotBool(); + } - object valueManaged = Marshaling.variant_to_mono_object(value); + object valueManaged = Marshaling.ConvertVariantToManagedObject(CustomUnsafe.AsRef(value)); return godotObject._Set(nameManaged, valueManaged).ToGodotBool(); } @@ -89,10 +94,10 @@ namespace Godot.Bridge throw new InvalidOperationException(); var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(name)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name))); if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(), - out godot_variant outRetValue)) + out godot_variant outRetValue)) { *outRet = outRetValue; return true.ToGodotBool(); @@ -106,7 +111,7 @@ namespace Godot.Bridge return false.ToGodotBool(); } - *outRet = Marshaling.mono_object_to_variant(ret); + *outRet = Marshaling.ConvertManagedObjectToVariant(ret); return true.ToGodotBool(); } catch (Exception e) @@ -158,7 +163,7 @@ namespace Godot.Bridge return; } - *outRes = Marshaling.mono_string_to_godot(resultStr); + *outRes = Marshaling.ConvertStringToNative(resultStr); *outValid = true.ToGodotBool(); } catch (Exception e) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 9655887e529..689d6cddbb5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -104,8 +104,8 @@ namespace Godot.Bridge for (int i = 0; i < paramCount; i++) { - invokeParams[i] = Marshaling.variant_to_mono_object_of_type( - args[i], parameters[i].ParameterType); + invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType( + *args[i], parameters[i].ParameterType); } ctor.Invoke(obj, invokeParams); @@ -149,7 +149,7 @@ namespace Godot.Bridge return; } - *outRes = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue); + *outRes = NativeFuncs.godotsharp_string_name_new_copy((godot_string_name)nativeName.NativeValue); } catch (Exception e) { @@ -177,7 +177,7 @@ namespace Godot.Bridge { // Performance is not critical here as this will be replaced with a generated dictionary. using var stringName = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(nativeTypeName)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName))); string nativeTypeNameStr = stringName.ToString(); if (nativeTypeNameStr[0] == '_') @@ -277,7 +277,8 @@ namespace Godot.Bridge *outOwnerIsNull = false.ToGodotBool(); - owner.InternalRaiseEventSignal(eventSignalName, args, argCount); + owner.InternalRaiseEventSignal(CustomUnsafe.AsRef(eventSignalName), + new NativeVariantPtrArgs(args), argCount); } catch (Exception e) { @@ -302,9 +303,10 @@ namespace Godot.Bridge // Legacy signals foreach (var signalDelegate in top - .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public) - .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) - .Where(@delegate => @delegate.GetCustomAttributes().OfType().Any())) + .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | + BindingFlags.Public) + .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) + .Where(@delegate => @delegate.GetCustomAttributes().OfType().Any())) { var invokeMethod = signalDelegate.GetMethod("Invoke"); @@ -315,7 +317,7 @@ namespace Godot.Bridge foreach (var parameters in invokeMethod.GetParameters()) { - var paramType = Marshaling.managed_to_variant_type( + var paramType = Marshaling.ConvertManagedTypeToVariantType( parameters.ParameterType, out bool nilIsVariant); signalParams.Add(new Dictionary() { @@ -341,8 +343,8 @@ namespace Godot.Bridge BindingFlags.NonPublic | BindingFlags.Public); foreach (var eventSignalField in fields - .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType)) - .Where(f => foundEventSignals.Contains(f.Name))) + .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType)) + .Where(f => foundEventSignals.Contains(f.Name))) { var delegateType = eventSignalField.FieldType; var invokeMethod = delegateType.GetMethod("Invoke"); @@ -354,7 +356,7 @@ namespace Godot.Bridge foreach (var parameters in invokeMethod.GetParameters()) { - var paramType = Marshaling.managed_to_variant_type( + var paramType = Marshaling.ConvertManagedTypeToVariantType( parameters.ParameterType, out bool nilIsVariant); signalParams.Add(new Dictionary() { @@ -370,7 +372,7 @@ namespace Godot.Bridge top = top.BaseType; } - *outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue); + *outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy((godot_dictionary)signals.NativeValue); } catch (Exception e) { @@ -387,7 +389,7 @@ namespace Godot.Bridge // Performance is not critical here as this will be replaced with source generators. using var signals = new Dictionary(); - string signalNameStr = Marshaling.mono_string_from_godot(*signalName); + string signalNameStr = Marshaling.ConvertStringToManaged(*signalName); Type top = _scriptBridgeMap[scriptPtr]; Type native = Object.InternalGetClassNativeBase(top); @@ -401,7 +403,7 @@ namespace Godot.Bridge .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) .Where(@delegate => @delegate.GetCustomAttributes().OfType().Any()) .Any(signalDelegate => signalDelegate.Name == signalNameStr) - ) + ) { return true.ToGodotBool(); } @@ -413,7 +415,7 @@ namespace Godot.Bridge BindingFlags.NonPublic | BindingFlags.Public) .Where(ev => ev.GetCustomAttributes().OfType().Any()) .Any(eventSignal => eventSignal.Name == signalNameStr) - ) + ) { return true.ToGodotBool(); } @@ -440,7 +442,7 @@ namespace Godot.Bridge if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType)) return false.ToGodotBool(); - string methodStr = Marshaling.mono_string_from_godot(*method); + string methodStr = Marshaling.ConvertStringToManaged(*method); if (deep.ToBool()) { @@ -517,7 +519,7 @@ namespace Godot.Bridge { try { - string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath); + string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath); if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo)) return false.ToGodotBool(); @@ -612,7 +614,8 @@ namespace Godot.Bridge } *outRpcFunctionsDest = - NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue); + NativeFuncs.godotsharp_dictionary_new_copy( + (godot_dictionary)((Dictionary)rpcFunctions).NativeValue); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index 2722b64e6d9..ef75ff446ac 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -1,5 +1,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Godot.NativeInterop; namespace Godot { @@ -24,7 +26,7 @@ namespace Godot /// } /// /// - public struct Callable + public readonly struct Callable { private readonly Object _target; private readonly StringName _method; @@ -34,10 +36,12 @@ namespace Godot /// Object that contains the method. /// public Object Target => _target; + /// /// Name of the method that will be called. /// public StringName Method => _method; + /// /// Delegate of the method that will be called. /// @@ -73,15 +77,43 @@ namespace Godot _delegate = @delegate; } + private const int VarArgsSpanThreshold = 5; + /// /// Calls the method represented by this . /// Arguments can be passed and should match the method's signature. /// /// Arguments that will be passed to the method call. /// The value returned by the method. - public object Call(params object[] args) + public unsafe object Call(params object[] args) { - return godot_icall_Callable_Call(ref this, args); + using godot_callable callable = Marshaling.ConvertCallableToNative(this); + + int argc = args.Length; + + Span argsStoreSpan = argc <= VarArgsSpanThreshold ? + stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() : + new godot_variant.movable[argc]; + + Span argsSpan = argc <= 10 ? + stackalloc IntPtr[argc] : + new IntPtr[argc]; + + using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan); + + fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef) + fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan)) + { + for (int i = 0; i < argc; i++) + { + varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + argsPtr[i] = new IntPtr(&varargs[i]); + } + + using godot_variant ret = NativeFuncs.godotsharp_callable_call(callable, + (godot_variant**)argsPtr, argc, out _); + return Marshaling.ConvertVariantToManagedObject(ret); + } } /// @@ -89,9 +121,33 @@ namespace Godot /// Arguments can be passed and should match the method's signature. /// /// Arguments that will be passed to the method call. - public void CallDeferred(params object[] args) + public unsafe void CallDeferred(params object[] args) { - godot_icall_Callable_CallDeferred(ref this, args); + using godot_callable callable = Marshaling.ConvertCallableToNative(this); + + int argc = args.Length; + + Span argsStoreSpan = argc <= VarArgsSpanThreshold ? + stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() : + new godot_variant.movable[argc]; + + Span argsSpan = argc <= 10 ? + stackalloc IntPtr[argc] : + new IntPtr[argc]; + + using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan); + + fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef) + fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan)) + { + for (int i = 0; i < argc; i++) + { + varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + argsPtr[i] = new IntPtr(&varargs[i]); + } + + NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc); + } } [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index a6324504fc4..ed0e1efd350 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -210,7 +210,7 @@ namespace Godot case 3: return a; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -230,7 +230,7 @@ namespace Godot a = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } @@ -841,7 +841,7 @@ namespace Godot return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1); } - private string ToHex32(float val) + private static string ToHex32(float val) { byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255)); return b.HexEncode(); @@ -849,7 +849,7 @@ namespace Godot internal static bool HtmlIsValid(string color) { - if (color.Length == 0) + if (string.IsNullOrEmpty(color)) { return false; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs index e446b3db1c2..39904b61548 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs @@ -18,7 +18,7 @@ namespace Godot else sb.Append(type); - sb.Append(" "); + sb.Append(' '); } [UnmanagedCallersOnly] @@ -55,15 +55,15 @@ namespace Godot if (methodBase is MethodInfo) sb.AppendTypeName(((MethodInfo)methodBase).ReturnType); - sb.Append(methodBase.DeclaringType.FullName); - sb.Append("."); + sb.Append(methodBase.DeclaringType?.FullName ?? ""); + sb.Append('.'); sb.Append(methodBase.Name); if (methodBase.IsGenericMethod) { Type[] genericParams = methodBase.GetGenericArguments(); - sb.Append("<"); + sb.Append('<'); for (int j = 0; j < genericParams.Length; j++) { @@ -73,10 +73,10 @@ namespace Godot sb.AppendTypeName(genericParams[j]); } - sb.Append(">"); + sb.Append('>'); } - sb.Append("("); + sb.Append('('); bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0; @@ -93,7 +93,7 @@ namespace Godot sb.AppendTypeName(parameter[i].ParameterType); } - sb.Append(")"); + sb.Append(')'); methodDecl = sb.ToString(); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 87c93e35f51..02ae392f479 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -48,13 +48,13 @@ namespace Godot for (uint i = 0; i < argc; i++) { - managedArgs[i] = Marshaling.variant_to_mono_object_of_type( - args[i], parameterInfos[i].ParameterType); + managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType( + *args[i], parameterInfos[i].ParameterType); } object invokeRet = @delegate.DynamicInvoke(managedArgs); - *outRet = Marshaling.mono_object_to_variant(invokeRet); + *outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index c21d53b4d4d..89fc2210b81 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections; using Godot.NativeInterop; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace Godot.Collections { @@ -15,14 +16,14 @@ namespace Godot.Collections IDictionary, IDisposable { - public godot_dictionary NativeValue; + internal godot_dictionary.movable NativeValue; /// /// Constructs a new empty . /// public Dictionary() { - NativeValue = NativeFuncs.godotsharp_dictionary_new(); + NativeValue = (godot_dictionary.movable)NativeFuncs.godotsharp_dictionary_new(); } /// @@ -33,7 +34,7 @@ namespace Godot.Collections public Dictionary(IDictionary dictionary) : this() { if (dictionary == null) - throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); + throw new ArgumentNullException(nameof(dictionary)); foreach (DictionaryEntry entry in dictionary) Add(entry.Key, entry.Value); @@ -41,7 +42,9 @@ namespace Godot.Collections private Dictionary(godot_dictionary nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_dictionary.movable)(nativeValueToOwn.IsAllocated ? + nativeValueToOwn : + NativeFuncs.godotsharp_dictionary_new()); } // Explicit name to make it very clear @@ -65,7 +68,7 @@ namespace Godot.Collections public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } /// @@ -76,7 +79,8 @@ namespace Godot.Collections public Dictionary Duplicate(bool deep = false) { godot_dictionary newDictionary; - NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep.ToGodotBool(), out newDictionary); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_duplicate(ref self, deep.ToGodotBool(), out newDictionary); return CreateTakingOwnershipOfDisposableValue(newDictionary); } @@ -90,7 +94,8 @@ namespace Godot.Collections get { godot_array keysArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray); return Array.CreateTakingOwnershipOfDisposableValue(keysArray); } } @@ -103,22 +108,25 @@ namespace Godot.Collections get { godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_values(ref NativeValue, out valuesArray); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray); return Array.CreateTakingOwnershipOfDisposableValue(valuesArray); } } private (Array keys, Array values, int count) GetKeyValuePairs() { + var self = (godot_dictionary)NativeValue; + godot_array keysArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray); + NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray); var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray); godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out valuesArray); + NativeFuncs.godotsharp_dictionary_keys(ref self, out valuesArray); var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray); - int count = NativeFuncs.godotsharp_dictionary_count(ref NativeValue); + int count = NativeFuncs.godotsharp_dictionary_count(ref self); return (keys, values, count); } @@ -131,16 +139,17 @@ namespace Godot.Collections /// Returns the object at the given . /// /// The object at the given . - public unsafe object this[object key] + public object this[object key] { get { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref NativeValue, &variantKey, - out godot_variant value).ToBool()) + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, + out godot_variant value).ToBool()) { using (value) - return Marshaling.variant_to_mono_object(&value); + return Marshaling.ConvertVariantToManagedObject(value); } else { @@ -149,9 +158,10 @@ namespace Godot.Collections } set { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_dictionary_set_value(ref NativeValue, &variantKey, &variantValue); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_set_value(ref self, variantKey, variantValue); } } @@ -161,31 +171,38 @@ namespace Godot.Collections /// /// The key at which to add the object. /// The object to add. - public unsafe void Add(object key, object value) + public void Add(object key, object value) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool()) + var self = (godot_dictionary)NativeValue; + + if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool()) throw new ArgumentException("An element with the same key already exists", nameof(key)); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_dictionary_add(ref NativeValue, &variantKey, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue); } /// /// Erases all items from this . /// - public void Clear() => NativeFuncs.godotsharp_dictionary_clear(ref NativeValue); + public void Clear() + { + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_clear(ref self); + } /// /// Checks if this contains the given key. /// /// The key to look for. /// Whether or not this dictionary contains the given key. - public unsafe bool Contains(object key) + public bool Contains(object key) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool(); } /// @@ -198,10 +215,11 @@ namespace Godot.Collections /// Removes an element from this by key. /// /// The key of the element to remove. - public unsafe void Remove(object key) + public void Remove(object key) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - NativeFuncs.godotsharp_dictionary_remove_key(ref NativeValue, &variantKey); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey); } // ICollection @@ -215,7 +233,14 @@ namespace Godot.Collections /// This is also known as the size or length of the dictionary. /// /// The number of elements. - public int Count => NativeFuncs.godotsharp_dictionary_count(ref NativeValue); + public int Count + { + get + { + var self = (godot_dictionary)NativeValue; + return NativeFuncs.godotsharp_dictionary_count(ref self); + } + } /// /// Copies the elements of this to the given @@ -279,17 +304,19 @@ namespace Godot.Collections } } - private unsafe void UpdateEntry() + private void UpdateEntry() { _dirty = false; - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _dictionary.NativeValue, _index, + var self = (godot_dictionary)_dictionary.NativeValue; + NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, _index, out godot_variant key, out godot_variant value); using (key) using (value) { - _entry = new DictionaryEntry(Marshaling.variant_to_mono_object(&key), - Marshaling.variant_to_mono_object(&value)); + // FIXME: DictionaryEntry keys cannot be null, but Godot dictionaries allow null keys + _entry = new DictionaryEntry(Marshaling.ConvertVariantToManagedObject(key)!, + Marshaling.ConvertVariantToManagedObject(value)); } } @@ -315,11 +342,12 @@ namespace Godot.Collections /// Converts this to a string. /// /// A string representation of this dictionary. - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_dictionary_to_string(ref NativeValue, &str); - return Marshaling.mono_string_from_godot(str); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_to_string(ref self, out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } } @@ -345,7 +373,11 @@ namespace Godot.Collections { private readonly Dictionary _underlyingDict; - internal ref godot_dictionary NativeValue => ref _underlyingDict.NativeValue; + internal ref godot_dictionary.movable NativeValue + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _underlyingDict.NativeValue; + } // ReSharper disable StaticMemberInGenericType // Warning is about unique static fields being created for each generic type combination: @@ -375,10 +407,10 @@ namespace Godot.Collections /// A new Godot Dictionary. public Dictionary(IDictionary dictionary) { - _underlyingDict = new Dictionary(); - if (dictionary == null) - throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); + throw new ArgumentNullException(nameof(dictionary)); + + _underlyingDict = new Dictionary(); foreach (KeyValuePair entry in dictionary) Add(entry.Key, entry.Value); @@ -405,7 +437,7 @@ namespace Godot.Collections /// The typed dictionary to convert. public static explicit operator Dictionary(Dictionary from) { - return from._underlyingDict; + return from?._underlyingDict; } /// @@ -428,19 +460,17 @@ namespace Godot.Collections { get { - unsafe + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant value).ToBool()) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant value).ToBool()) - { - using (value) - return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues); - } - else - { - throw new KeyNotFoundException(); - } + using (value) + return (TValue)Marshaling.ConvertVariantToManagedObjectOfType(value, TypeOfValues); + } + else + { + throw new KeyNotFoundException(); } } set => _underlyingDict[key] = value; @@ -454,7 +484,8 @@ namespace Godot.Collections get { godot_array keyArray; - NativeFuncs.godotsharp_dictionary_keys(ref _underlyingDict.NativeValue, out keyArray); + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray); return Array.CreateTakingOwnershipOfDisposableValue(keyArray); } } @@ -467,21 +498,23 @@ namespace Godot.Collections get { godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_values(ref _underlyingDict.NativeValue, out valuesArray); + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray); return Array.CreateTakingOwnershipOfDisposableValue(valuesArray); } } - private unsafe KeyValuePair GetKeyValuePair(int index) + private KeyValuePair GetKeyValuePair(int index) { - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _underlyingDict.NativeValue, index, + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index, out godot_variant key, out godot_variant value); using (key) using (value) { - return new KeyValuePair((TKey)Marshaling.variant_to_mono_object(&key), - (TValue)Marshaling.variant_to_mono_object(&value)); + return new KeyValuePair((TKey)Marshaling.ConvertVariantToManagedObject(key), + (TValue)Marshaling.ConvertVariantToManagedObject(value)); } } @@ -510,10 +543,11 @@ namespace Godot.Collections /// Removes an element from this by key. /// /// The key of the element to remove. - public unsafe bool Remove(TKey key) + public bool Remove(TKey key) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool(); } /// @@ -522,16 +556,17 @@ namespace Godot.Collections /// The key of the element to get. /// The value at the given . /// If an object was found for the given . - public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant retValue).ToBool(); using (retValue) { value = found ? - (TValue)Marshaling.variant_to_mono_object_of_type(&retValue, TypeOfValues) : + (TValue)Marshaling.ConvertVariantToManagedObjectOfType(retValue, TypeOfValues) : default; } @@ -562,19 +597,20 @@ namespace Godot.Collections _underlyingDict.Clear(); } - unsafe bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant retValue).ToBool(); using (retValue) { if (!found) return false; - using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value); - return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool(); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool(); } } @@ -606,22 +642,23 @@ namespace Godot.Collections } } - unsafe bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant retValue).ToBool(); using (retValue) { if (!found) return false; - using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value); - if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool()) + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool()) { return NativeFuncs.godotsharp_dictionary_remove_key( - ref _underlyingDict.NativeValue, &variantKey).ToBool(); + ref self, variantKey).ToBool(); } return false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs index 340780bb45a..4094ceeb227 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs @@ -35,17 +35,14 @@ namespace Godot if (!IsInstanceValid(obj)) return null; - using godot_ref weakRef = default; - - unsafe + NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef); + using (weakRef) { - NativeFuncs.godotsharp_weakref(GetPtr(obj), &weakRef); + if (weakRef.IsNull) + return null; + + return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference); } - - if (weakRef.IsNull) - return null; - - return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef._reference); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs index 17bca19fab2..fa8a1c64029 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using Godot.Collections; using Godot.NativeInterop; @@ -11,7 +10,7 @@ namespace Godot /// Returns a list of all nodes assigned to the given . /// /// The type to cast to. Should be a descendant of . - public unsafe Array GetNodesInGroup(StringName group) where T : class + public Array GetNodesInGroup(StringName group) where T : class { var array = GetNodesInGroup(group); @@ -29,19 +28,18 @@ namespace Godot BindingFlags.Public | BindingFlags.NonPublic); var nativeName = (StringName)field!.GetValue(null); - godot_string_name nativeNameAux = nativeName.NativeValue; - godot_array inputAux = array.NativeValue; - godot_array filteredArray; - NativeFuncs.godotsharp_array_filter_godot_objects_by_native( - &nativeNameAux, &inputAux, &filteredArray); + var nativeNameSelf = (godot_string_name)nativeName!.NativeValue; + var inputSelf = (godot_array)array.NativeValue; + NativeFuncs.godotsharp_array_filter_godot_objects_by_native(nativeNameSelf, inputSelf, + out godot_array filteredArray); return Array.CreateTakingOwnershipOfDisposableValue(filteredArray); } else { // Custom derived type - godot_array inputAux = array.NativeValue; - godot_array filteredArray; - NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray); + var inputSelf = (godot_array)array.NativeValue; + NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(inputSelf, + out godot_array filteredArray); var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 39271d3daf6..02ae32f46ec 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -26,12 +26,12 @@ namespace Godot /// Byte array that will be decoded to a Variant. /// If objects should be decoded. /// The decoded Variant. - public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false) + public static object Bytes2Var(byte[] bytes, bool allowObjects = false) { - using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes); - using godot_variant ret = default; - NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects.ToGodotBool(), &ret); - return Marshaling.variant_to_mono_object(&ret); + using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes); + NativeFuncs.godotsharp_bytes2var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// @@ -49,12 +49,12 @@ namespace Godot /// /// /// The Variant converted to the given . - public static unsafe object Convert(object what, Variant.Type type) + public static object Convert(object what, Variant.Type type) { - using var whatVariant = Marshaling.mono_object_to_variant(what); - using godot_variant ret = default; - NativeFuncs.godotsharp_convert(&whatVariant, (int)type, &ret); - return Marshaling.variant_to_mono_object(&ret); + using var whatVariant = Marshaling.ConvertManagedObjectToVariant(what); + NativeFuncs.godotsharp_convert(whatVariant, (int)type, out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// @@ -88,10 +88,10 @@ namespace Godot /// /// Variable that will be hashed. /// Hash of the variable passed. - public static unsafe int Hash(object var) + public static int Hash(object var) { - using var variant = Marshaling.mono_object_to_variant(var); - return NativeFuncs.godotsharp_hash(&variant); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + return NativeFuncs.godotsharp_hash(variant); } /// @@ -207,10 +207,10 @@ namespace Godot /// /// /// Error message. - public static unsafe void PushError(string message) + public static void PushError(string message) { - using var godotStr = Marshaling.mono_string_to_godot(message); - NativeFuncs.godotsharp_pusherror(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(message); + NativeFuncs.godotsharp_pusherror(godotStr); } /// @@ -220,10 +220,10 @@ namespace Godot /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call /// /// Warning message. - public static unsafe void PushWarning(string message) + public static void PushWarning(string message) { - using var godotStr = Marshaling.mono_string_to_godot(message); - NativeFuncs.godotsharp_pushwarning(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(message); + NativeFuncs.godotsharp_pushwarning(godotStr); } /// @@ -242,11 +242,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void Print(params object[] what) + public static void Print(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_print(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_print(godotStr); } /// @@ -273,11 +273,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void PrintRich(params object[] what) + public static void PrintRich(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_print_rich(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_print_rich(godotStr); } /// @@ -297,11 +297,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void PrintErr(params object[] what) + public static void PrintErr(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printerr(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printerr(godotStr); } /// @@ -319,11 +319,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void PrintRaw(params object[] what) + public static void PrintRaw(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printraw(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printraw(godotStr); } /// @@ -335,11 +335,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void PrintS(params object[] what) + public static void PrintS(params object[] what) { string str = string.Join(' ', GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_prints(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_prints(godotStr); } /// @@ -351,11 +351,11 @@ namespace Godot /// /// /// Arguments that will be printed. - public static unsafe void PrintT(params object[] what) + public static void PrintT(params object[] what) { string str = string.Join('\t', GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printt(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printt(godotStr); } /// @@ -520,12 +520,12 @@ namespace Godot /// /// Arguments that will converted to string. /// The string formed by the given arguments. - public static unsafe string Str(params object[] what) + public static string Str(params object[] what) { - using var whatGodotArray = Marshaling.mono_array_to_Array(what); - using godot_string ret = default; - NativeFuncs.godotsharp_str(&whatGodotArray, &ret); - return Marshaling.mono_string_from_godot(ret); + using var whatGodotArray = Marshaling.ConvertSystemArrayToNativeGodotArray(what); + NativeFuncs.godotsharp_str(whatGodotArray, out godot_string ret); + using (ret) + return Marshaling.ConvertStringToManaged(ret); } /// @@ -540,12 +540,12 @@ namespace Godot /// /// String that will be converted to Variant. /// The decoded Variant. - public static unsafe object Str2Var(string str) + public static object Str2Var(string str) { - using var godotStr = Marshaling.mono_string_to_godot(str); - using godot_variant ret = default; - NativeFuncs.godotsharp_str2var(&godotStr, &ret); - return Marshaling.variant_to_mono_object(&ret); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_str2var(godotStr, out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// @@ -557,13 +557,12 @@ namespace Godot /// Variant that will be encoded. /// If objects should be serialized. /// The Variant encoded as an array of bytes. - public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false) + public static byte[] Var2Bytes(object var, bool fullObjects = false) { - using var variant = Marshaling.mono_object_to_variant(var); - using godot_packed_byte_array varBytes = default; - NativeFuncs.godotsharp_var2bytes(&variant, fullObjects.ToGodotBool(), &varBytes); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + NativeFuncs.godotsharp_var2bytes(variant, fullObjects.ToGodotBool(), out var varBytes); using (varBytes) - return Marshaling.PackedByteArray_to_mono_array(&varBytes); + return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes); } /// @@ -583,12 +582,12 @@ namespace Godot /// /// Variant that will be converted to string. /// The Variant encoded as a string. - public static unsafe string Var2Str(object var) + public static string Var2Str(object var) { - using var variant = Marshaling.mono_object_to_variant(var); - using godot_string ret = default; - NativeFuncs.godotsharp_var2str(&variant, &ret); - return Marshaling.mono_string_from_godot(ret); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + NativeFuncs.godotsharp_var2str(variant, out godot_string ret); + using (ret) + return Marshaling.ConvertStringToManaged(ret); } /// @@ -597,7 +596,7 @@ namespace Godot /// The for the given . public static Variant.Type TypeToVariantType(Type type) { - return Marshaling.managed_to_variant_type(type, out bool _); + return Marshaling.ConvertManagedTypeToVariantType(type, out bool _); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs index 0942d8f722b..ef20819d62f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -10,7 +10,10 @@ using System.Runtime.InteropServices; namespace Godot.NativeInterop { - internal static class GodotBoolExtensions + // NOTES: + // ref structs cannot implement interfaces, but they still work in `using` directives if they declare Dispose() + + public static class GodotBoolExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe godot_bool ToGodotBool(this bool @bool) @@ -35,9 +38,9 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_ref : IDisposable + public ref struct godot_ref { - internal IntPtr _reference; + private IntPtr _reference; public void Dispose() { @@ -47,7 +50,17 @@ namespace Godot.NativeInterop _reference = IntPtr.Zero; } - public bool IsNull => _reference == IntPtr.Zero; + public readonly IntPtr Reference + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _reference; + } + + public readonly bool IsNull + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _reference == IntPtr.Zero; + } } [SuppressMessage("ReSharper", "InconsistentNaming")] @@ -63,41 +76,53 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_variant_call_error + public ref struct godot_variant_call_error { - public godot_variant_call_error_error error; - public int argument; - public int expected; + private godot_variant_call_error_error error; + private int argument; + private int expected; + + public godot_variant_call_error_error Error + { + readonly get => error; + set => error = value; + } + + public int Argument + { + readonly get => argument; + set => argument = value; + } + + public Godot.Variant.Type Expected + { + readonly get => (Godot.Variant.Type)expected; + set => expected = (int)value; + } } [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - public struct godot_variant : IDisposable + public ref struct godot_variant { // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. [FieldOffset(0)] private int _typeField; // There's padding here - [FieldOffset(8)] internal godot_variant_data _data; - - public Variant.Type _type - { - get => (Variant.Type)_typeField; - set => _typeField = (int)value; - } + [FieldOffset(8)] private godot_variant_data _data; [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - internal unsafe struct godot_variant_data + private unsafe ref struct godot_variant_data { [FieldOffset(0)] public godot_bool _bool; [FieldOffset(0)] public long _int; [FieldOffset(0)] public double _float; - [FieldOffset(0)] public Transform2D* _transform2d; + [FieldOffset(0)] public Transform2D* _transform2D; [FieldOffset(0)] public AABB* _aabb; [FieldOffset(0)] public Basis* _basis; - [FieldOffset(0)] public Transform3D* _transform3d; + [FieldOffset(0)] public Transform3D* _transform3D; [FieldOffset(0)] public Vector4* _vector4; [FieldOffset(0)] public Vector4i* _vector4i; [FieldOffset(0)] public Projection* _projection; @@ -125,7 +150,7 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - internal struct godot_variant_obj_data + public struct godot_variant_obj_data { public UInt64 id; public IntPtr obj; @@ -133,7 +158,7 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - private struct godot_variant_data_mem + public struct godot_variant_data_mem { #pragma warning disable 169 private real_t _mem0; @@ -144,9 +169,225 @@ namespace Godot.NativeInterop } } + public Variant.Type Type + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => (Variant.Type)_typeField; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _typeField = (int)value; + } + + public godot_bool Bool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._bool; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._bool = value; + } + + public long Int + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._int; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._int = value; + } + + public double Float + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._float; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._float = value; + } + + public readonly unsafe Transform2D* Transform2D + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._transform2D; + } + + public readonly unsafe AABB* AABB + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._aabb; + } + + public readonly unsafe Basis* Basis + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._basis; + } + + public readonly unsafe Transform3D* Transform3D + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._transform3D; + } + + public readonly unsafe Vector4* Vector4 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._vector4; + } + + public readonly unsafe Vector4i* Vector4i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._vector4i; + } + + public readonly unsafe Projection* Projection + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._projection; + } + + public godot_string_name StringName + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_string_name; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_string_name = value; + } + + public godot_string String + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_string; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_string = value; + } + + public Vector3 Vector3 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector3; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector3 = value; + } + + public Vector3i Vector3i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector3i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector3i = value; + } + + public Vector2 Vector2 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector2; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector2 = value; + } + + public Vector2i Vector2i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector2i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector2i = value; + } + + public Rect2 Rect2 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rect2; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rect2 = value; + } + + public Rect2i Rect2i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rect2i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rect2i = value; + } + + public Plane Plane + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_plane; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_plane = value; + } + + public Quaternion Quaternion + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_quaternion; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_quaternion = value; + } + + public Color Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_color; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_color = value; + } + + public godot_node_path NodePath + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_node_path; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_node_path = value; + } + + public RID RID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rid; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rid = value; + } + + public godot_callable Callable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_callable; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_callable = value; + } + + public godot_signal Signal + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_signal; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_signal = value; + } + + public godot_dictionary Dictionary + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_dictionary; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_dictionary = value; + } + + public godot_array Array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_array; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_array = value; + } + + public readonly IntPtr Object + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._m_obj_data.obj; + } + public void Dispose() { - switch (_type) + switch (Type) { case Variant.Type.Nil: case Variant.Type.Bool: @@ -166,15 +407,36 @@ namespace Godot.NativeInterop } NativeFuncs.godotsharp_variant_destroy(ref this); - _type = Variant.Type.Nil; + Type = Variant.Type.Nil; + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. + [FieldOffset(0)] private int _typeField; + + // There's padding here + + [FieldOffset(8)] private godot_variant_data.godot_variant_data_mem _data; + + public static unsafe explicit operator movable(in godot_variant value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_variant(movable value) + => *(godot_variant*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_variant DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_variant*)Unsafe.AsPointer(ref this)); } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_string : IDisposable + public ref struct godot_string { - internal IntPtr _ptr; + private IntPtr _ptr; public void Dispose() { @@ -184,15 +446,25 @@ namespace Godot.NativeInterop _ptr = IntPtr.Zero; } + public readonly IntPtr Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + // Size including the null termination character - public unsafe int Size => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0; + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_string_name : IDisposable + public ref struct godot_string_name { - internal IntPtr _data; + private IntPtr _data; public void Dispose() { @@ -202,18 +474,41 @@ namespace Godot.NativeInterop _data = IntPtr.Zero; } - // An static method because an instance method could result in a hidden copy if called on an `in` parameter. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsEmpty(in godot_string_name name) => + public readonly bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data != IntPtr.Zero; + } + + public readonly bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] // This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++. - name._data == IntPtr.Zero; + get => _data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _data; + + public static unsafe explicit operator movable(in godot_string_name value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_string_name(movable value) + => *(godot_string_name*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_string_name DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_string_name*)Unsafe.AsPointer(ref this)); + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_node_path : IDisposable + public ref struct godot_node_path { - internal IntPtr _data; + private IntPtr _data; public void Dispose() { @@ -223,49 +518,98 @@ namespace Godot.NativeInterop _data = IntPtr.Zero; } - // An static method because an instance method could result in a hidden copy if called on an `in` parameter. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsEmpty(in godot_node_path nodePath) => - // This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does. - nodePath._data == IntPtr.Zero; - } - - [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming - public struct godot_signal : IDisposable - { - [FieldOffset(0)] public godot_string_name _name; - - // There's padding here on 32-bit - - [FieldOffset(8)] public UInt64 _objectId; - - public void Dispose() + public readonly bool IsAllocated { - if (_name._data == IntPtr.Zero) - return; - NativeFuncs.godotsharp_signal_destroy(ref this); - _name._data = IntPtr.Zero; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data != IntPtr.Zero; + } + + public readonly bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does. + get => _data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _data; + + public static unsafe explicit operator movable(in godot_node_path value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_node_path(movable value) + => *(godot_node_path*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_node_path DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_node_path*)Unsafe.AsPointer(ref this)); } } [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - public struct godot_callable : IDisposable + public ref struct godot_signal { - [FieldOffset(0)] public godot_string_name _method; + [FieldOffset(0)] private godot_string_name _name; // There's padding here on 32-bit - [FieldOffset(8)] public UInt64 _objectId; - [FieldOffset(8)] public IntPtr _custom; + [FieldOffset(8)] private UInt64 _objectId; + + public godot_signal(godot_string_name name, ulong objectId) + { + _name = name; + _objectId = objectId; + } + + public godot_string_name Name + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _name; + } + + public UInt64 ObjectId + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _objectId; + } public void Dispose() { - if (_method._data == IntPtr.Zero && _custom == IntPtr.Zero) + if (!_name.IsAllocated) + return; + NativeFuncs.godotsharp_signal_destroy(ref this); + _name = default; + } + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + public ref struct godot_callable + { + [FieldOffset(0)] private godot_string_name _method; + + // There's padding here on 32-bit + + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable + [FieldOffset(8)] private UInt64 _objectId; + [FieldOffset(8)] private IntPtr _custom; + + public godot_callable(godot_string_name method, ulong objectId) : this() + { + _method = method; + _objectId = objectId; + } + + public void Dispose() + { + // _custom needs freeing as well + if (!_method.IsAllocated && _custom == IntPtr.Zero) return; NativeFuncs.godotsharp_callable_destroy(ref this); - _method._data = IntPtr.Zero; + _method = default; _custom = IntPtr.Zero; } } @@ -275,29 +619,55 @@ namespace Godot.NativeInterop // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_array : IDisposable + public ref struct godot_array { - internal unsafe ArrayPrivate* _p; + private unsafe ArrayPrivate* _p; [StructLayout(LayoutKind.Sequential)] - internal struct ArrayPrivate + private struct ArrayPrivate { private uint _safeRefCount; - internal VariantVector _arrayVector; - // There's more here, but we don't care as we never store this in C# + public VariantVector _arrayVector; + // There are more fields here, but we don't care as we never store this in C# + + public readonly int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _arrayVector.Size; + } } [StructLayout(LayoutKind.Sequential)] - internal struct VariantVector + private struct VariantVector { - internal IntPtr _writeProxy; - internal unsafe godot_variant* _ptr; + private IntPtr _writeProxy; + public unsafe godot_variant* _ptr; - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } - public unsafe int Size => _p != null ? _p->_arrayVector.Size : 0; + public readonly unsafe godot_variant* Elements + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p->_arrayVector._ptr; + } + + public readonly unsafe bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != null; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != null ? _p->Size : 0; + } public unsafe void Dispose() { @@ -306,6 +676,22 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_array_destroy(ref this); _p = null; } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private unsafe ArrayPrivate* _p; + + public static unsafe explicit operator movable(in godot_array value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_array(movable value) + => *(godot_array*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_array DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_array*)Unsafe.AsPointer(ref this)); + } } // IMPORTANT: @@ -314,9 +700,15 @@ namespace Godot.NativeInterop // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_dictionary : IDisposable + public ref struct godot_dictionary { - internal IntPtr _p; + private IntPtr _p; + + public readonly bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != IntPtr.Zero; + } public void Dispose() { @@ -325,14 +717,30 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_dictionary_destroy(ref this); _p = IntPtr.Zero; } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _p; + + public static unsafe explicit operator movable(in godot_dictionary value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_dictionary(movable value) + => *(godot_dictionary*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_dictionary DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_dictionary*)Unsafe.AsPointer(ref this)); + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_byte_array : IDisposable + public ref struct godot_packed_byte_array { - internal IntPtr _writeProxy; - internal unsafe byte* _ptr; + private IntPtr _writeProxy; + private unsafe byte* _ptr; public unsafe void Dispose() { @@ -342,15 +750,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe byte* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_int32_array : IDisposable + public ref struct godot_packed_int32_array { - internal IntPtr _writeProxy; - internal unsafe int* _ptr; + private IntPtr _writeProxy; + private unsafe int* _ptr; public unsafe void Dispose() { @@ -360,15 +778,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *(_ptr - 1) : 0; + public readonly unsafe int* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *(_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_int64_array : IDisposable + public ref struct godot_packed_int64_array { - internal IntPtr _writeProxy; - internal unsafe long* _ptr; + private IntPtr _writeProxy; + private unsafe long* _ptr; public unsafe void Dispose() { @@ -378,15 +806,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe long* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_float32_array : IDisposable + public ref struct godot_packed_float32_array { - internal IntPtr _writeProxy; - internal unsafe float* _ptr; + private IntPtr _writeProxy; + private unsafe float* _ptr; public unsafe void Dispose() { @@ -396,15 +834,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe float* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_float64_array : IDisposable + public ref struct godot_packed_float64_array { - internal IntPtr _writeProxy; - internal unsafe double* _ptr; + private IntPtr _writeProxy; + private unsafe double* _ptr; public unsafe void Dispose() { @@ -414,15 +862,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe double* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_string_array : IDisposable + public ref struct godot_packed_string_array { - internal IntPtr _writeProxy; - internal unsafe godot_string* _ptr; + private IntPtr _writeProxy; + private unsafe godot_string* _ptr; public unsafe void Dispose() { @@ -432,15 +890,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe godot_string* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_vector2_array : IDisposable + public ref struct godot_packed_vector2_array { - internal IntPtr _writeProxy; - internal unsafe Vector2* _ptr; + private IntPtr _writeProxy; + private unsafe Vector2* _ptr; public unsafe void Dispose() { @@ -450,15 +918,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Vector2* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_vector3_array : IDisposable + public ref struct godot_packed_vector3_array { - internal IntPtr _writeProxy; - internal unsafe Vector3* _ptr; + private IntPtr _writeProxy; + private unsafe Vector3* _ptr; public unsafe void Dispose() { @@ -468,15 +946,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Vector3* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_color_array : IDisposable + public ref struct godot_packed_color_array { - internal IntPtr _writeProxy; - internal unsafe Color* _ptr; + private IntPtr _writeProxy; + private unsafe Color* _ptr; public unsafe void Dispose() { @@ -486,6 +974,16 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Color* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs index 5779421c699..8ddf28ba16e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Godot.Bridge; @@ -16,22 +15,19 @@ namespace Godot.NativeInterop return null; IntPtr gcHandlePtr; - godot_bool has_cs_script_instance = false.ToGodotBool(); + godot_bool hasCsScriptInstance; // First try to get the tied managed instance from a CSharpInstance script instance - unsafe - { - gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed( - unmanaged, &has_cs_script_instance); - } + gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed( + unmanaged, out hasCsScriptInstance); if (gcHandlePtr != IntPtr.Zero) return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target; // Otherwise, if the object has a CSharpInstance script instance, return null - if (has_cs_script_instance.ToBool()) + if (hasCsScriptInstance.ToBool()) return null; // If it doesn't have a CSharpInstance script instance, try with native instance bindings @@ -58,12 +54,9 @@ namespace Godot.NativeInterop if (type == nativeType) { - unsafe - { - godot_string_name nativeNameAux = nativeName.NativeValue; - NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged( - GCHandle.ToIntPtr(gcHandle), unmanaged, &nativeNameAux, refCounted.ToGodotBool()); - } + var nativeNameSelf = (godot_string_name)nativeName.NativeValue; + NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged( + GCHandle.ToIntPtr(gcHandle), unmanaged, nativeNameSelf, refCounted.ToGodotBool()); } else { @@ -88,10 +81,10 @@ namespace Godot.NativeInterop GCHandle.ToIntPtr(strongGCHandle), unmanaged); } - public static unsafe Object EngineGetSingleton(string name) + public static Object EngineGetSingleton(string name) { - using godot_string src = Marshaling.mono_string_to_godot(name); - return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(&src)); + using godot_string src = Marshaling.ConvertStringToNative(name); + return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(src)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 74232425bb0..d1a1450f044 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -1,19 +1,21 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming +// We want to use full name qualifiers here even if redundant for clarity +// ReSharper disable RedundantNameQualifier + +#nullable enable + namespace Godot.NativeInterop { - // We want to use full name qualifiers here even if redundant for clarity - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static class Marshaling { - public static Variant.Type managed_to_variant_type(Type type, out bool r_nil_is_variant) + internal static Variant.Type ConvertManagedTypeToVariantType(Type type, out bool r_nil_is_variant) { r_nil_is_variant = false; @@ -106,7 +108,7 @@ namespace Godot.NativeInterop if (type.IsArray || type.IsSZArray) { - if (type == typeof(Byte[])) + if (type == typeof(byte[])) return Variant.Type.PackedByteArray; if (type == typeof(Int32[])) @@ -133,6 +135,15 @@ namespace Godot.NativeInterop if (type == typeof(Color[])) return Variant.Type.PackedColorArray; + if (type == typeof(StringName[])) + return Variant.Type.Array; + + if (type == typeof(NodePath[])) + return Variant.Type.Array; + + if (type == typeof(RID[])) + return Variant.Type.Array; + if (typeof(Godot.Object[]).IsAssignableFrom(type)) return Variant.Type.Array; @@ -161,6 +172,9 @@ namespace Godot.NativeInterop if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) return Variant.Type.Array; + + if (typeof(Godot.Object).IsAssignableFrom(type)) + return Variant.Type.Object; } else if (type == typeof(object)) { @@ -200,44 +214,9 @@ namespace Godot.NativeInterop return Variant.Type.Nil; } - public static bool try_get_array_element_type(Type p_array_type, out Type r_elem_type) - { - if (p_array_type.IsArray || p_array_type.IsSZArray) - { - r_elem_type = p_array_type.GetElementType(); - return true; - } - else if (p_array_type.IsGenericType) - { - var genericTypeDefinition = p_array_type.GetGenericTypeDefinition(); - - if (typeof(Collections.Array) == genericTypeDefinition || - typeof(System.Collections.Generic.List<>) == genericTypeDefinition || - typeof(System.Collections.ICollection) == genericTypeDefinition || - typeof(System.Collections.IEnumerable) == genericTypeDefinition) - { - r_elem_type = p_array_type.GetGenericArguments()[0]; - return true; - } - } - - r_elem_type = null; - return false; - } - /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */ - public static godot_variant mono_object_to_variant(object p_obj) - { - return mono_object_to_variant_impl(p_obj); - } - - public static godot_variant mono_object_to_variant_no_err(object p_obj) - { - return mono_object_to_variant_impl(p_obj); - } - - private static unsafe godot_variant mono_object_to_variant_impl(object p_obj, bool p_fail_with_err = true) + public static godot_variant ConvertManagedObjectToVariant(object? p_obj) { if (p_obj == null) return new godot_variant(); @@ -248,7 +227,7 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromBool(@bool); case char @char: return VariantUtils.CreateFromInt(@char); - case SByte @int8: + case sbyte @int8: return VariantUtils.CreateFromInt(@int8); case Int16 @int16: return VariantUtils.CreateFromInt(@int16); @@ -256,7 +235,7 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromInt(@int32); case Int64 @int64: return VariantUtils.CreateFromInt(@int64); - case Byte @uint8: + case byte @uint8: return VariantUtils.CreateFromInt(@uint8); case UInt16 @uint16: return VariantUtils.CreateFromInt(@uint16); @@ -311,58 +290,72 @@ namespace Godot.NativeInterop case string @string: { return VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue( - mono_string_to_godot(@string)); + ConvertStringToNative(@string)); } - case Byte[] byteArray: + case byte[] byteArray: { - using godot_packed_byte_array array = mono_array_to_PackedByteArray(byteArray); - return VariantUtils.CreateFromPackedByteArray(&array); + using godot_packed_byte_array array = ConvertSystemArrayToNativePackedByteArray(byteArray); + return VariantUtils.CreateFromPackedByteArray(array); } case Int32[] int32Array: { - using godot_packed_int32_array array = mono_array_to_PackedInt32Array(int32Array); - return VariantUtils.CreateFromPackedInt32Array(&array); + using godot_packed_int32_array array = ConvertSystemArrayToNativePackedInt32Array(int32Array); + return VariantUtils.CreateFromPackedInt32Array(array); } case Int64[] int64Array: { - using godot_packed_int64_array array = mono_array_to_PackedInt64Array(int64Array); - return VariantUtils.CreateFromPackedInt64Array(&array); + using godot_packed_int64_array array = ConvertSystemArrayToNativePackedInt64Array(int64Array); + return VariantUtils.CreateFromPackedInt64Array(array); } case float[] floatArray: { - using godot_packed_float32_array array = mono_array_to_PackedFloat32Array(floatArray); - return VariantUtils.CreateFromPackedFloat32Array(&array); + using godot_packed_float32_array array = ConvertSystemArrayToNativePackedFloat32Array(floatArray); + return VariantUtils.CreateFromPackedFloat32Array(array); } case double[] doubleArray: { - using godot_packed_float64_array array = mono_array_to_PackedFloat64Array(doubleArray); - return VariantUtils.CreateFromPackedFloat64Array(&array); + using godot_packed_float64_array array = ConvertSystemArrayToNativePackedFloat64Array(doubleArray); + return VariantUtils.CreateFromPackedFloat64Array(array); } case string[] stringArray: { - using godot_packed_string_array array = mono_array_to_PackedStringArray(stringArray); - return VariantUtils.CreateFromPackedStringArray(&array); + using godot_packed_string_array array = ConvertSystemArrayToNativePackedStringArray(stringArray); + return VariantUtils.CreateFromPackedStringArray(array); } case Vector2[] vector2Array: { - using godot_packed_vector2_array array = mono_array_to_PackedVector2Array(vector2Array); - return VariantUtils.CreateFromPackedVector2Array(&array); + using godot_packed_vector2_array array = ConvertSystemArrayToNativePackedVector2Array(vector2Array); + return VariantUtils.CreateFromPackedVector2Array(array); } case Vector3[] vector3Array: { - using godot_packed_vector3_array array = mono_array_to_PackedVector3Array(vector3Array); - return VariantUtils.CreateFromPackedVector3Array(&array); + using godot_packed_vector3_array array = ConvertSystemArrayToNativePackedVector3Array(vector3Array); + return VariantUtils.CreateFromPackedVector3Array(array); } case Color[] colorArray: { - using godot_packed_color_array array = mono_array_to_PackedColorArray(colorArray); - return VariantUtils.CreateFromPackedColorArray(&array); + using godot_packed_color_array array = ConvertSystemArrayToNativePackedColorArray(colorArray); + return VariantUtils.CreateFromPackedColorArray(array); + } + case StringName[] stringNameArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(stringNameArray); + return VariantUtils.CreateFromArray(array); + } + case NodePath[] nodePathArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(nodePathArray); + return VariantUtils.CreateFromArray(array); + } + case RID[] ridArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(ridArray); + return VariantUtils.CreateFromArray(array); } case Godot.Object[] godotObjectArray: { - // ReSharper disable once CoVariantArrayConversion - using godot_array array = mono_array_to_Array(godotObjectArray); - return VariantUtils.CreateFromArray(&array); + using godot_array array = ConvertSystemArrayToNativeGodotArray(godotObjectArray); + return VariantUtils.CreateFromArray(array); } case object[] objectArray: // Last one to avoid catching others like string[] and Godot.Object[] { @@ -370,45 +363,38 @@ namespace Godot.NativeInterop // so we need to check the actual type to make sure it's truly `object[]`. if (objectArray.GetType() == typeof(object[])) { - using godot_array array = mono_array_to_Array(objectArray); - return VariantUtils.CreateFromArray(&array); + using godot_array array = ConvertSystemArrayToNativeGodotArray(objectArray); + return VariantUtils.CreateFromArray(array); } - if (p_fail_with_err) - { - GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); - return new godot_variant(); - } - else - { - return new godot_variant(); - } + GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); + return new godot_variant(); } case Godot.Object godotObject: return VariantUtils.CreateFromGodotObject(godotObject.NativeInstance); case StringName stringName: - return VariantUtils.CreateFromStringName(ref stringName.NativeValue); + return VariantUtils.CreateFromStringName(stringName.NativeValue.DangerousSelfRef); case NodePath nodePath: - return VariantUtils.CreateFromNodePath(ref nodePath.NativeValue); + return VariantUtils.CreateFromNodePath((godot_node_path)nodePath.NativeValue); case RID rid: return VariantUtils.CreateFromRID(rid); case Collections.Dictionary godotDictionary: - return VariantUtils.CreateFromDictionary(godotDictionary.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDictionary.NativeValue); case Collections.Array godotArray: - return VariantUtils.CreateFromArray(godotArray.NativeValue); + return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); case Collections.IGenericGodotDictionary genericGodotDictionary: { var godotDict = genericGodotDictionary.UnderlyingDictionary; if (godotDict == null) return new godot_variant(); - return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); } case Collections.IGenericGodotArray genericGodotArray: { var godotArray = genericGodotArray.UnderlyingArray; if (godotArray == null) return new godot_variant(); - return VariantUtils.CreateFromArray(godotArray.NativeValue); + return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); } default: { @@ -426,14 +412,14 @@ namespace Godot.NativeInterop foreach (KeyValuePair entry in (IDictionary)p_obj) godotDict.Add(entry.Key, entry.Value); - return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); } if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) { // TODO: Validate element type is compatible with Variant - var nativeGodotArray = mono_array_to_Array((IList)p_obj); - return VariantUtils.CreateFromArray(&nativeGodotArray); + using var nativeGodotArray = ConvertIListToNativeGodotArray((IList)p_obj); + return VariantUtils.CreateFromArray(nativeGodotArray); } } @@ -441,38 +427,31 @@ namespace Godot.NativeInterop } } - if (p_fail_with_err) - { - GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + - p_obj.GetType().FullName + "."); - return new godot_variant(); - } - else - { - return new godot_variant(); - } + GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + + p_obj.GetType().FullName + "."); + return new godot_variant(); } - public static unsafe string variant_to_mono_string(godot_variant* p_var) + private static string? ConvertVariantToManagedString(in godot_variant p_var) { - switch ((*p_var)._type) + switch (p_var.Type) { case Variant.Type.Nil: return null; // Otherwise, Variant -> String would return the string "Null" case Variant.Type.String: { // We avoid the internal call if the stored type is the same we want. - return mono_string_from_godot((*p_var)._data._m_string); + return ConvertStringToManaged(p_var.String); } default: { using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var); - return mono_string_from_godot(godotString); + return ConvertStringToManaged(godotString); } } } - public static unsafe object variant_to_mono_object_of_type(godot_variant* p_var, Type type) + public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type) { // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant. switch (Type.GetTypeCode(type)) @@ -502,7 +481,7 @@ namespace Godot.NativeInterop case TypeCode.Double: return VariantUtils.ConvertToFloat64(p_var); case TypeCode.String: - return variant_to_mono_string(p_var); + return ConvertVariantToManagedString(p_var); default: { if (type == typeof(Vector2)) @@ -556,13 +535,13 @@ namespace Godot.NativeInterop if (type == typeof(Callable)) { using godot_callable callable = NativeFuncs.godotsharp_variant_as_callable(p_var); - return ConvertCallableToManaged(&callable); + return ConvertCallableToManaged(in callable); } if (type == typeof(SignalInfo)) { using godot_signal signal = NativeFuncs.godotsharp_variant_as_signal(p_var); - return ConvertSignalToManaged(&signal); + return ConvertSignalToManaged(in signal); } if (type.IsEnum) @@ -597,12 +576,12 @@ namespace Godot.NativeInterop } if (type.IsArray || type.IsSZArray) - return variant_to_mono_array_of_type(p_var, type); + return ConvertVariantToSystemArrayOfType(p_var, type); else if (type.IsGenericType) - return variant_to_mono_object_of_genericinst(p_var, type); + return ConvertVariantToManagedObjectOfGenericType(p_var, type); else if (type == typeof(object)) - return variant_to_mono_object(p_var); - if (variant_to_mono_object_of_class(p_var, type, out object res)) + return ConvertVariantToManagedObject(p_var); + if (ConvertVariantToManagedObjectOfClass(p_var, type, out object? res)) return res; break; @@ -614,72 +593,90 @@ namespace Godot.NativeInterop return null; } - private static unsafe object variant_to_mono_array_of_type(godot_variant* p_var, Type type) + private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type) { - if (type == typeof(Byte[])) + if (type == typeof(byte[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return PackedByteArray_to_mono_array(&packedArray); + return ConvertNativePackedByteArrayToSystemArray(packedArray); } if (type == typeof(Int32[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return PackedInt32Array_to_mono_array(&packedArray); + return ConvertNativePackedInt32ArrayToSystemArray(packedArray); } if (type == typeof(Int64[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return PackedInt64Array_to_mono_array(&packedArray); + return ConvertNativePackedInt64ArrayToSystemArray(packedArray); } if (type == typeof(float[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return PackedFloat32Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); } if (type == typeof(double[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return PackedFloat64Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); } if (type == typeof(string[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return PackedStringArray_to_mono_array(&packedArray); + return ConvertNativePackedStringArrayToSystemArray(packedArray); } if (type == typeof(Vector2[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return PackedVector2Array_to_mono_array(&packedArray); + return ConvertNativePackedVector2ArrayToSystemArray(packedArray); } if (type == typeof(Vector3[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return PackedVector3Array_to_mono_array(&packedArray); + return ConvertNativePackedVector3ArrayToSystemArray(packedArray); } if (type == typeof(Color[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return PackedColorArray_to_mono_array(&packedArray); + return ConvertNativePackedColorArrayToSystemArray(packedArray); + } + + if (type == typeof(StringName[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); + } + + if (type == typeof(NodePath[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); + } + + if (type == typeof(RID[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); } if (typeof(Godot.Object[]).IsAssignableFrom(type)) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Array_to_mono_array_of_godot_object_type(&godotArray, type); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); } if (type == typeof(object[])) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Array_to_mono_array(&godotArray); + return ConvertNativeGodotArrayToSystemArray(godotArray); } GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " + @@ -687,7 +684,8 @@ namespace Godot.NativeInterop return null; } - private static unsafe bool variant_to_mono_object_of_class(godot_variant* p_var, Type type, out object res) + private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type, + out object? res) { if (typeof(Godot.Object).IsAssignableFrom(type)) { @@ -735,33 +733,33 @@ namespace Godot.NativeInterop return false; } - private static unsafe object variant_to_mono_object_of_genericinst(godot_variant* p_var, Type type) + private static object? ConvertVariantToManagedObjectOfGenericType(in godot_variant p_var, Type type) { - static object variant_to_generic_godot_collections_dictionary(godot_variant* p_var, Type fullType) + static object ConvertVariantToGenericGodotCollectionsDictionary(in godot_variant p_var, Type fullType) { var underlyingDict = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( VariantUtils.ConvertToDictionary(p_var)); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingDict }, null); + args: new object[] { underlyingDict }, null)!; } - static object variant_to_generic_godot_collections_array(godot_variant* p_var, Type fullType) + static object ConvertVariantToGenericGodotCollectionsArray(in godot_variant p_var, Type fullType) { var underlyingArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( VariantUtils.ConvertToArray(p_var)); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingArray }, null); + args: new object[] { underlyingArray }, null)!; } var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) - return variant_to_generic_godot_collections_dictionary(p_var, type); + return ConvertVariantToGenericGodotCollectionsDictionary(p_var, type); if (genericTypeDefinition == typeof(Collections.Array<>)) - return variant_to_generic_godot_collections_array(p_var, type); + return ConvertVariantToGenericGodotCollectionsArray(p_var, type); if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) { @@ -773,7 +771,7 @@ namespace Godot.NativeInterop args: new object[] { /* capacity: */ godotDictionary.Count - }, null); + }, null)!; foreach (System.Collections.DictionaryEntry pair in godotDictionary) dictionary.Add(pair.Key, pair.Value); @@ -791,7 +789,7 @@ namespace Godot.NativeInterop args: new object[] { /* capacity: */ godotArray.Count - }, null); + }, null)!; foreach (object elem in godotArray) list.Add(elem); @@ -807,7 +805,7 @@ namespace Godot.NativeInterop var genericGodotDictionaryType = typeof(Collections.Dictionary<,>) .MakeGenericType(keyType, valueType); - return variant_to_generic_godot_collections_dictionary(p_var, genericGodotDictionaryType); + return ConvertVariantToGenericGodotCollectionsDictionary(p_var, genericGodotDictionaryType); } if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) @@ -816,138 +814,141 @@ namespace Godot.NativeInterop var genericGodotArrayType = typeof(Collections.Array<>) .MakeGenericType(elementType); - return variant_to_generic_godot_collections_array(p_var, genericGodotArrayType); + return ConvertVariantToGenericGodotCollectionsArray(p_var, genericGodotArrayType); } + if (typeof(Godot.Object).IsAssignableFrom(type)) + return InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var)); + return null; } - public static unsafe object variant_to_mono_object(godot_variant* p_var) + public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var) { - switch ((*p_var)._type) + switch (p_var.Type) { case Variant.Type.Bool: - return (*p_var)._data._bool.ToBool(); + return p_var.Bool.ToBool(); case Variant.Type.Int: - return (*p_var)._data._int; + return p_var.Int; case Variant.Type.Float: { #if REAL_T_IS_DOUBLE - return (*p_var)._data._float; + return p_var.Float; #else - return (float)(*p_var)._data._float; + return (float)p_var.Float; #endif } case Variant.Type.String: - return mono_string_from_godot((*p_var)._data._m_string); + return ConvertStringToManaged(p_var.String); case Variant.Type.Vector2: - return (*p_var)._data._m_vector2; + return p_var.Vector2; case Variant.Type.Vector2i: - return (*p_var)._data._m_vector2i; + return p_var.Vector2i; case Variant.Type.Rect2: - return (*p_var)._data._m_rect2; + return p_var.Rect2; case Variant.Type.Rect2i: - return (*p_var)._data._m_rect2i; + return p_var.Rect2i; case Variant.Type.Vector3: - return (*p_var)._data._m_vector3; + return p_var.Vector3; case Variant.Type.Vector3i: - return (*p_var)._data._m_vector3i; + return p_var.Vector3i; case Variant.Type.Transform2d: - return *(*p_var)._data._transform2d; + return *p_var.Transform2D; case Variant.Type.Vector4: - return *(*p_var)._data._vector4; + return *p_var.Vector4; case Variant.Type.Vector4i: - return *(*p_var)._data._vector4i; + return *p_var.Vector4i; case Variant.Type.Plane: - return (*p_var)._data._m_plane; + return p_var.Plane; case Variant.Type.Quaternion: - return (*p_var)._data._m_quaternion; + return p_var.Quaternion; case Variant.Type.Aabb: - return *(*p_var)._data._aabb; + return *p_var.AABB; case Variant.Type.Basis: - return *(*p_var)._data._basis; + return *p_var.Basis; case Variant.Type.Transform3d: - return *(*p_var)._data._transform3d; + return *p_var.Transform3D; case Variant.Type.Projection: - return *(*p_var)._data._projection; + return *p_var.Projection; case Variant.Type.Color: - return (*p_var)._data._m_color; + return p_var.Color; case Variant.Type.StringName: { // The Variant owns the value, so we need to make a copy return StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name)); + NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName)); } case Variant.Type.NodePath: { // The Variant owns the value, so we need to make a copy return NodePath.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path)); + NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath)); } case Variant.Type.Rid: - return (*p_var)._data._m_rid; + return p_var.RID; case Variant.Type.Object: - return InteropUtils.UnmanagedGetManaged((*p_var)._data._m_obj_data.obj); + return InteropUtils.UnmanagedGetManaged(p_var.Object); case Variant.Type.Callable: - return ConvertCallableToManaged(&(*p_var)._data._m_callable); + return ConvertCallableToManaged(p_var.Callable); case Variant.Type.Signal: - return ConvertSignalToManaged(&(*p_var)._data._m_signal); + return ConvertSignalToManaged(p_var.Signal); case Variant.Type.Dictionary: { // The Variant owns the value, so we need to make a copy return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary)); + NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary)); } case Variant.Type.Array: { // The Variant owns the value, so we need to make a copy return Collections.Array.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array)); + NativeFuncs.godotsharp_array_new_copy(p_var.Array)); } case Variant.Type.PackedByteArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return PackedByteArray_to_mono_array(&packedArray); + return ConvertNativePackedByteArrayToSystemArray(packedArray); } case Variant.Type.PackedInt32Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return PackedInt32Array_to_mono_array(&packedArray); + return ConvertNativePackedInt32ArrayToSystemArray(packedArray); } case Variant.Type.PackedInt64Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return PackedInt64Array_to_mono_array(&packedArray); + return ConvertNativePackedInt64ArrayToSystemArray(packedArray); } case Variant.Type.PackedFloat32Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return PackedFloat32Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); } case Variant.Type.PackedFloat64Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return PackedFloat64Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); } case Variant.Type.PackedStringArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return PackedStringArray_to_mono_array(&packedArray); + return ConvertNativePackedStringArrayToSystemArray(packedArray); } case Variant.Type.PackedVector2Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return PackedVector2Array_to_mono_array(&packedArray); + return ConvertNativePackedVector2ArrayToSystemArray(packedArray); } case Variant.Type.PackedVector3Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return PackedVector3Array_to_mono_array(&packedArray); + return ConvertNativePackedVector3ArrayToSystemArray(packedArray); } case Variant.Type.PackedColorArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return PackedColorArray_to_mono_array(&packedArray); + return ConvertNativePackedColorArrayToSystemArray(packedArray); } default: return null; @@ -956,26 +957,25 @@ namespace Godot.NativeInterop // String - public static unsafe godot_string mono_string_to_godot(string p_mono_string) + public static unsafe godot_string ConvertStringToNative(string? p_mono_string) { if (p_mono_string == null) return new godot_string(); fixed (char* methodChars = p_mono_string) { - godot_string dest; - NativeFuncs.godotsharp_string_new_with_utf16_chars(&dest, methodChars); + NativeFuncs.godotsharp_string_new_with_utf16_chars(out godot_string dest, methodChars); return dest; } } - public static unsafe string mono_string_from_godot(in godot_string p_string) + public static unsafe string ConvertStringToManaged(in godot_string p_string) { - if (p_string._ptr == IntPtr.Zero) + if (p_string.Buffer == IntPtr.Zero) return string.Empty; const int sizeOfChar32 = 4; - byte* bytes = (byte*)p_string._ptr; + byte* bytes = (byte*)p_string.Buffer; int size = p_string.Size; if (size == 0) return string.Empty; @@ -987,54 +987,45 @@ namespace Godot.NativeInterop // Callable public static godot_callable ConvertCallableToNative(ref Callable p_managed_callable) + => ConvertCallableToNative(p_managed_callable); + + public static godot_callable ConvertCallableToNative(Callable p_managed_callable) { if (p_managed_callable.Delegate != null) { - unsafe - { - godot_callable callable; - NativeFuncs.godotsharp_callable_new_with_delegate( - GCHandle.ToIntPtr(GCHandle.Alloc(p_managed_callable.Delegate)), &callable); - return callable; - } + NativeFuncs.godotsharp_callable_new_with_delegate( + GCHandle.ToIntPtr(GCHandle.Alloc(p_managed_callable.Delegate)), + out godot_callable callable); + return callable; } else { - unsafe + godot_string_name method; + + if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty) { - godot_string_name method; - - if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty) - { - godot_string_name src = p_managed_callable.Method.NativeValue; - method = NativeFuncs.godotsharp_string_name_new_copy(&src); - } - else - { - method = default; - } - - return new godot_callable - { - _method = method, // Takes ownership of disposable - _objectId = p_managed_callable.Target.GetInstanceId() - }; + var src = (godot_string_name)p_managed_callable.Method.NativeValue; + method = NativeFuncs.godotsharp_string_name_new_copy(src); } + else + { + method = default; + } + + return new godot_callable(method /* Takes ownership of disposable */, + p_managed_callable.Target.GetInstanceId()); } } - public static unsafe Callable ConvertCallableToManaged(godot_callable* p_callable) + public static Callable ConvertCallableToManaged(in godot_callable p_callable) { - IntPtr delegateGCHandle; - IntPtr godotObject; - godot_string_name name; - - if (NativeFuncs.godotsharp_callable_get_data_for_marshalling( - p_callable, &delegateGCHandle, &godotObject, &name).ToBool()) + if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable, + out IntPtr delegateGCHandle, out IntPtr godotObject, + out godot_string_name name).ToBool()) { if (delegateGCHandle != IntPtr.Zero) { - return new Callable((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target); + return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target); } else { @@ -1053,39 +1044,32 @@ namespace Godot.NativeInterop public static godot_signal ConvertSignalToNative(ref SignalInfo p_managed_signal) { ulong ownerId = p_managed_signal.Owner.GetInstanceId(); - unsafe + godot_string_name name; + + if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty) { - godot_string_name name; - - if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty) - { - godot_string_name src = p_managed_signal.Name.NativeValue; - name = NativeFuncs.godotsharp_string_name_new_copy(&src); - } - else - { - name = default; - } - - return new godot_signal() - { - _name = name, - _objectId = ownerId - }; + var src = (godot_string_name)p_managed_signal.Name.NativeValue; + name = NativeFuncs.godotsharp_string_name_new_copy(src); } + else + { + name = default; + } + + return new godot_signal(name, ownerId); } - public static unsafe SignalInfo ConvertSignalToManaged(godot_signal* p_signal) + public static SignalInfo ConvertSignalToManaged(in godot_signal p_signal) { - var owner = GD.InstanceFromId((*p_signal)._objectId); + var owner = GD.InstanceFromId(p_signal.ObjectId); var name = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(&(*p_signal)._name)); + NativeFuncs.godotsharp_string_name_new_copy(p_signal.Name)); return new SignalInfo(owner, name); } // Array - public static unsafe object[] Array_to_mono_array(godot_array* p_array) + public static object[] ConvertNativeGodotArrayToSystemArray(in godot_array p_array) { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); @@ -1093,27 +1077,27 @@ namespace Godot.NativeInterop int length = array.Count; var ret = new object[length]; - array.CopyTo(ret, 0); // variant_to_mono_object handled by Collections.Array + array.CopyTo(ret, 0); // ConvertVariantToManagedObject handled by Collections.Array return ret; } - public static unsafe object Array_to_mono_array_of_godot_object_type(godot_array* p_array, Type type) + private static object ConvertNativeGodotArrayToSystemArrayOfType(in godot_array p_array, Type type) { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); int length = array.Count; - object ret = Activator.CreateInstance(type, length); + object ret = Activator.CreateInstance(type, length)!; - // variant_to_mono_object handled by Collections.Array - // variant_to_mono_object_of_type is not needed because target element types are Godot.Object (or derived) + // ConvertVariantToManagedObject handled by Collections.Array + // ConvertVariantToManagedObjectOfType is not needed because target element types are Godot.Object (or derived) array.CopyTo((object[])ret, 0); return ret; } - public static godot_array mono_array_to_Array(object[] p_array) + public static godot_array ConvertSystemArrayToNativeGodotArray(object[] p_array) { int length = p_array.Length; @@ -1126,14 +1110,28 @@ namespace Godot.NativeInterop for (int i = 0; i < length; i++) array[i] = p_array[i]; - godot_array src = array.NativeValue; - unsafe - { - return NativeFuncs.godotsharp_array_new_copy(&src); - } + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); } - public static godot_array mono_array_to_Array(IList p_array) + public static godot_array ConvertSystemArrayToNativeGodotArray(T[] p_array) + { + int length = p_array.Length; + + if (length == 0) + return NativeFuncs.godotsharp_array_new(); + + using var array = new Collections.Array(); + array.Resize(length); + + for (int i = 0; i < length; i++) + array[i] = p_array[i]; + + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); + } + + public static godot_array ConvertIListToNativeGodotArray(IList p_array) { int length = p_array.Count; @@ -1146,26 +1144,25 @@ namespace Godot.NativeInterop for (int i = 0; i < length; i++) array[i] = p_array[i]; - godot_array src = array.NativeValue; - unsafe - { - return NativeFuncs.godotsharp_array_new_copy(&src); - } + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); } // PackedByteArray - public static unsafe byte[] PackedByteArray_to_mono_array(godot_packed_byte_array* p_array) + public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_packed_byte_array p_array) { - byte* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + byte* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); var array = new byte[size]; fixed (byte* dest = array) Buffer.MemoryCopy(buffer, dest, size, size); return array; } - public static unsafe godot_packed_byte_array mono_array_to_PackedByteArray(Span p_array) + public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span p_array) { if (p_array.IsEmpty) return new godot_packed_byte_array(); @@ -1175,10 +1172,12 @@ namespace Godot.NativeInterop // PackedInt32Array - public static unsafe int[] PackedInt32Array_to_mono_array(godot_packed_int32_array* p_array) + public static unsafe int[] ConvertNativePackedInt32ArrayToSystemArray(godot_packed_int32_array p_array) { - int* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + int* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(int); var array = new int[size]; fixed (int* dest = array) @@ -1186,7 +1185,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int32_array mono_array_to_PackedInt32Array(Span p_array) + public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span p_array) { if (p_array.IsEmpty) return new godot_packed_int32_array(); @@ -1196,10 +1195,12 @@ namespace Godot.NativeInterop // PackedInt64Array - public static unsafe long[] PackedInt64Array_to_mono_array(godot_packed_int64_array* p_array) + public static unsafe long[] ConvertNativePackedInt64ArrayToSystemArray(godot_packed_int64_array p_array) { - long* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + long* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(long); var array = new long[size]; fixed (long* dest = array) @@ -1207,7 +1208,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int64_array mono_array_to_PackedInt64Array(Span p_array) + public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span p_array) { if (p_array.IsEmpty) return new godot_packed_int64_array(); @@ -1217,10 +1218,12 @@ namespace Godot.NativeInterop // PackedFloat32Array - public static unsafe float[] PackedFloat32Array_to_mono_array(godot_packed_float32_array* p_array) + public static unsafe float[] ConvertNativePackedFloat32ArrayToSystemArray(godot_packed_float32_array p_array) { - float* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + float* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(float); var array = new float[size]; fixed (float* dest = array) @@ -1228,7 +1231,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_float32_array mono_array_to_PackedFloat32Array(Span p_array) + public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array( + Span p_array) { if (p_array.IsEmpty) return new godot_packed_float32_array(); @@ -1238,10 +1242,12 @@ namespace Godot.NativeInterop // PackedFloat64Array - public static unsafe double[] PackedFloat64Array_to_mono_array(godot_packed_float64_array* p_array) + public static unsafe double[] ConvertNativePackedFloat64ArrayToSystemArray(godot_packed_float64_array p_array) { - double* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + double* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(double); var array = new double[size]; fixed (double* dest = array) @@ -1249,7 +1255,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_float64_array mono_array_to_PackedFloat64Array(Span p_array) + public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array( + Span p_array) { if (p_array.IsEmpty) return new godot_packed_float64_array(); @@ -1259,19 +1266,19 @@ namespace Godot.NativeInterop // PackedStringArray - public static unsafe string[] PackedStringArray_to_mono_array(godot_packed_string_array* p_array) + public static unsafe string[] ConvertNativePackedStringArrayToSystemArray(godot_packed_string_array p_array) { - godot_string* buffer = (*p_array)._ptr; - if (buffer == null) - return new string[] { }; - int size = (*p_array).Size; + godot_string* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); var array = new string[size]; for (int i = 0; i < size; i++) - array[i] = mono_string_from_godot(buffer[i]); + array[i] = ConvertStringToManaged(buffer[i]); return array; } - public static unsafe godot_packed_string_array mono_array_to_PackedStringArray(Span p_array) + public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span p_array) { godot_packed_string_array dest = new godot_packed_string_array(); @@ -1283,8 +1290,8 @@ namespace Godot.NativeInterop for (int i = 0; i < p_array.Length; i++) { - using godot_string godotStrElem = mono_string_to_godot(p_array[i]); - NativeFuncs.godotsharp_packed_string_array_add(&dest, &godotStrElem); + using godot_string godotStrElem = ConvertStringToNative(p_array[i]); + NativeFuncs.godotsharp_packed_string_array_add(ref dest, godotStrElem); } return dest; @@ -1292,10 +1299,12 @@ namespace Godot.NativeInterop // PackedVector2Array - public static unsafe Vector2[] PackedVector2Array_to_mono_array(godot_packed_vector2_array* p_array) + public static unsafe Vector2[] ConvertNativePackedVector2ArrayToSystemArray(godot_packed_vector2_array p_array) { - Vector2* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Vector2* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(Vector2); var array = new Vector2[size]; fixed (Vector2* dest = array) @@ -1303,7 +1312,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_vector2_array mono_array_to_PackedVector2Array(Span p_array) + public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array( + Span p_array) { if (p_array.IsEmpty) return new godot_packed_vector2_array(); @@ -1313,10 +1323,12 @@ namespace Godot.NativeInterop // PackedVector3Array - public static unsafe Vector3[] PackedVector3Array_to_mono_array(godot_packed_vector3_array* p_array) + public static unsafe Vector3[] ConvertNativePackedVector3ArrayToSystemArray(godot_packed_vector3_array p_array) { - Vector3* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Vector3* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(Vector3); var array = new Vector3[size]; fixed (Vector3* dest = array) @@ -1324,7 +1336,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_vector3_array mono_array_to_PackedVector3Array(Span p_array) + public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array( + Span p_array) { if (p_array.IsEmpty) return new godot_packed_vector3_array(); @@ -1334,10 +1347,12 @@ namespace Godot.NativeInterop // PackedColorArray - public static unsafe Color[] PackedColorArray_to_mono_array(godot_packed_color_array* p_array) + public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_packed_color_array p_array) { - Color* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Color* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty(); int sizeInBytes = size * sizeof(Color); var array = new Color[size]; fixed (Color* dest = array) @@ -1345,7 +1360,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_color_array mono_array_to_PackedColorArray(Span p_array) + public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span p_array) { if (p_array.IsEmpty) return new godot_packed_color_array(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index 8bc785f3758..f1cccfed0a7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -1,15 +1,23 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming namespace Godot.NativeInterop { -#if !NET - // This improves P/Invoke performance. - // The attribute is not available with .NET Core and it's not needed there. - [System.Security.SuppressUnmanagedCodeSecurity] -#endif + /* + * TODO: + * P/Invoke pins by-ref parameters in case the managed memory is moved. + * That's not needed here since we use "ref structs" which are stack-only. + * Unfortunately, the runtime is not smart enough and pins them anyway. + * We want to avoid pinning, so we must wrap these DllImports in methods + * that reinterpret refs and pointers with CustomUnsafe.AsPointer/AsRef. + * I wish such unnecessary boilerplate wasn't needed... + */ + + [SuppressMessage("Interoperability", "CA1401", + MessageId = "P/Invokes should not be visible" /* Meh. What are you gonna do about it? */)] public static unsafe partial class NativeFuncs { private const string GodotDllName = "__Internal"; @@ -17,15 +25,15 @@ namespace Godot.NativeInterop // Custom functions [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname, + public static extern IntPtr godotsharp_method_bind_get_method(in godot_string_name p_classname, char* p_methodname); [DllImport(GodotDllName)] public static extern delegate* unmanaged godotsharp_get_class_constructor( - ref godot_string_name p_classname); + in godot_string_name p_classname); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name); + public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name); [DllImport(GodotDllName)] internal static extern void godotsharp_internal_object_disposed(IntPtr ptr); @@ -35,61 +43,64 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj, - godot_string_name* eventSignal); + in godot_string_name eventSignal); [DllImport(GodotDllName)] internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source, - ref godot_string_name signal, + in godot_string_name signal, IntPtr target, IntPtr awaiterHandlePtr); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr, - IntPtr unmanaged, godot_string_name* nativeName, godot_bool refCounted); + internal static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr, + IntPtr unmanaged, in godot_string_name nativeName, godot_bool refCounted); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr, + internal static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr, IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup( + internal static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup( IntPtr gcHandleIntPtr, IntPtr unmanaged); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged, - godot_bool* r_has_cs_script_instance); + internal static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged, + out godot_bool r_has_cs_script_instance); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged); + internal static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged, + internal static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged, IntPtr oldGCHandlePtr); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_new_csharp_script(); + internal static extern IntPtr godotsharp_internal_new_csharp_script(); [DllImport(GodotDllName)] - public static extern void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name, - godot_array* p_input, godot_array* r_output); + internal static extern void godotsharp_array_filter_godot_objects_by_native(in godot_string_name p_native_name, + in godot_array p_input, out godot_array r_output); [DllImport(GodotDllName)] - public static extern void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input, - godot_array* r_output); + internal static extern void godotsharp_array_filter_godot_objects_by_non_native(in godot_array p_input, + out godot_array r_output); [DllImport(GodotDllName)] public static extern void godotsharp_ref_destroy(ref godot_ref p_instance); [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_new_from_string(godot_string_name* dest, godot_string* name); + public static extern void godotsharp_string_name_new_from_string(out godot_string_name r_dest, + in godot_string p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_new_from_string(godot_node_path* dest, godot_string* name); + public static extern void godotsharp_node_path_new_from_string(out godot_node_path r_dest, + in godot_string p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_as_string(godot_string* r_dest, godot_string_name* p_name); + public static extern void + godotsharp_string_name_as_string(out godot_string r_dest, in godot_string_name p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_as_string(godot_string* r_dest, godot_node_path* p_np); + public static extern void godotsharp_node_path_as_string(out godot_string r_dest, in godot_node_path p_np); [DllImport(GodotDllName)] public static extern godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src, @@ -124,16 +135,24 @@ namespace Godot.NativeInterop int p_length); [DllImport(GodotDllName)] - public static extern void godotsharp_packed_string_array_add(godot_packed_string_array* r_dest, - godot_string* p_element); + public static extern void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest, + in godot_string p_element); [DllImport(GodotDllName)] public static extern void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, - godot_callable* r_callable); + out godot_callable r_callable); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_callable_get_data_for_marshalling(godot_callable* p_callable, - IntPtr* r_delegate_handle, IntPtr* r_object, godot_string_name* r_name); + internal static extern godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable, + out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name); + + [DllImport(GodotDllName)] + internal static extern godot_variant godotsharp_callable_call(in godot_callable p_callable, + godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error); + + [DllImport(GodotDllName)] + internal static extern void godotsharp_callable_call_deferred(in godot_callable p_callable, + godot_variant** p_args, int p_arg_count); // GDNative functions @@ -145,219 +164,223 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] public static extern godot_variant godotsharp_method_bind_call(IntPtr p_method_bind, IntPtr p_instance, - godot_variant** p_args, int p_arg_count, godot_variant_call_error* p_call_error); + godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error); // variant.h [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_string_name(godot_variant* r_dest, godot_string_name* p_s); + public static extern void + godotsharp_variant_new_string_name(out godot_variant r_dest, in godot_string_name p_s); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_node_path(godot_variant* r_dest, godot_node_path* p_np); + public static extern void godotsharp_variant_new_node_path(out godot_variant r_dest, in godot_node_path p_np); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_object(godot_variant* r_dest, IntPtr p_obj); + public static extern void godotsharp_variant_new_object(out godot_variant r_dest, IntPtr p_obj); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_transform2d(godot_variant* r_dest, Transform2D* p_t2d); + public static extern void godotsharp_variant_new_transform2d(out godot_variant r_dest, in Transform2D p_t2d); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_vector4(godot_variant* r_dest, Vector4* p_vec4); + public static extern void godotsharp_variant_new_vector4(out godot_variant r_dest, in Vector4 p_vec4); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_vector4i(godot_variant* r_dest, Vector4i* p_vec4i); + public static extern void godotsharp_variant_new_vector4i(out godot_variant r_dest, in Vector4i p_vec4i); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_basis(godot_variant* r_dest, Basis* p_basis); + public static extern void godotsharp_variant_new_basis(out godot_variant r_dest, in Basis p_basis); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_transform3d(godot_variant* r_dest, Transform3D* p_trans); + public static extern void godotsharp_variant_new_transform3d(out godot_variant r_dest, in Transform3D p_trans); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_projection(godot_variant* r_dest, Projection* p_proj); + public static extern void godotsharp_variant_new_projection(out godot_variant r_dest, in Projection p_proj); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_aabb(godot_variant* r_dest, AABB* p_aabb); + public static extern void godotsharp_variant_new_aabb(out godot_variant r_dest, in AABB p_aabb); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_dictionary(godot_variant* r_dest, godot_dictionary* p_dict); + public static extern void godotsharp_variant_new_dictionary(out godot_variant r_dest, + in godot_dictionary p_dict); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_array(godot_variant* r_dest, godot_array* p_arr); + public static extern void godotsharp_variant_new_array(out godot_variant r_dest, in godot_array p_arr); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_byte_array(godot_variant* r_dest, - godot_packed_byte_array* p_pba); + public static extern void godotsharp_variant_new_packed_byte_array(out godot_variant r_dest, + in godot_packed_byte_array p_pba); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_int32_array(godot_variant* r_dest, - godot_packed_int32_array* p_pia); + public static extern void godotsharp_variant_new_packed_int32_array(out godot_variant r_dest, + in godot_packed_int32_array p_pia); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_int64_array(godot_variant* r_dest, - godot_packed_int64_array* p_pia); + public static extern void godotsharp_variant_new_packed_int64_array(out godot_variant r_dest, + in godot_packed_int64_array p_pia); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_float32_array(godot_variant* r_dest, - godot_packed_float32_array* p_pra); + public static extern void godotsharp_variant_new_packed_float32_array(out godot_variant r_dest, + in godot_packed_float32_array p_pra); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_float64_array(godot_variant* r_dest, - godot_packed_float64_array* p_pra); + public static extern void godotsharp_variant_new_packed_float64_array(out godot_variant r_dest, + in godot_packed_float64_array p_pra); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_string_array(godot_variant* r_dest, - godot_packed_string_array* p_psa); + public static extern void godotsharp_variant_new_packed_string_array(out godot_variant r_dest, + in godot_packed_string_array p_psa); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_vector2_array(godot_variant* r_dest, - godot_packed_vector2_array* p_pv2a); + public static extern void godotsharp_variant_new_packed_vector2_array(out godot_variant r_dest, + in godot_packed_vector2_array p_pv2a); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_vector3_array(godot_variant* r_dest, - godot_packed_vector3_array* p_pv3a); + public static extern void godotsharp_variant_new_packed_vector3_array(out godot_variant r_dest, + in godot_packed_vector3_array p_pv3a); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_color_array(godot_variant* r_dest, - godot_packed_color_array* p_pca); + public static extern void godotsharp_variant_new_packed_color_array(out godot_variant r_dest, + in godot_packed_color_array p_pca); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_variant_as_bool(godot_variant* p_self); + public static extern godot_bool godotsharp_variant_as_bool(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Int64 godotsharp_variant_as_int(godot_variant* p_self); + public static extern Int64 godotsharp_variant_as_int(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern double godotsharp_variant_as_float(godot_variant* p_self); + public static extern double godotsharp_variant_as_float(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_string godotsharp_variant_as_string(godot_variant* p_self); + public static extern godot_string godotsharp_variant_as_string(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector2 godotsharp_variant_as_vector2(godot_variant* p_self); + public static extern Vector2 godotsharp_variant_as_vector2(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector2i godotsharp_variant_as_vector2i(godot_variant* p_self); + public static extern Vector2i godotsharp_variant_as_vector2i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Rect2 godotsharp_variant_as_rect2(godot_variant* p_self); + public static extern Rect2 godotsharp_variant_as_rect2(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Rect2i godotsharp_variant_as_rect2i(godot_variant* p_self); + public static extern Rect2i godotsharp_variant_as_rect2i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector3 godotsharp_variant_as_vector3(godot_variant* p_self); + public static extern Vector3 godotsharp_variant_as_vector3(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector3i godotsharp_variant_as_vector3i(godot_variant* p_self); + public static extern Vector3i godotsharp_variant_as_vector3i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Transform2D godotsharp_variant_as_transform2d(godot_variant* p_self); + public static extern Transform2D godotsharp_variant_as_transform2d(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector4 godotsharp_variant_as_vector4(godot_variant* p_self); + public static extern Vector4 godotsharp_variant_as_vector4(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector4i godotsharp_variant_as_vector4i(godot_variant* p_self); + public static extern Vector4i godotsharp_variant_as_vector4i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Plane godotsharp_variant_as_plane(godot_variant* p_self); + public static extern Plane godotsharp_variant_as_plane(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Quaternion godotsharp_variant_as_quaternion(godot_variant* p_self); + public static extern Quaternion godotsharp_variant_as_quaternion(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern AABB godotsharp_variant_as_aabb(godot_variant* p_self); + public static extern AABB godotsharp_variant_as_aabb(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Basis godotsharp_variant_as_basis(godot_variant* p_self); + public static extern Basis godotsharp_variant_as_basis(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Transform3D godotsharp_variant_as_transform3d(godot_variant* p_self); + public static extern Transform3D godotsharp_variant_as_transform3d(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Projection godotsharp_variant_as_projection(godot_variant* p_self); + public static extern Projection godotsharp_variant_as_projection(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Color godotsharp_variant_as_color(godot_variant* p_self); + public static extern Color godotsharp_variant_as_color(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_string_name godotsharp_variant_as_string_name(godot_variant* p_self); + public static extern godot_string_name godotsharp_variant_as_string_name(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_node_path godotsharp_variant_as_node_path(godot_variant* p_self); + public static extern godot_node_path godotsharp_variant_as_node_path(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern RID godotsharp_variant_as_rid(godot_variant* p_self); + public static extern RID godotsharp_variant_as_rid(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_callable godotsharp_variant_as_callable(godot_variant* p_self); + public static extern godot_callable godotsharp_variant_as_callable(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_signal godotsharp_variant_as_signal(godot_variant* p_self); + public static extern godot_signal godotsharp_variant_as_signal(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_dictionary godotsharp_variant_as_dictionary(godot_variant* p_self); + public static extern godot_dictionary godotsharp_variant_as_dictionary(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_array godotsharp_variant_as_array(godot_variant* p_self); + public static extern godot_array godotsharp_variant_as_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(godot_variant* p_self); + public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(godot_variant* p_self); + public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(godot_variant* p_self); + public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_float32_array godotsharp_variant_as_packed_float32_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_float64_array godotsharp_variant_as_packed_float64_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(godot_variant* p_self); + public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array( + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(godot_variant* p_self); + public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_variant_equals(godot_variant* p_a, godot_variant* p_b); + public static extern godot_bool godotsharp_variant_equals(in godot_variant p_a, in godot_variant p_b); // string.h [DllImport(GodotDllName)] - public static extern void godotsharp_string_new_with_utf16_chars(godot_string* r_dest, char* p_contents); + public static extern void godotsharp_string_new_with_utf16_chars(out godot_string r_dest, char* p_contents); // string_name.h [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_new_copy(godot_string_name* r_dest, godot_string_name* p_src); + public static extern void godotsharp_string_name_new_copy(out godot_string_name r_dest, + in godot_string_name p_src); // node_path.h [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_new_copy(godot_node_path* r_dest, godot_node_path* p_src); + public static extern void godotsharp_node_path_new_copy(out godot_node_path r_dest, in godot_node_path p_src); // array.h [DllImport(GodotDllName)] - public static extern void godotsharp_array_new(godot_array* p_self); + public static extern void godotsharp_array_new(out godot_array r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_array_new_copy(godot_array* r_dest, godot_array* p_src); + public static extern void godotsharp_array_new_copy(out godot_array r_dest, in godot_array p_src); [DllImport(GodotDllName)] public static extern godot_variant* godotsharp_array_ptrw(ref godot_array p_self); @@ -365,10 +388,11 @@ namespace Godot.NativeInterop // dictionary.h [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_new(godot_dictionary* p_self); + public static extern void godotsharp_dictionary_new(out godot_dictionary r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_new_copy(godot_dictionary* r_dest, godot_dictionary* p_src); + public static extern void godotsharp_dictionary_new_copy(out godot_dictionary r_dest, + in godot_dictionary p_src); // destroy functions @@ -426,17 +450,17 @@ namespace Godot.NativeInterop // Array [DllImport(GodotDllName)] - public static extern int godotsharp_array_add(ref godot_array p_self, godot_variant* p_item); + public static extern int godotsharp_array_add(ref godot_array p_self, in godot_variant p_item); [DllImport(GodotDllName)] public static extern void godotsharp_array_duplicate(ref godot_array p_self, godot_bool p_deep, out godot_array r_dest); [DllImport(GodotDllName)] - public static extern int godotsharp_array_index_of(ref godot_array p_self, godot_variant* p_item); + public static extern int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item); [DllImport(GodotDllName)] - public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, godot_variant* p_item); + public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, in godot_variant p_item); [DllImport(GodotDllName)] public static extern void godotsharp_array_remove_at(ref godot_array p_self, int p_index); @@ -448,18 +472,18 @@ namespace Godot.NativeInterop public static extern Error godotsharp_array_shuffle(ref godot_array p_self); [DllImport(GodotDllName)] - public static extern void godotsharp_array_to_string(ref godot_array p_self, godot_string* r_str); + public static extern void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str); // Dictionary [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_try_get_value(ref godot_dictionary p_self, - godot_variant* p_key, + in godot_variant p_key, out godot_variant r_value); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, godot_variant* p_key, - godot_variant* p_value); + public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, in godot_variant p_key, + in godot_variant p_value); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_keys(ref godot_dictionary p_self, out godot_array r_dest); @@ -475,15 +499,15 @@ namespace Godot.NativeInterop out godot_variant r_key, out godot_variant r_value); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, godot_variant* p_key, - godot_variant* p_value); + public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, in godot_variant p_key, + in godot_variant p_value); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_clear(ref godot_dictionary p_self); [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_contains_key(ref godot_dictionary p_self, - godot_variant* p_key); + in godot_variant p_key); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_duplicate(ref godot_dictionary p_self, godot_bool p_deep, @@ -491,149 +515,153 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_remove_key(ref godot_dictionary p_self, - godot_variant* p_key); + in godot_variant p_key); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, godot_string* r_str); + public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, out godot_string r_str); // StringExtensions [DllImport(GodotDllName)] - public static extern void godotsharp_string_md5_buffer(godot_string* p_self, - godot_packed_byte_array* r_md5_buffer); + public static extern void godotsharp_string_md5_buffer(in godot_string p_self, + out godot_packed_byte_array r_md5_buffer); [DllImport(GodotDllName)] - public static extern void godotsharp_string_md5_text(godot_string* p_self, godot_string* r_md5_text); + public static extern void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text); [DllImport(GodotDllName)] - public static extern int godotsharp_string_rfind(godot_string* p_self, godot_string* p_what, int p_from); + public static extern int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from); [DllImport(GodotDllName)] - public static extern int godotsharp_string_rfindn(godot_string* p_self, godot_string* p_what, int p_from); + public static extern int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from); [DllImport(GodotDllName)] - public static extern void godotsharp_string_sha256_buffer(godot_string* p_self, - godot_packed_byte_array* r_sha256_buffer); + public static extern void godotsharp_string_sha256_buffer(in godot_string p_self, + out godot_packed_byte_array r_sha256_buffer); [DllImport(GodotDllName)] - public static extern void godotsharp_string_sha256_text(godot_string* p_self, godot_string* r_sha256_text); + public static extern void godotsharp_string_sha256_text(in godot_string p_self, + out godot_string r_sha256_text); [DllImport(GodotDllName)] - public static extern void godotsharp_string_simplify_path(godot_string* p_self, godot_string* r_simplified_path); + public static extern void godotsharp_string_simplify_path(in godot_string p_self, + out godot_string r_simplified_path); // NodePath [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_as_property_path(ref godot_node_path p_self, + public static extern void godotsharp_node_path_get_as_property_path(in godot_node_path p_self, ref godot_node_path r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_concatenated_names(ref godot_node_path p_self, - godot_string* r_names); + public static extern void godotsharp_node_path_get_concatenated_names(in godot_node_path p_self, + out godot_string r_names); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_concatenated_subnames(ref godot_node_path p_self, - godot_string* r_subnames); + public static extern void godotsharp_node_path_get_concatenated_subnames(in godot_node_path p_self, + out godot_string r_subnames); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_name(ref godot_node_path p_self, int p_idx, - godot_string* r_name); + public static extern void godotsharp_node_path_get_name(in godot_node_path p_self, int p_idx, + out godot_string r_name); [DllImport(GodotDllName)] - public static extern int godotsharp_node_path_get_name_count(ref godot_node_path p_self); + public static extern int godotsharp_node_path_get_name_count(in godot_node_path p_self); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_subname(ref godot_node_path p_self, int p_idx, - godot_string* r_subname); + public static extern void godotsharp_node_path_get_subname(in godot_node_path p_self, int p_idx, + out godot_string r_subname); [DllImport(GodotDllName)] - public static extern int godotsharp_node_path_get_subname_count(ref godot_node_path p_self); + public static extern int godotsharp_node_path_get_subname_count(in godot_node_path p_self); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_node_path_is_absolute(ref godot_node_path p_self); + public static extern godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self); // GD, etc [DllImport(GodotDllName)] - public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, godot_bool p_allow_objects, - godot_variant* r_ret); + internal static extern void godotsharp_bytes2var(in godot_packed_byte_array p_bytes, + godot_bool p_allow_objects, + out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_convert(godot_variant* p_what, int p_type, godot_variant* r_ret); + internal static extern void godotsharp_convert(in godot_variant p_what, int p_type, + out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern int godotsharp_hash(godot_variant* var); + internal static extern int godotsharp_hash(in godot_variant p_var); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_instance_from_id(ulong instanceId); + internal static extern IntPtr godotsharp_instance_from_id(ulong p_instance_id); [DllImport(GodotDllName)] - public static extern void godotsharp_print(godot_string* p_what); + internal static extern void godotsharp_print(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_print_rich(godot_string* p_what); + public static extern void godotsharp_print_rich(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printerr(godot_string* p_what); + internal static extern void godotsharp_printerr(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printraw(godot_string* p_what); + internal static extern void godotsharp_printraw(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_prints(godot_string* p_what); + internal static extern void godotsharp_prints(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printt(godot_string* p_what); + internal static extern void godotsharp_printt(in godot_string p_what); [DllImport(GodotDllName)] - public static extern float godotsharp_randf(); + internal static extern float godotsharp_randf(); [DllImport(GodotDllName)] - public static extern uint godotsharp_randi(); + internal static extern uint godotsharp_randi(); [DllImport(GodotDllName)] - public static extern void godotsharp_randomize(); + internal static extern void godotsharp_randomize(); [DllImport(GodotDllName)] - public static extern double godotsharp_randf_range(double from, double to); + internal static extern double godotsharp_randf_range(double from, double to); [DllImport(GodotDllName)] - public static extern double godotsharp_randfn(double mean, double deviation); + internal static extern double godotsharp_randfn(double mean, double deviation); [DllImport(GodotDllName)] - public static extern int godotsharp_randi_range(int from, int to); + internal static extern int godotsharp_randi_range(int from, int to); [DllImport(GodotDllName)] - public static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed); + internal static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed); [DllImport(GodotDllName)] - public static extern void godotsharp_seed(ulong seed); + internal static extern void godotsharp_seed(ulong seed); [DllImport(GodotDllName)] - public static extern void godotsharp_weakref(IntPtr obj, godot_ref* r_weak_ref); + internal static extern void godotsharp_weakref(IntPtr p_obj, out godot_ref r_weak_ref); [DllImport(GodotDllName)] - public static extern string godotsharp_str(godot_array* p_what, godot_string* r_ret); + internal static extern void godotsharp_str(in godot_array p_what, out godot_string r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret); + internal static extern void godotsharp_str2var(in godot_string p_str, out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_var2bytes(godot_variant* what, godot_bool fullObjects, - godot_packed_byte_array* bytes); + internal static extern void godotsharp_var2bytes(in godot_variant p_what, godot_bool p_full_objects, + out godot_packed_byte_array r_bytes); [DllImport(GodotDllName)] - public static extern void godotsharp_var2str(godot_variant* var, godot_string* r_ret); + internal static extern void godotsharp_var2str(in godot_variant p_var, out godot_string r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_pusherror(godot_string* type); + internal static extern void godotsharp_pusherror(in godot_string p_str); [DllImport(GodotDllName)] - public static extern void godotsharp_pushwarning(godot_string* type); + internal static extern void godotsharp_pushwarning(in godot_string p_str); // Object [DllImport(GodotDllName)] - public static extern string godotsharp_object_to_string(IntPtr ptr, godot_string* r_str); + public static extern void godotsharp_object_to_string(IntPtr ptr, out godot_string r_str); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs index 089883c7e8f..0c49660cf0e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs @@ -1,83 +1,60 @@ -using System; -using System.Runtime.CompilerServices; - // ReSharper disable InconsistentNaming namespace Godot.NativeInterop { - public static unsafe partial class NativeFuncs + public static partial class NativeFuncs { - public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src) + public static godot_string_name godotsharp_string_name_new_copy(in godot_string_name src) { - godot_string_name ret; - godotsharp_string_name_new_copy(&ret, src); + if (src.IsEmpty) + return default; + godotsharp_string_name_new_copy(out godot_string_name ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_string_name godotsharp_string_name_new_copy(godot_string_name src) - => godotsharp_string_name_new_copy(&src); - - public static godot_node_path godotsharp_node_path_new_copy(godot_node_path* src) + public static godot_node_path godotsharp_node_path_new_copy(in godot_node_path src) { - godot_node_path ret; - godotsharp_node_path_new_copy(&ret, src); + if (src.IsEmpty) + return default; + godotsharp_node_path_new_copy(out godot_node_path ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_node_path godotsharp_node_path_new_copy(godot_node_path src) - => godotsharp_node_path_new_copy(&src); - public static godot_array godotsharp_array_new() { - godot_array ret; - godotsharp_array_new(&ret); + godotsharp_array_new(out godot_array ret); return ret; } - public static godot_array godotsharp_array_new_copy(godot_array* src) + public static godot_array godotsharp_array_new_copy(in godot_array src) { - godot_array ret; - godotsharp_array_new_copy(&ret, src); + godotsharp_array_new_copy(out godot_array ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_array godotsharp_array_new_copy(godot_array src) - => godotsharp_array_new_copy(&src); - public static godot_dictionary godotsharp_dictionary_new() { - godot_dictionary ret; - godotsharp_dictionary_new(&ret); + godotsharp_dictionary_new(out godot_dictionary ret); return ret; } - public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary* src) + public static godot_dictionary godotsharp_dictionary_new_copy(in godot_dictionary src) { - godot_dictionary ret; - godotsharp_dictionary_new_copy(&ret, src); + godotsharp_dictionary_new_copy(out godot_dictionary ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary src) - => godotsharp_dictionary_new_copy(&src); - public static godot_string_name godotsharp_string_name_new_from_string(string name) { - godot_string_name ret; - using godot_string src = Marshaling.mono_string_to_godot(name); - godotsharp_string_name_new_from_string(&ret, &src); + using godot_string src = Marshaling.ConvertStringToNative(name); + godotsharp_string_name_new_from_string(out godot_string_name ret, src); return ret; } public static godot_node_path godotsharp_node_path_new_from_string(string name) { - godot_node_path ret; - using godot_string src = Marshaling.mono_string_to_godot(name); - godotsharp_node_path_new_from_string(&ret, &src); + using godot_string src = Marshaling.ConvertStringToNative(name); + godotsharp_node_path_new_from_string(out godot_node_path ret, src); return ret; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs new file mode 100644 index 00000000000..422df74c236 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs @@ -0,0 +1,20 @@ +using System.Runtime.CompilerServices; + +namespace Godot.NativeInterop +{ + // Our source generators will add trampolines methods that access variant arguments. + // This struct makes that possible without having to enable `AllowUnsafeBlocks` in game projects. + + public unsafe ref struct NativeVariantPtrArgs + { + private godot_variant** _args; + + internal NativeVariantPtrArgs(godot_variant** args) => _args = args; + + public ref godot_variant this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref *_args[index]; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs index 2814f9d506b..46f31bbf4ec 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs @@ -2,13 +2,13 @@ using System; namespace Godot.NativeInterop { - internal ref struct VariantSpanDisposer + internal readonly ref struct VariantSpanDisposer { - private readonly Span _variantSpan; + private readonly Span _variantSpan; // IMPORTANT: The span element must be default initialized. // Make sure call Clear() on the span if it was created with stackalloc. - public VariantSpanDisposer(Span variantSpan) + public VariantSpanDisposer(Span variantSpan) { _variantSpan = variantSpan; } @@ -16,7 +16,7 @@ namespace Godot.NativeInterop public void Dispose() { for (int i = 0; i < _variantSpan.Length; i++) - _variantSpan[i].Dispose(); + _variantSpan[i].DangerousSelfRef.Dispose(); } } @@ -24,7 +24,7 @@ namespace Godot.NativeInterop { // Used to make sure we always initialize the span values to the default, // as we need that in order to safely dispose all elements after. - public static Span Cleared(this Span span) + public static Span Cleared(this Span span) { span.Clear(); return span; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index e52454a2e33..f69cc40314a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; // ReSharper disable InconsistentNaming @@ -8,378 +7,353 @@ namespace Godot.NativeInterop public static class VariantUtils { public static godot_variant CreateFromRID(RID from) - => new() { _type = Variant.Type.Rid, _data = { _m_rid = from } }; + => new() { Type = Variant.Type.Rid, RID = from }; public static godot_variant CreateFromBool(bool from) - => new() { _type = Variant.Type.Bool, _data = { _bool = from.ToGodotBool() } }; + => new() { Type = Variant.Type.Bool, Bool = from.ToGodotBool() }; public static godot_variant CreateFromInt(long from) - => new() { _type = Variant.Type.Int, _data = { _int = from } }; + => new() { Type = Variant.Type.Int, Int = from }; public static godot_variant CreateFromInt(ulong from) - => new() { _type = Variant.Type.Int, _data = { _int = (long)from } }; + => new() { Type = Variant.Type.Int, Int = (long)from }; public static godot_variant CreateFromFloat(double from) - => new() { _type = Variant.Type.Float, _data = { _float = from } }; + => new() { Type = Variant.Type.Float, Float = from }; public static godot_variant CreateFromVector2(Vector2 from) - => new() { _type = Variant.Type.Vector2, _data = { _m_vector2 = from } }; + => new() { Type = Variant.Type.Vector2, Vector2 = from }; public static godot_variant CreateFromVector2i(Vector2i from) - => new() { _type = Variant.Type.Vector2i, _data = { _m_vector2i = from } }; + => new() { Type = Variant.Type.Vector2i, Vector2i = from }; public static godot_variant CreateFromVector3(Vector3 from) - => new() { _type = Variant.Type.Vector3, _data = { _m_vector3 = from } }; + => new() { Type = Variant.Type.Vector3, Vector3 = from }; public static godot_variant CreateFromVector3i(Vector3i from) - => new() { _type = Variant.Type.Vector3i, _data = { _m_vector3i = from } }; + => new() { Type = Variant.Type.Vector3i, Vector3i = from }; public static godot_variant CreateFromRect2(Rect2 from) - => new() { _type = Variant.Type.Rect2, _data = { _m_rect2 = from } }; + => new() { Type = Variant.Type.Rect2, Rect2 = from }; public static godot_variant CreateFromRect2i(Rect2i from) - => new() { _type = Variant.Type.Rect2i, _data = { _m_rect2i = from } }; + => new() { Type = Variant.Type.Rect2i, Rect2i = from }; public static godot_variant CreateFromQuaternion(Quaternion from) - => new() { _type = Variant.Type.Quaternion, _data = { _m_quaternion = from } }; + => new() { Type = Variant.Type.Quaternion, Quaternion = from }; public static godot_variant CreateFromColor(Color from) - => new() { _type = Variant.Type.Color, _data = { _m_color = from } }; + => new() { Type = Variant.Type.Color, Color = from }; public static godot_variant CreateFromPlane(Plane from) - => new() { _type = Variant.Type.Plane, _data = { _m_plane = from } }; + => new() { Type = Variant.Type.Plane, Plane = from }; - public static unsafe godot_variant CreateFromTransform2D(Transform2D from) + public static godot_variant CreateFromTransform2D(Transform2D from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_transform2d(&ret, &from); + NativeFuncs.godotsharp_variant_new_transform2d(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromVector4(Vector4 from) + public static godot_variant CreateFromVector4(Vector4 from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_vector4(&ret, &from); + NativeFuncs.godotsharp_variant_new_vector4(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromVector4i(Vector4i from) + public static godot_variant CreateFromVector4i(Vector4i from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_vector4i(&ret, &from); + NativeFuncs.godotsharp_variant_new_vector4i(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromBasis(Basis from) + public static godot_variant CreateFromBasis(Basis from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_basis(&ret, &from); + NativeFuncs.godotsharp_variant_new_basis(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromTransform3D(Transform3D from) + public static godot_variant CreateFromTransform3D(Transform3D from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_transform3d(&ret, &from); + NativeFuncs.godotsharp_variant_new_transform3d(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromProjection(Projection from) + public static godot_variant CreateFromProjection(Projection from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_projection(&ret, &from); + NativeFuncs.godotsharp_variant_new_projection(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromAABB(AABB from) + public static godot_variant CreateFromAABB(AABB from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_aabb(&ret, &from); + NativeFuncs.godotsharp_variant_new_aabb(out godot_variant ret, from); return ret; } // Explicit name to make it very clear public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from) - => new() { _type = Variant.Type.Callable, _data = { _m_callable = from } }; + => new() { Type = Variant.Type.Callable, Callable = from }; // Explicit name to make it very clear public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from) - => new() { _type = Variant.Type.Signal, _data = { _m_signal = from } }; + => new() { Type = Variant.Type.Signal, Signal = from }; // Explicit name to make it very clear public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from) - => new() { _type = Variant.Type.String, _data = { _m_string = from } }; + => new() { Type = Variant.Type.String, String = from }; - public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from) + public static godot_variant CreateFromPackedByteArray(in godot_packed_byte_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_byte_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_byte_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedInt32Array(godot_packed_int32_array* from) + public static godot_variant CreateFromPackedInt32Array(in godot_packed_int32_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_int32_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_int32_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedInt64Array(godot_packed_int64_array* from) + public static godot_variant CreateFromPackedInt64Array(in godot_packed_int64_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_int64_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_int64_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedFloat32Array(godot_packed_float32_array* from) + public static godot_variant CreateFromPackedFloat32Array(in godot_packed_float32_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_float32_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_float32_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedFloat64Array(godot_packed_float64_array* from) + public static godot_variant CreateFromPackedFloat64Array(in godot_packed_float64_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_float64_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_float64_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedStringArray(godot_packed_string_array* from) + public static godot_variant CreateFromPackedStringArray(in godot_packed_string_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_string_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_string_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedVector2Array(godot_packed_vector2_array* from) + public static godot_variant CreateFromPackedVector2Array(in godot_packed_vector2_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_vector2_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_vector2_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedVector3Array(godot_packed_vector3_array* from) + public static godot_variant CreateFromPackedVector3Array(in godot_packed_vector3_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_vector3_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_vector3_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedColorArray(godot_packed_color_array* from) + public static godot_variant CreateFromPackedColorArray(in godot_packed_color_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_color_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_color_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromArray(godot_array* from) + public static godot_variant CreateFromArray(godot_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_array(&ret, from); + NativeFuncs.godotsharp_variant_new_array(out godot_variant ret, from); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe godot_variant CreateFromArray(godot_array from) - => CreateFromArray(&from); - - public static unsafe godot_variant CreateFromDictionary(godot_dictionary* from) + public static godot_variant CreateFromDictionary(godot_dictionary from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_dictionary(&ret, from); + NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe godot_variant CreateFromDictionary(godot_dictionary from) - => CreateFromDictionary(&from); - - public static unsafe godot_variant CreateFromStringName(ref godot_string_name arg1) + public static godot_variant CreateFromStringName(godot_string_name from) { - godot_variant ret; - godot_string_name src = arg1; - NativeFuncs.godotsharp_variant_new_string_name(&ret, &src); + NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromNodePath(ref godot_node_path arg1) + public static godot_variant CreateFromNodePath(godot_node_path from) { - godot_variant ret; - godot_node_path src = arg1; - NativeFuncs.godotsharp_variant_new_node_path(&ret, &src); + NativeFuncs.godotsharp_variant_new_node_path(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromGodotObject(IntPtr from) + public static godot_variant CreateFromGodotObject(IntPtr from) { if (from == IntPtr.Zero) return new godot_variant(); - godot_variant ret; - NativeFuncs.godotsharp_variant_new_object(&ret, from); + NativeFuncs.godotsharp_variant_new_object(out godot_variant ret, from); return ret; } // We avoid the internal call if the stored type is the same we want. - public static unsafe bool ConvertToBool(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Bool ? - (*p_var)._data._bool.ToBool() : + public static bool ConvertToBool(in godot_variant p_var) + => p_var.Type == Variant.Type.Bool ? + p_var.Bool.ToBool() : NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool(); - public static unsafe char ConvertToChar(godot_variant* p_var) - => (char)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static char ConvertToChar(in godot_variant p_var) + => (char)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe sbyte ConvertToInt8(godot_variant* p_var) - => (sbyte)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static sbyte ConvertToInt8(in godot_variant p_var) + => (sbyte)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int16 ConvertToInt16(godot_variant* p_var) - => (Int16)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static Int16 ConvertToInt16(in godot_variant p_var) + => (Int16)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int32 ConvertToInt32(godot_variant* p_var) - => (Int32)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static Int32 ConvertToInt32(in godot_variant p_var) + => (Int32)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int64 ConvertToInt64(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var); + public static Int64 ConvertToInt64(in godot_variant p_var) + => p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var); - public static unsafe byte ConvertToUInt8(godot_variant* p_var) - => (byte)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static byte ConvertToUInt8(in godot_variant p_var) + => (byte)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt16 ConvertToUInt16(godot_variant* p_var) - => (UInt16)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt16 ConvertToUInt16(in godot_variant p_var) + => (UInt16)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt32 ConvertToUInt32(godot_variant* p_var) - => (UInt32)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt32 ConvertToUInt32(in godot_variant p_var) + => (UInt32)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt64 ConvertToUInt64(godot_variant* p_var) - => (UInt64)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt64 ConvertToUInt64(in godot_variant p_var) + => (UInt64)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe float ConvertToFloat32(godot_variant* p_var) - => (float)((*p_var)._type == Variant.Type.Float ? - (*p_var)._data._float : + public static float ConvertToFloat32(in godot_variant p_var) + => (float)(p_var.Type == Variant.Type.Float ? + p_var.Float : NativeFuncs.godotsharp_variant_as_float(p_var)); - public static unsafe double ConvertToFloat64(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Float ? - (*p_var)._data._float : + public static double ConvertToFloat64(in godot_variant p_var) + => p_var.Type == Variant.Type.Float ? + p_var.Float : NativeFuncs.godotsharp_variant_as_float(p_var); - public static unsafe Vector2 ConvertToVector2(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector2 ? - (*p_var)._data._m_vector2 : + public static Vector2 ConvertToVector2(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector2 ? + p_var.Vector2 : NativeFuncs.godotsharp_variant_as_vector2(p_var); - public static unsafe Vector2i ConvertToVector2i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector2i ? - (*p_var)._data._m_vector2i : + public static Vector2i ConvertToVector2i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector2i ? + p_var.Vector2i : NativeFuncs.godotsharp_variant_as_vector2i(p_var); - public static unsafe Rect2 ConvertToRect2(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rect2 ? - (*p_var)._data._m_rect2 : + public static Rect2 ConvertToRect2(in godot_variant p_var) + => p_var.Type == Variant.Type.Rect2 ? + p_var.Rect2 : NativeFuncs.godotsharp_variant_as_rect2(p_var); - public static unsafe Rect2i ConvertToRect2i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rect2i ? - (*p_var)._data._m_rect2i : + public static Rect2i ConvertToRect2i(in godot_variant p_var) + => p_var.Type == Variant.Type.Rect2i ? + p_var.Rect2i : NativeFuncs.godotsharp_variant_as_rect2i(p_var); - public static unsafe Transform2D ConvertToTransform2D(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Transform2d ? - *(*p_var)._data._transform2d : + public static unsafe Transform2D ConvertToTransform2D(in godot_variant p_var) + => p_var.Type == Variant.Type.Transform2d ? + *p_var.Transform2D : NativeFuncs.godotsharp_variant_as_transform2d(p_var); - public static unsafe Vector3 ConvertToVector3(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector3 ? - (*p_var)._data._m_vector3 : + public static Vector3 ConvertToVector3(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector3 ? + p_var.Vector3 : NativeFuncs.godotsharp_variant_as_vector3(p_var); - public static unsafe Vector3i ConvertToVector3i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector3i ? - (*p_var)._data._m_vector3i : + public static Vector3i ConvertToVector3i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector3i ? + p_var.Vector3i : NativeFuncs.godotsharp_variant_as_vector3i(p_var); - public static unsafe Vector4 ConvertToVector4(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var); + public static unsafe Vector4 ConvertToVector4(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector4 ? + *p_var.Vector4 : + NativeFuncs.godotsharp_variant_as_vector4(p_var); - public static unsafe Vector4i ConvertToVector4i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var); + public static unsafe Vector4i ConvertToVector4i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector4i ? + *p_var.Vector4i : + NativeFuncs.godotsharp_variant_as_vector4i(p_var); - public static unsafe Basis ConvertToBasis(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Basis ? - *(*p_var)._data._basis : + public static unsafe Basis ConvertToBasis(in godot_variant p_var) + => p_var.Type == Variant.Type.Basis ? + *p_var.Basis : NativeFuncs.godotsharp_variant_as_basis(p_var); - public static unsafe Quaternion ConvertToQuaternion(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Quaternion ? - (*p_var)._data._m_quaternion : + public static Quaternion ConvertToQuaternion(in godot_variant p_var) + => p_var.Type == Variant.Type.Quaternion ? + p_var.Quaternion : NativeFuncs.godotsharp_variant_as_quaternion(p_var); - public static unsafe Transform3D ConvertToTransform3D(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Transform3d ? - *(*p_var)._data._transform3d : + public static unsafe Transform3D ConvertToTransform3D(in godot_variant p_var) + => p_var.Type == Variant.Type.Transform3d ? + *p_var.Transform3D : NativeFuncs.godotsharp_variant_as_transform3d(p_var); - public static unsafe Projection ConvertToProjection(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var); + public static unsafe Projection ConvertToProjection(in godot_variant p_var) + => p_var.Type == Variant.Type.Projection ? + *p_var.Projection : + NativeFuncs.godotsharp_variant_as_projection(p_var); - public static unsafe AABB ConvertToAABB(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Aabb ? - *(*p_var)._data._aabb : + public static unsafe AABB ConvertToAABB(in godot_variant p_var) + => p_var.Type == Variant.Type.Aabb ? + *p_var.AABB : NativeFuncs.godotsharp_variant_as_aabb(p_var); - public static unsafe Color ConvertToColor(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Color ? - (*p_var)._data._m_color : + public static Color ConvertToColor(in godot_variant p_var) + => p_var.Type == Variant.Type.Color ? + p_var.Color : NativeFuncs.godotsharp_variant_as_color(p_var); - public static unsafe Plane ConvertToPlane(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Plane ? - (*p_var)._data._m_plane : + public static Plane ConvertToPlane(in godot_variant p_var) + => p_var.Type == Variant.Type.Plane ? + p_var.Plane : NativeFuncs.godotsharp_variant_as_plane(p_var); - public static unsafe IntPtr ConvertToGodotObject(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Object ? (*p_var)._data._m_obj_data.obj : IntPtr.Zero; + public static IntPtr ConvertToGodotObject(in godot_variant p_var) + => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero; - public static unsafe RID ConvertToRID(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rid ? - (*p_var)._data._m_rid : + public static RID ConvertToRID(in godot_variant p_var) + => p_var.Type == Variant.Type.Rid ? + p_var.RID : NativeFuncs.godotsharp_variant_as_rid(p_var); - public static unsafe godot_string_name ConvertToStringName(godot_variant* p_var) - => (*p_var)._type == Variant.Type.StringName ? - NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name) : + public static godot_string_name ConvertToStringName(in godot_variant p_var) + => p_var.Type == Variant.Type.StringName ? + NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) : NativeFuncs.godotsharp_variant_as_string_name(p_var); - public static unsafe godot_node_path ConvertToNodePath(godot_variant* p_var) - => (*p_var)._type == Variant.Type.NodePath ? - NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path) : + public static godot_node_path ConvertToNodePath(in godot_variant p_var) + => p_var.Type == Variant.Type.NodePath ? + NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) : NativeFuncs.godotsharp_variant_as_node_path(p_var); - public static unsafe godot_array ConvertToArray(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Array ? - NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array) : + public static godot_array ConvertToArray(in godot_variant p_var) + => p_var.Type == Variant.Type.Array ? + NativeFuncs.godotsharp_array_new_copy(p_var.Array) : NativeFuncs.godotsharp_variant_as_array(p_var); - public static unsafe godot_dictionary ConvertToDictionary(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Dictionary ? - NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary) : + public static godot_dictionary ConvertToDictionary(in godot_variant p_var) + => p_var.Type == Variant.Type.Dictionary ? + NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) : NativeFuncs.godotsharp_variant_as_dictionary(p_var); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs index b18606b47e7..d7b736fbcf0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -42,7 +41,7 @@ namespace Godot /// public sealed class NodePath : IDisposable { - public godot_node_path NativeValue; + internal godot_node_path.movable NativeValue; ~NodePath() { @@ -61,12 +60,12 @@ namespace Godot public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } private NodePath(godot_node_path nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_node_path.movable)nativeValueToOwn; } // Explicit name to make it very clear @@ -112,7 +111,7 @@ namespace Godot public NodePath(string path) { if (!string.IsNullOrEmpty(path)) - NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path); + NativeValue = (godot_node_path.movable)NativeFuncs.godotsharp_node_path_new_from_string(path); } /// @@ -125,22 +124,21 @@ namespace Godot /// Converts this to a string. /// /// The to convert. - public static implicit operator string(NodePath from) => from.ToString(); + public static implicit operator string(NodePath from) => from?.ToString(); /// /// Converts this to a string. /// /// A string representation of this . - public override unsafe string ToString() + public override string ToString() { if (IsEmpty) return string.Empty; - godot_string dest; - godot_node_path src = NativeValue; - NativeFuncs.godotsharp_node_path_as_string(&dest, &src); + var src = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_as_string(out godot_string dest, src); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } /// @@ -161,7 +159,8 @@ namespace Godot public NodePath GetAsPropertyPath() { godot_node_path propertyPath = default; - NativeFuncs.godotsharp_node_path_get_as_property_path(ref NativeValue, ref propertyPath); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_as_property_path(self, ref propertyPath); return CreateTakingOwnershipOfDisposableValue(propertyPath); } @@ -175,11 +174,12 @@ namespace Godot /// /// /// The names concatenated with /. - public unsafe string GetConcatenatedNames() + public string GetConcatenatedNames() { - using godot_string names = default; - NativeFuncs.godotsharp_node_path_get_concatenated_names(ref NativeValue, &names); - return Marshaling.mono_string_from_godot(names); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_concatenated_names(self, out godot_string names); + using (names) + return Marshaling.ConvertStringToManaged(names); } /// @@ -193,11 +193,12 @@ namespace Godot /// /// /// The subnames concatenated with :. - public unsafe string GetConcatenatedSubNames() + public string GetConcatenatedSubNames() { - using godot_string subNames = default; - NativeFuncs.godotsharp_node_path_get_concatenated_subnames(ref NativeValue, &subNames); - return Marshaling.mono_string_from_godot(subNames); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_concatenated_subnames(self, out godot_string subNames); + using (subNames) + return Marshaling.ConvertStringToManaged(subNames); } /// @@ -213,11 +214,12 @@ namespace Godot /// /// The name index. /// The name at the given index . - public unsafe string GetName(int idx) + public string GetName(int idx) { - using godot_string name = default; - NativeFuncs.godotsharp_node_path_get_name(ref NativeValue, idx, &name); - return Marshaling.mono_string_from_godot(name); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_name(self, idx, out godot_string name); + using (name) + return Marshaling.ConvertStringToManaged(name); } /// @@ -228,7 +230,8 @@ namespace Godot /// The number of node names which make up the path. public int GetNameCount() { - return NativeFuncs.godotsharp_node_path_get_name_count(ref NativeValue); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_get_name_count(self); } /// @@ -236,11 +239,12 @@ namespace Godot /// /// The subname index. /// The subname at the given index . - public unsafe string GetSubName(int idx) + public string GetSubName(int idx) { - using godot_string subName = default; - NativeFuncs.godotsharp_node_path_get_subname(ref NativeValue, idx, &subName); - return Marshaling.mono_string_from_godot(subName); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_subname(self, idx, out godot_string subName); + using (subName) + return Marshaling.ConvertStringToManaged(subName); } /// @@ -251,7 +255,8 @@ namespace Godot /// The number of subnames in the path. public int GetSubNameCount() { - return NativeFuncs.godotsharp_node_path_get_subname_count(ref NativeValue); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_get_subname_count(self); } /// @@ -263,13 +268,14 @@ namespace Godot /// If the is an absolute path. public bool IsAbsolute() { - return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue).ToBool(); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_is_absolute(self).ToBool(); } /// /// Returns if the node path is empty. /// /// If the is empty. - public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue); + public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 98266ffdfcf..5f4dc50c729 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -47,16 +46,13 @@ namespace Godot while (top != null && top != native) { foreach (var eventSignal in top.GetEvents( - BindingFlags.DeclaredOnly | BindingFlags.Instance | - BindingFlags.NonPublic | BindingFlags.Public) - .Where(ev => ev.GetCustomAttributes().OfType().Any())) + BindingFlags.DeclaredOnly | BindingFlags.Instance | + BindingFlags.NonPublic | BindingFlags.Public) + .Where(ev => ev.GetCustomAttributes().OfType().Any())) { - unsafe - { - using var eventSignalName = new StringName(eventSignal.Name); - godot_string_name eventSignalNameAux = eventSignalName.NativeValue; - NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, &eventSignalNameAux); - } + using var eventSignalName = new StringName(eventSignal.Name); + var eventSignalNameSelf = (godot_string_name)eventSignalName.NativeValue; + NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, eventSignalNameSelf); } top = top.BaseType; @@ -128,11 +124,11 @@ namespace Godot /// Converts this to a string. /// /// A string representation of this object. - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_object_to_string(GetPtr(this), &str); - return Marshaling.mono_string_from_godot(str); + NativeFuncs.godotsharp_object_to_string(GetPtr(this), out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } /// @@ -189,7 +185,7 @@ namespace Godot return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor"; } - internal unsafe bool InternalGodotScriptCallViaReflection(string method, godot_variant** args, int argCount, + internal bool InternalGodotScriptCallViaReflection(string method, NativeVariantPtrArgs args, int argCount, out godot_variant ret) { // Performance is not critical here as this will be replaced with source generators. @@ -213,13 +209,13 @@ namespace Godot for (int i = 0; i < paramCount; i++) { - invokeParams[i] = Marshaling.variant_to_mono_object_of_type( + invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType( args[i], parameters[i].ParameterType); } object retObj = methodInfo.Invoke(this, invokeParams); - ret = Marshaling.mono_object_to_variant(retObj); + ret = Marshaling.ConvertManagedObjectToVariant(retObj); return true; } } @@ -231,7 +227,7 @@ namespace Godot return false; } - internal unsafe bool InternalGodotScriptSetFieldOrPropViaReflection(string name, godot_variant* value) + internal bool InternalGodotScriptSetFieldOrPropViaReflection(string name, in godot_variant value) { // Performance is not critical here as this will be replaced with source generators. Type top = GetType(); @@ -245,7 +241,7 @@ namespace Godot if (fieldInfo != null) { - object valueManaged = Marshaling.variant_to_mono_object_of_type(value, fieldInfo.FieldType); + object valueManaged = Marshaling.ConvertVariantToManagedObjectOfType(value, fieldInfo.FieldType); fieldInfo.SetValue(this, valueManaged); return true; @@ -257,7 +253,8 @@ namespace Godot if (propertyInfo != null) { - object valueManaged = Marshaling.variant_to_mono_object_of_type(value, propertyInfo.PropertyType); + object valueManaged = + Marshaling.ConvertVariantToManagedObjectOfType(value, propertyInfo.PropertyType); propertyInfo.SetValue(this, valueManaged); return true; @@ -284,7 +281,7 @@ namespace Godot if (fieldInfo != null) { object valueManaged = fieldInfo.GetValue(this); - value = Marshaling.mono_object_to_variant(valueManaged); + value = Marshaling.ConvertManagedObjectToVariant(valueManaged); return true; } @@ -295,7 +292,7 @@ namespace Godot if (propertyInfo != null) { object valueManaged = propertyInfo.GetValue(this); - value = Marshaling.mono_object_to_variant(valueManaged); + value = Marshaling.ConvertManagedObjectToVariant(valueManaged); return true; } @@ -306,7 +303,7 @@ namespace Godot return false; } - internal unsafe void InternalRaiseEventSignal(godot_string_name* eventSignalName, godot_variant** args, + internal unsafe void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args, int argc) { // Performance is not critical here as this will be replaced with source generators. @@ -360,9 +357,9 @@ namespace Godot var managedArgs = new object[argc]; - for (uint i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) { - managedArgs[i] = Marshaling.variant_to_mono_object_of_type( + managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType( args[i], parameterInfos[i].ParameterType); } @@ -379,7 +376,8 @@ namespace Godot IntPtr methodBind; fixed (char* methodChars = method) { - methodBind = NativeFuncs.godotsharp_method_bind_get_method(ref type.NativeValue, methodChars); + var typeSelf = (godot_string_name)type.NativeValue; + methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodChars); } if (methodBind == IntPtr.Zero) @@ -391,7 +389,8 @@ namespace Godot internal static unsafe delegate* unmanaged ClassDB_get_constructor(StringName type) { // for some reason the '??' operator doesn't support 'delegate*' - var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue); + var typeSelf = (godot_string_name)type.NativeValue; + var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(typeSelf); if (nativeConstructor == null) throw new NativeConstructorNotFoundException(type); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index e38dca414f7..369b95c7cbd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -73,7 +73,7 @@ namespace Godot case 3: return w; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -93,7 +93,7 @@ namespace Godot w = value; break; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs index 62dec815827..c8bf686afa0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs @@ -8,19 +8,21 @@ namespace Godot { private bool _completed; private object[] _result; - private Action _action; + private Action _continuation; public SignalAwaiter(Object source, StringName signal, Object target) { - NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), ref signal.NativeValue, + using godot_string_name signalSrc = NativeFuncs.godotsharp_string_name_new_copy( + (godot_string_name)(signal?.NativeValue ?? default)); + NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), in signalSrc, Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this))); } public bool IsCompleted => _completed; - public void OnCompleted(Action action) + public void OnCompleted(Action continuation) { - this._action = action; + _continuation = continuation; } public object[] GetResult() => _result; @@ -48,11 +50,11 @@ namespace Godot object[] signalArgs = new object[argCount]; for (int i = 0; i < argCount; i++) - signalArgs[i] = Marshaling.variant_to_mono_object(args[i]); + signalArgs[i] = Marshaling.ConvertVariantToManagedObject(*args[i]); awaiter._result = signalArgs; - awaiter._action?.Invoke(); + awaiter._continuation?.Invoke(); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs index da013005863..3f50df0a0dc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs @@ -3,7 +3,7 @@ namespace Godot /// /// Represents a signal defined in an object. /// - public struct SignalInfo + public readonly struct SignalInfo { private readonly Object _owner; private readonly StringName _signalName; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index dfdef81f9e0..ce89e134b81 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Runtime.CompilerServices; using System.Security; using System.Text; using System.Text.RegularExpressions; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// @@ -1077,12 +1078,12 @@ namespace Godot /// /// The string to hash. /// The MD5 hash of the string. - public static unsafe byte[] MD5Buffer(this string instance) + public static byte[] MD5Buffer(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_packed_byte_array md5Buffer = default; - NativeFuncs.godotsharp_string_md5_buffer(&instanceStr, &md5Buffer); - return Marshaling.PackedByteArray_to_mono_array(&md5Buffer); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer); + using (md5Buffer) + return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer); } /// @@ -1091,12 +1092,12 @@ namespace Godot /// /// The string to hash. /// The MD5 hash of the string. - public static unsafe string MD5Text(this string instance) + public static string MD5Text(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string md5Text = default; - NativeFuncs.godotsharp_string_md5_text(&instanceStr, &md5Text); - return Marshaling.mono_string_from_godot(md5Text); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text); + using (md5Text) + return Marshaling.ConvertStringToManaged(md5Text); } /// @@ -1251,11 +1252,11 @@ namespace Godot /// The substring to search in the string. /// The position at which to start searching. /// The position at which the substring was found, or -1 if not found. - public static unsafe int RFind(this string instance, string what, int from = -1) + public static int RFind(this string instance, string what, int from = -1) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string whatStr = Marshaling.mono_string_to_godot(instance); - return NativeFuncs.godotsharp_string_rfind(&instanceStr, &whatStr, from); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + using godot_string whatStr = Marshaling.ConvertStringToNative(instance); + return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from); } /// @@ -1267,11 +1268,11 @@ namespace Godot /// The substring to search in the string. /// The position at which to start searching. /// The position at which the substring was found, or -1 if not found. - public static unsafe int RFindN(this string instance, string what, int from = -1) + public static int RFindN(this string instance, string what, int from = -1) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string whatStr = Marshaling.mono_string_to_godot(instance); - return NativeFuncs.godotsharp_string_rfindn(&instanceStr, &whatStr, from); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + using godot_string whatStr = Marshaling.ConvertStringToNative(instance); + return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from); } /// @@ -1326,12 +1327,12 @@ namespace Godot /// /// The string to hash. /// The SHA-256 hash of the string. - public static unsafe byte[] SHA256Buffer(this string instance) + public static byte[] SHA256Buffer(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_packed_byte_array sha256Buffer = default; - NativeFuncs.godotsharp_string_sha256_buffer(&instanceStr, &sha256Buffer); - return Marshaling.PackedByteArray_to_mono_array(&sha256Buffer); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer); + using (sha256Buffer) + return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer); } /// @@ -1340,12 +1341,12 @@ namespace Godot /// /// The string to hash. /// The SHA-256 hash of the string. - public static unsafe string SHA256Text(this string instance) + public static string SHA256Text(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string sha256Text = default; - NativeFuncs.godotsharp_string_sha256_text(&instanceStr, &sha256Text); - return Marshaling.mono_string_from_godot(sha256Text); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text); + using (sha256Text) + return Marshaling.ConvertStringToManaged(sha256Text); } /// @@ -1396,12 +1397,12 @@ namespace Godot /// /// Returns a simplified canonical path. /// - public static unsafe string SimplifyPath(this string instance) + public static string SimplifyPath(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string simplifiedPath = default; - NativeFuncs.godotsharp_string_simplify_path(&instanceStr, &simplifiedPath); - return Marshaling.mono_string_from_godot(simplifiedPath); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_simplify_path(instanceStr, out godot_string simplifiedPath); + using (simplifiedPath) + return Marshaling.ConvertStringToManaged(simplifiedPath); } /// @@ -1602,7 +1603,7 @@ namespace Godot /// /// The string to escape. /// The escaped string. - public static string XMLEscape(this string instance) + public static string? XMLEscape(this string instance) { return SecurityElement.Escape(instance); } @@ -1614,9 +1615,9 @@ namespace Godot /// /// The string to unescape. /// The unescaped string. - public static string XMLUnescape(this string instance) + public static string? XMLUnescape(this string instance) { - return SecurityElement.FromString(instance).Text; + return SecurityElement.FromString(instance)?.Text; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index 84b0ab623ce..e8bda9b219e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -13,7 +12,7 @@ namespace Godot /// public sealed class StringName : IDisposable { - public godot_string_name NativeValue; + internal godot_string_name.movable NativeValue; ~StringName() { @@ -32,12 +31,12 @@ namespace Godot public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } private StringName(godot_string_name nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_string_name.movable)nativeValueToOwn; } // Explicit name to make it very clear @@ -58,7 +57,7 @@ namespace Godot public StringName(string name) { if (!string.IsNullOrEmpty(name)) - NativeValue = NativeFuncs.godotsharp_string_name_new_from_string(name); + NativeValue = (godot_string_name.movable)NativeFuncs.godotsharp_string_name_new_from_string(name); } /// @@ -71,28 +70,27 @@ namespace Godot /// Converts a to a string. /// /// The to convert. - public static implicit operator string(StringName from) => from.ToString(); + public static implicit operator string(StringName from) => from?.ToString(); /// /// Converts this to a string. /// /// A string representation of this . - public override unsafe string ToString() + public override string ToString() { if (IsEmpty) return string.Empty; - godot_string dest; - godot_string_name src = NativeValue; - NativeFuncs.godotsharp_string_name_as_string(&dest, &src); + var src = (godot_string_name)NativeValue; + NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, src); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } /// /// Check whether this is empty. /// /// If the is empty. - public bool IsEmpty => godot_string_name.IsEmpty(in NativeValue); + public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 68d097eb4e3..1e3a13ba8ea 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -93,7 +93,7 @@ namespace Godot case 2: return origin; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -110,7 +110,7 @@ namespace Godot origin = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 9eaf4f32525..27de87d7d41 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -52,7 +52,7 @@ namespace Godot case 3: return origin; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -72,7 +72,7 @@ namespace Godot origin = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } @@ -168,7 +168,7 @@ namespace Godot /// The object to look at. /// The relative up direction. /// The resulting transform. - public Transform3D LookingAt(Vector3 target, Vector3 up) + public readonly Transform3D LookingAt(Vector3 target, Vector3 up) { Transform3D t = this; t.SetLookAt(origin, target, up); @@ -194,7 +194,7 @@ namespace Godot /// The axis to rotate around. Must be normalized. /// The angle to rotate, in radians. /// The rotated transformation matrix. - public Transform3D Rotated(Vector3 axis, real_t angle) + public readonly Transform3D Rotated(Vector3 axis, real_t angle) { return new Transform3D(new Basis(axis, angle), new Vector3()) * this; } @@ -443,7 +443,7 @@ namespace Godot /// /// The object to compare with. /// Whether or not the transform and the object are exactly equal. - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { if (obj is Transform3D) { @@ -460,7 +460,7 @@ namespace Godot /// /// The other transform to compare. /// Whether or not the matrices are exactly equal. - public bool Equals(Transform3D other) + public readonly bool Equals(Transform3D other) { return basis.Equals(other.basis) && origin.Equals(other.origin); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 67f70390dd0..6223f3ae533 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -62,7 +62,7 @@ namespace Godot case 1: return y; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -76,7 +76,7 @@ namespace Godot y = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index b61954a84ca..e4c3f869b15 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -62,7 +62,7 @@ namespace Godot case 1: return y; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -76,7 +76,7 @@ namespace Godot y = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 67a98efc2d6..7e98969d348 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -74,7 +74,7 @@ namespace Godot case 2: return z; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -91,7 +91,7 @@ namespace Godot z = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index 0d4894f2067..88b58e20cd0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -74,7 +74,7 @@ namespace Godot case 2: return z; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -91,7 +91,7 @@ namespace Godot z = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml b/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml new file mode 100644 index 00000000000..d7abb3c982d --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets b/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets new file mode 100644 index 00000000000..f572f8a75c9 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(GodotInteropStructs.Identity) + + + + + diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 763ded88096..a06b448136e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -10,6 +10,8 @@ true 9 + Recommended + CS1591 @@ -20,6 +22,12 @@ + + + + + + @@ -62,6 +70,7 @@ + diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index 14e638d1637..c5db869a05f 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -445,6 +445,21 @@ GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callab } } +GD_PINVOKE_EXPORT godot_variant godotsharp_callable_call(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count, Callable::CallError *p_call_error) { + godot_variant ret; + memnew_placement(&ret, Variant); + + Variant *ret_val = (Variant *)&ret; + + p_callable->callp(p_args, p_arg_count, *ret_val, *p_call_error); + + return ret; +} + +GD_PINVOKE_EXPORT void godotsharp_callable_call_deferred(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count) { + p_callable->call_deferredp(p_args, p_arg_count); +} + // GDNative functions // gdnative.h @@ -1241,7 +1256,7 @@ GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string * #endif // We need this to prevent the functions from being stripped. -void *godotsharp_pinvoke_funcs[176] = { +void *godotsharp_pinvoke_funcs[178] = { (void *)godotsharp_method_bind_get_method, (void *)godotsharp_get_class_constructor, (void *)godotsharp_engine_get_singleton, @@ -1274,6 +1289,8 @@ void *godotsharp_pinvoke_funcs[176] = { (void *)godotsharp_packed_string_array_add, (void *)godotsharp_callable_new_with_delegate, (void *)godotsharp_callable_get_data_for_marshalling, + (void *)godotsharp_callable_call, + (void *)godotsharp_callable_call_deferred, (void *)godotsharp_method_bind_ptrcall, (void *)godotsharp_method_bind_call, (void *)godotsharp_variant_new_string_name,