summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/mono/SCsub31
-rw-r--r--modules/mono/build_scripts/api_solution_build.py80
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py306
-rw-r--r--modules/mono/build_scripts/gen_cs_glue_version.py20
-rw-r--r--modules/mono/build_scripts/godot_net_sdk_build.py55
-rw-r--r--modules/mono/build_scripts/godot_tools_build.py38
-rw-r--r--modules/mono/build_scripts/solution_builder.py145
-rw-r--r--modules/mono/config.py2
-rw-r--r--modules/mono/csharp_script.cpp49
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs2
-rw-r--r--modules/mono/editor/bindings_generator.cpp1429
-rw-r--r--modules/mono/editor/bindings_generator.h182
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs279
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs59
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs314
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs23
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs141
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs438
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs32
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs1370
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs346
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs335
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs119
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs92
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs135
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs85
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs23
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs67
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings4
-rw-r--r--modules/mono/glue/base_object_glue.cpp18
-rw-r--r--modules/mono/glue/collections_glue.cpp154
-rw-r--r--modules/mono/glue/gd_glue.cpp22
-rw-r--r--modules/mono/glue/glue_header.h91
-rw-r--r--modules/mono/glue/node_path_glue.cpp (renamed from modules/mono/glue/nodepath_glue.cpp)33
-rw-r--r--modules/mono/glue/placeholder_glue.cpp (renamed from modules/mono/glue/rid_glue.cpp)44
-rw-r--r--modules/mono/glue/runtime_interop.cpp786
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp15
-rw-r--r--modules/mono/glue/string_glue.cpp4
-rw-r--r--modules/mono/glue/string_name_glue.cpp62
-rw-r--r--modules/mono/godotsharp_defs.h4
-rw-r--r--modules/mono/interop_types.h208
-rw-r--r--modules/mono/managed_callable.cpp60
-rw-r--r--modules/mono/managed_callable.h11
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp118
-rw-r--r--modules/mono/mono_gd/gd_mono.h14
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp170
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h84
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp11
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp419
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp1736
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h511
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp13
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h1
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp19
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp206
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h29
-rw-r--r--modules/mono/signal_awaiter_utils.cpp4
-rw-r--r--modules/mono/signal_awaiter_utils.h13
-rw-r--r--modules/mono/utils/string_utils.cpp29
-rw-r--r--modules/mono/utils/string_utils.h3
71 files changed, 5676 insertions, 5569 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index d10ebc7b47..5757917f56 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -7,21 +7,6 @@ Import("env_modules")
env_mono = env_modules.Clone()
-if env_mono["tools"]:
- # NOTE: It is safe to generate this file here, since this is still executed serially
- import build_scripts.gen_cs_glue_version as gen_cs_glue_version
-
- gen_cs_glue_version.generate_header("glue/GodotSharp", "glue/cs_glue_version.gen.h")
-
-# Glue sources
-if env_mono["mono_glue"]:
- env_mono.Append(CPPDEFINES=["MONO_GLUE_ENABLED"])
-
- import os.path
-
- if not os.path.isfile("glue/mono_glue.gen.cpp"):
- raise RuntimeError("Mono glue sources not found. Did you forget to run '--generate-mono-glue'?")
-
if env_mono["tools"] or env_mono["target"] != "release":
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
@@ -29,22 +14,6 @@ if env_mono["tools"] or env_mono["target"] != "release":
mono_configure.configure(env, env_mono)
-if env_mono["tools"] and env_mono["mono_glue"] and env_mono["build_cil"]:
- # Build Godot API solution
- import build_scripts.api_solution_build as api_solution_build
-
- api_sln_cmd = api_solution_build.build(env_mono)
-
- # Build GodotTools
- import build_scripts.godot_tools_build as godot_tools_build
-
- godot_tools_build.build(env_mono, api_sln_cmd)
-
- # Build Godot.NET.Sdk
- import build_scripts.godot_net_sdk_build as godot_net_sdk_build
-
- godot_net_sdk_build.build(env_mono)
-
# Add sources
env_mono.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/mono/build_scripts/api_solution_build.py b/modules/mono/build_scripts/api_solution_build.py
deleted file mode 100644
index 9abac22df6..0000000000
--- a/modules/mono/build_scripts/api_solution_build.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Build the Godot API solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_api_solution(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
-
- build_config = env["solution_build_config"]
-
- extra_msbuild_args = ["/p:NoWarn=1591"] # Ignore missing documentation warnings
-
- from .solution_builder import build_solution
-
- build_solution(env, solution_path, build_config, extra_msbuild_args=extra_msbuild_args)
-
- # Copy targets
-
- core_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharp", "bin", build_config))
- editor_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharpEditor", "bin", build_config))
-
- dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
-
- if not os.path.isdir(dst_dir):
- assert not os.path.isfile(dst_dir)
- os.makedirs(dst_dir)
-
- def copy_target(target_path):
- from shutil import copy
-
- filename = os.path.basename(target_path)
-
- src_path = os.path.join(core_src_dir, filename)
- if not os.path.isfile(src_path):
- src_path = os.path.join(editor_src_dir, filename)
-
- copy(src_path, target_path)
-
- for scons_target in target:
- copy_target(str(scons_target))
-
-
-def build(env_mono):
- assert env_mono["tools"]
-
- target_filenames = [
- "GodotSharp.dll",
- "GodotSharp.pdb",
- "GodotSharp.xml",
- "GodotSharpEditor.dll",
- "GodotSharpEditor.pdb",
- "GodotSharpEditor.xml",
- ]
-
- depend_cmd = []
-
- for build_config in ["Debug", "Release"]:
- output_dir = Dir("#bin").abspath
- editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config)
-
- targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(
- targets, depend_cmd, build_api_solution, module_dir=os.getcwd(), solution_build_config=build_config
- )
- env_mono.AlwaysBuild(cmd)
-
- # Make the Release build of the API solution depend on the Debug build.
- # We do this in order to prevent SCons from building them in parallel,
- # which can freak out MSBuild. In many cases, one of the builds would
- # hang indefinitely requiring a key to be pressed for it to continue.
- depend_cmd = cmd
-
- return depend_cmd
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
new file mode 100755
index 0000000000..dd96f40f6b
--- /dev/null
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -0,0 +1,306 @@
+#!/usr/bin/python3
+
+import os
+import os.path
+import shlex
+import subprocess
+from dataclasses import dataclass
+
+
+def find_dotnet_cli():
+ if os.name == "nt":
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "dotnet")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
+ else:
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "dotnet")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+
+def find_msbuild_standalone_windows():
+ msbuild_tools_path = find_msbuild_tools_path_reg()
+
+ if msbuild_tools_path:
+ return os.path.join(msbuild_tools_path, "MSBuild.exe")
+
+ return None
+
+
+def find_msbuild_mono_windows(mono_prefix):
+ assert mono_prefix is not None
+
+ mono_bin_dir = os.path.join(mono_prefix, "bin")
+ msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat")
+
+ if os.path.isfile(msbuild_mono):
+ return msbuild_mono
+
+ return None
+
+
+def find_msbuild_mono_unix():
+ import sys
+
+ hint_dirs = []
+ if sys.platform == "darwin":
+ hint_dirs[:0] = [
+ "/Library/Frameworks/Mono.framework/Versions/Current/bin",
+ "/usr/local/var/homebrew/linked/mono/bin",
+ ]
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, "msbuild")
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + ".exe"):
+ return hint_path + ".exe"
+
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "msbuild")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
+
+ return None
+
+
+def find_msbuild_tools_path_reg():
+ import subprocess
+
+ program_files = os.getenv("PROGRAMFILES(X86)")
+ if not program_files:
+ program_files = os.getenv("PROGRAMFILES")
+ vswhere = os.path.join(program_files, "Microsoft Visual Studio", "Installer", "vswhere.exe")
+
+ vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"]
+
+ try:
+ lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
+
+ for line in lines:
+ parts = line.decode("utf-8").split(":", 1)
+
+ if len(parts) < 2 or parts[0] != "installationPath":
+ continue
+
+ val = parts[1].strip()
+
+ if not val:
+ raise ValueError("Value of `installationPath` entry is empty")
+
+ # Since VS2019, the directory is simply named "Current"
+ msbuild_dir = os.path.join(val, "MSBuild", "Current", "Bin")
+ if os.path.isdir(msbuild_dir):
+ return msbuild_dir
+
+ # Directory name "15.0" is used in VS 2017
+ return os.path.join(val, "MSBuild", "15.0", "Bin")
+
+ raise ValueError("Cannot find `installationPath` entry")
+ except ValueError as e:
+ print("Error reading output from vswhere: " + str(e))
+ except OSError:
+ pass # Fine, vswhere not found
+ except (subprocess.CalledProcessError, OSError):
+ pass
+
+
+@dataclass
+class ToolsLocation:
+ dotnet_cli: str = ""
+ msbuild_standalone: str = ""
+ msbuild_mono: str = ""
+ mono_bin_dir: str = ""
+
+
+def find_any_msbuild_tool(mono_prefix):
+ # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild
+
+ # Find dotnet CLI
+ dotnet_cli = find_dotnet_cli()
+ if dotnet_cli:
+ return ToolsLocation(dotnet_cli=dotnet_cli)
+
+ # Find standalone MSBuild
+ if os.name == "nt":
+ msbuild_standalone = find_msbuild_standalone_windows()
+ if msbuild_standalone:
+ return ToolsLocation(msbuild_standalone=msbuild_standalone)
+
+ if mono_prefix:
+ # Find Mono's MSBuild
+ if os.name == "nt":
+ msbuild_mono = find_msbuild_mono_windows(mono_prefix)
+ if msbuild_mono:
+ return ToolsLocation(msbuild_mono=msbuild_mono)
+ else:
+ msbuild_mono = find_msbuild_mono_unix()
+ if msbuild_mono:
+ return ToolsLocation(msbuild_mono=msbuild_mono)
+
+ return None
+
+
+def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None):
+ if msbuild_args is None:
+ msbuild_args = []
+
+ using_msbuild_mono = False
+
+ # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild
+ if tools.dotnet_cli:
+ args = [tools.dotnet_cli, "msbuild"]
+ elif tools.msbuild_standalone:
+ args = [tools.msbuild_standalone]
+ elif tools.msbuild_mono:
+ args = [tools.msbuild_mono]
+ using_msbuild_mono = True
+ else:
+ raise RuntimeError("Path to MSBuild or dotnet CLI not provided.")
+
+ args += [sln]
+
+ if len(msbuild_args) > 0:
+ args += msbuild_args
+
+ print("Running MSBuild: ", " ".join(shlex.quote(arg) for arg in args), flush=True)
+
+ msbuild_env = os.environ.copy()
+
+ # Needed when running from Developer Command Prompt for VS
+ if "PLATFORM" in msbuild_env:
+ del msbuild_env["PLATFORM"]
+
+ if using_msbuild_mono:
+ # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
+ # building with Mono's MSBuild. They must point to the batch files
+ # in Mono's bin directory to make sure they are executed with Mono.
+ msbuild_env.update(
+ {
+ "CscToolExe": os.path.join(tools.mono_bin_dir, "csc.bat"),
+ "VbcToolExe": os.path.join(tools.mono_bin_dir, "vbc.bat"),
+ "FscToolExe": os.path.join(tools.mono_bin_dir, "fsharpc.bat"),
+ }
+ )
+
+ return subprocess.call(args, env=msbuild_env)
+
+
+def build_godot_api(msbuild_tool, module_dir, output_dir):
+ target_filenames = [
+ "GodotSharp.dll",
+ "GodotSharp.pdb",
+ "GodotSharp.xml",
+ "GodotSharpEditor.dll",
+ "GodotSharpEditor.pdb",
+ "GodotSharpEditor.xml",
+ ]
+
+ for build_config in ["Debug", "Release"]:
+ editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config)
+
+ targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames]
+
+ sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
+ exit_code = run_msbuild(
+ msbuild_tool,
+ sln=sln,
+ msbuild_args=["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"],
+ )
+ if exit_code != 0:
+ return exit_code
+
+ # Copy targets
+
+ core_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharp", "bin", build_config))
+ editor_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharpEditor", "bin", build_config))
+
+ if not os.path.isdir(editor_api_dir):
+ assert not os.path.isfile(editor_api_dir)
+ os.makedirs(editor_api_dir)
+
+ def copy_target(target_path):
+ from shutil import copy
+
+ filename = os.path.basename(target_path)
+
+ src_path = os.path.join(core_src_dir, filename)
+ if not os.path.isfile(src_path):
+ src_path = os.path.join(editor_src_dir, filename)
+
+ print(f"Copying assembly to {target_path}...")
+ copy(src_path, target_path)
+
+ for scons_target in targets:
+ copy_target(scons_target)
+
+ return 0
+
+
+def build_all(msbuild_tool, module_dir, output_dir, dev_debug, godot_platform):
+ # Godot API
+ exit_code = build_godot_api(msbuild_tool, module_dir, output_dir)
+ if exit_code != 0:
+ return exit_code
+
+ # GodotTools
+ sln = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln")
+ args = ["/restore", "/t:Build", "/p:Configuration=" + ("Debug" if dev_debug else "Release")] + (
+ ["/p:GodotPlatform=" + godot_platform] if godot_platform else []
+ )
+ exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
+ if exit_code != 0:
+ return exit_code
+
+ # Godot.NET.Sdk
+ sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
+ exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=["/restore", "/t:Build", "/p:Configuration=Release"])
+ if exit_code != 0:
+ return exit_code
+
+ return 0
+
+
+def main():
+ import argparse
+ import sys
+
+ parser = argparse.ArgumentParser(description="Builds all Godot .NET solutions")
+ parser.add_argument("--godot-output-dir", type=str, required=True)
+ parser.add_argument(
+ "--dev-debug",
+ action="store_true",
+ default=False,
+ help="Build GodotTools and Godot.NET.Sdk with 'Configuration=Debug'",
+ )
+ parser.add_argument("--godot-platform", type=str, default="")
+ parser.add_argument("--mono-prefix", type=str, default="")
+
+ args = parser.parse_args()
+
+ this_script_dir = os.path.dirname(os.path.realpath(__file__))
+ module_dir = os.path.abspath(os.path.join(this_script_dir, os.pardir))
+
+ output_dir = os.path.abspath(args.godot_output_dir)
+
+ msbuild_tool = find_any_msbuild_tool(args.mono_prefix)
+
+ if msbuild_tool is None:
+ print("Unable to find MSBuild")
+ sys.exit(1)
+
+ exit_code = build_all(msbuild_tool, module_dir, output_dir, args.godot_platform, args.dev_debug)
+ sys.exit(exit_code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/modules/mono/build_scripts/gen_cs_glue_version.py b/modules/mono/build_scripts/gen_cs_glue_version.py
deleted file mode 100644
index 98bbb4d9be..0000000000
--- a/modules/mono/build_scripts/gen_cs_glue_version.py
+++ /dev/null
@@ -1,20 +0,0 @@
-def generate_header(solution_dir, version_header_dst):
- import os
-
- latest_mtime = 0
- for root, dirs, files in os.walk(solution_dir, topdown=True):
- dirs[:] = [d for d in dirs if d not in ["Generated"]] # Ignored generated files
- files = [f for f in files if f.endswith(".cs")]
- for file in files:
- filepath = os.path.join(root, file)
- mtime = os.path.getmtime(filepath)
- latest_mtime = mtime if mtime > latest_mtime else latest_mtime
-
- glue_version = int(latest_mtime) # The latest modified time will do for now
-
- with open(version_header_dst, "w") as version_header:
- version_header.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- version_header.write("#ifndef CS_GLUE_VERSION_H\n")
- version_header.write("#define CS_GLUE_VERSION_H\n\n")
- version_header.write("#define CS_GLUE_VERSION UINT32_C(" + str(glue_version) + ")\n")
- version_header.write("\n#endif // CS_GLUE_VERSION_H\n")
diff --git a/modules/mono/build_scripts/godot_net_sdk_build.py b/modules/mono/build_scripts/godot_net_sdk_build.py
deleted file mode 100644
index 8c5a60d2db..0000000000
--- a/modules/mono/build_scripts/godot_net_sdk_build.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Build Godot.NET.Sdk solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_godot_net_sdk(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
- build_config = "Release"
-
- from .solution_builder import build_solution
-
- extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
-
- build_solution(env, solution_path, build_config, extra_msbuild_args)
- # No need to copy targets. The Godot.NET.Sdk csproj takes care of copying them.
-
-
-def get_nupkgs_versions(props_file):
- import xml.etree.ElementTree as ET
-
- tree = ET.parse(props_file)
- root = tree.getroot()
-
- return {
- "Godot.NET.Sdk": root.find("./PropertyGroup/PackageVersion_Godot_NET_Sdk").text.strip(),
- "Godot.SourceGenerators": root.find("./PropertyGroup/PackageVersion_Godot_SourceGenerators").text.strip(),
- }
-
-
-def build(env_mono):
- assert env_mono["tools"]
-
- output_dir = Dir("#bin").abspath
- editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
- nupkgs_dir = os.path.join(editor_tools_dir, "nupkgs")
-
- module_dir = os.getcwd()
-
- nupkgs_versions = get_nupkgs_versions(os.path.join(module_dir, "SdkPackageVersions.props"))
-
- target_filenames = [
- "Godot.NET.Sdk.%s.nupkg" % nupkgs_versions["Godot.NET.Sdk"],
- "Godot.SourceGenerators.%s.nupkg" % nupkgs_versions["Godot.SourceGenerators"],
- ]
-
- targets = [os.path.join(nupkgs_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(targets, [], build_godot_net_sdk, module_dir=module_dir)
- env_mono.AlwaysBuild(cmd)
diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py
deleted file mode 100644
index 3bbbf29d3b..0000000000
--- a/modules/mono/build_scripts/godot_tools_build.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Build GodotTools solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_godot_tools(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln")
- build_config = "Debug" if env["target"] == "debug" else "Release"
-
- from .solution_builder import build_solution
-
- extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
-
- build_solution(env, solution_path, build_config, extra_msbuild_args)
- # No need to copy targets. The GodotTools csproj takes care of copying them.
-
-
-def build(env_mono, api_sln_cmd):
- assert env_mono["tools"]
-
- output_dir = Dir("#bin").abspath
- editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
-
- target_filenames = ["GodotTools.dll"]
-
- if env_mono["target"] == "debug":
- target_filenames += ["GodotTools.pdb"]
-
- targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(targets, api_sln_cmd, build_godot_tools, module_dir=os.getcwd())
- env_mono.AlwaysBuild(cmd)
diff --git a/modules/mono/build_scripts/solution_builder.py b/modules/mono/build_scripts/solution_builder.py
deleted file mode 100644
index 6a621c3c8b..0000000000
--- a/modules/mono/build_scripts/solution_builder.py
+++ /dev/null
@@ -1,145 +0,0 @@
-import os
-
-
-verbose = False
-
-
-def find_dotnet_cli():
- import os.path
-
- if os.name == "nt":
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "dotnet")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
- return hint_path + ".exe"
- else:
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "dotnet")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
-
-def find_msbuild_unix():
- import os.path
- import sys
-
- hint_dirs = []
- if sys.platform == "darwin":
- hint_dirs[:0] = [
- "/Library/Frameworks/Mono.framework/Versions/Current/bin",
- "/usr/local/var/homebrew/linked/mono/bin",
- ]
-
- for hint_dir in hint_dirs:
- hint_path = os.path.join(hint_dir, "msbuild")
- if os.path.isfile(hint_path):
- return hint_path
- elif os.path.isfile(hint_path + ".exe"):
- return hint_path + ".exe"
-
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "msbuild")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
- return hint_path + ".exe"
-
- return None
-
-
-def find_msbuild_windows(env):
- from .mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg
-
- mono_root = env["mono_prefix"] or find_mono_root_dir(env["bits"])
-
- if not mono_root:
- raise RuntimeError("Cannot find mono root directory")
-
- mono_bin_dir = os.path.join(mono_root, "bin")
- msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat")
-
- msbuild_tools_path = find_msbuild_tools_path_reg()
-
- if msbuild_tools_path:
- return (os.path.join(msbuild_tools_path, "MSBuild.exe"), {})
-
- if os.path.isfile(msbuild_mono):
- # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
- # building with Mono's MSBuild. They must point to the batch files
- # in Mono's bin directory to make sure they are executed with Mono.
- mono_msbuild_env = {
- "CscToolExe": os.path.join(mono_bin_dir, "csc.bat"),
- "VbcToolExe": os.path.join(mono_bin_dir, "vbc.bat"),
- "FscToolExe": os.path.join(mono_bin_dir, "fsharpc.bat"),
- }
- return (msbuild_mono, mono_msbuild_env)
-
- return None
-
-
-def run_command(command, args, env_override=None, name=None):
- def cmd_args_to_str(cmd_args):
- return " ".join([arg if not " " in arg else '"%s"' % arg for arg in cmd_args])
-
- args = [command] + args
-
- if name is None:
- name = os.path.basename(command)
-
- if verbose:
- print("Running '%s': %s" % (name, cmd_args_to_str(args)))
-
- import subprocess
-
- try:
- if env_override is None:
- subprocess.check_call(args)
- else:
- subprocess.check_call(args, env=env_override)
- except subprocess.CalledProcessError as e:
- raise RuntimeError("'%s' exited with error code: %s" % (name, e.returncode))
-
-
-def build_solution(env, solution_path, build_config, extra_msbuild_args=[]):
- global verbose
- verbose = env["verbose"]
-
- msbuild_env = os.environ.copy()
-
- # Needed when running from Developer Command Prompt for VS
- if "PLATFORM" in msbuild_env:
- del msbuild_env["PLATFORM"]
-
- msbuild_args = []
-
- dotnet_cli = find_dotnet_cli()
-
- if dotnet_cli:
- msbuild_path = dotnet_cli
- msbuild_args += ["msbuild"] # `dotnet msbuild` command
- else:
- # Find MSBuild
- if os.name == "nt":
- msbuild_info = find_msbuild_windows(env)
- if msbuild_info is None:
- raise RuntimeError("Cannot find MSBuild executable")
- msbuild_path = msbuild_info[0]
- msbuild_env.update(msbuild_info[1])
- else:
- msbuild_path = find_msbuild_unix()
- if msbuild_path is None:
- raise RuntimeError("Cannot find MSBuild executable")
-
- print("MSBuild path: " + msbuild_path)
-
- # Build solution
-
- msbuild_args += [solution_path, "/restore", "/t:Build", "/p:Configuration=" + build_config]
- msbuild_args += extra_msbuild_args
-
- run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name="msbuild")
diff --git a/modules/mono/config.py b/modules/mono/config.py
index d895d2d92d..010f1ef1e5 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -25,11 +25,11 @@ def get_opts(platform):
PathVariable.PathAccept,
),
BoolVariable("mono_static", "Statically link Mono", default_mono_static),
- BoolVariable("mono_glue", "Build with the Mono glue sources", True),
BoolVariable("build_cil", "Build C# solutions", True),
BoolVariable(
"copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True
),
+ # TODO: It would be great if this could be detected automatically instead
BoolVariable(
"mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib
),
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index b95b63cf1f..2e6a6ef7e0 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -57,6 +57,7 @@
#endif
#include "godotsharp_dirs.h"
+#include "managed_callable.h"
#include "mono_gd/gd_mono_cache.h"
#include "mono_gd/gd_mono_class.h"
#include "mono_gd/gd_mono_marshal.h"
@@ -108,6 +109,9 @@ Error CSharpLanguage::execute_file(const String &p_path) {
return OK;
}
+extern void *godotsharp_pinvoke_funcs[101];
+[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
+
void CSharpLanguage::init() {
#ifdef DEBUG_METHODS_ENABLED
if (OS::get_singleton()->get_cmdline_args().find("--class-db-json")) {
@@ -118,20 +122,18 @@ void CSharpLanguage::init() {
}
#endif
- gdmono = memnew(GDMono);
- gdmono->initialize();
+ // Hopefully this will be enough for all compilers. Otherwise we could use the printf on fake getenv trick.
+ do_not_strip_godotsharp_pinvoke_funcs = (volatile void **)godotsharp_pinvoke_funcs;
#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
- // Generate bindings here, before loading assemblies. 'initialize_load_assemblies' aborts
- // the applications if the api assemblies or the main tools assembly is missing, but this
- // is not a problem for BindingsGenerator as it only needs the tools project editor assembly.
+ // Generate the bindings here, before loading assemblies. The Godot assemblies
+ // may be missing if the glue wasn't generated yet in order to build them.
List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
BindingsGenerator::handle_cmdline_args(cmdline_args);
#endif
-#ifndef MONO_GLUE_ENABLED
- print_line("Run this binary with '--generate-mono-glue path/to/modules/mono/glue'");
-#endif
+ gdmono = memnew(GDMono);
+ gdmono->initialize();
if (gdmono->is_runtime_initialized()) {
gdmono->initialize_load_assemblies();
@@ -596,7 +598,9 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
return Vector<StackInfo>();
}
_recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
+ SCOPE_EXIT {
+ _recursion_flag_ = false;
+ };
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -628,7 +632,9 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
return Vector<StackInfo>();
}
_recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
+ SCOPE_EXIT {
+ _recursion_flag_ = false;
+ };
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -824,13 +830,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
ManagedCallable *managed_callable = elem->self();
- MonoDelegate *delegate = (MonoDelegate *)managed_callable->delegate_handle.get_target();
-
Array serialized_data;
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate, managed_serialized_data, &exc);
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegateWithGCHandle)
+ .invoke(managed_callable->delegate_handle,
+ managed_serialized_data, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -1149,10 +1155,11 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
const Array &serialized_data = elem.value;
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
- MonoDelegate *delegate = nullptr;
+ void *delegate = nullptr;
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegateWithGCHandle)
+ .invoke(managed_serialized_data, &delegate, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -1161,7 +1168,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
if (success) {
ERR_CONTINUE(delegate == nullptr);
- managed_callable->set_delegate(delegate);
+ managed_callable->delegate_handle = delegate;
} else if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to deserialize delegate\n");
}
@@ -1289,7 +1296,7 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
}
}
-void CSharpLanguage::_on_scripts_domain_unloaded() {
+void CSharpLanguage::_on_scripts_domain_about_to_unload() {
for (KeyValue<Object *, CSharpScriptBinding> &E : script_bindings) {
CSharpScriptBinding &script_binding = E.value;
script_binding.gchandle.release();
@@ -1302,8 +1309,7 @@ void CSharpLanguage::_on_scripts_domain_unloaded() {
for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
ManagedCallable *managed_callable = elem->self();
- managed_callable->delegate_handle.release();
- managed_callable->delegate_invoke = nullptr;
+ managed_callable->release_delegate_handle();
}
}
#endif
@@ -1455,7 +1461,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
if (GDMono::get_singleton() == nullptr) {
#ifdef DEBUG_ENABLED
- CRASH_COND(!csharp_lang->script_bindings.is_empty());
+ CRASH_COND(csharp_lang && !csharp_lang->script_bindings.is_empty());
#endif
// Mono runtime finalized, all the gchandle bindings were already released
return;
@@ -1784,7 +1790,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate_field_value, managed_serialized_data, &exc);
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate)
+ .invoke(delegate_field_value, managed_serialized_data, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 823de91bf6..cf4f971b88 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -398,7 +398,7 @@ class CSharpLanguage : public ScriptLanguage {
String _debug_error;
friend class GDMono;
- void _on_scripts_domain_unloaded();
+ void _on_scripts_domain_about_to_unload();
#ifdef TOOLS_ENABLED
EditorPlugin *godotsharp_editor = nullptr;
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
index dd05f28af0..43b1cf0f64 100644
--- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -38,7 +38,7 @@ namespace GodotTools
_watchTimer = new Timer
{
OneShot = false,
- WaitTime = (float)EditorDef("mono/assembly_watch_interval_sec", 0.5)
+ WaitTime = 0.5f
};
_watchTimer.Timeout += TimerTimeout;
AddChild(_watchTimer);
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 2e628cb576..64fe82664d 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -41,12 +41,20 @@
#include "core/string/ucaps.h"
#include "main/main.h"
-#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_defs.h"
-#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
#include "../utils/string_utils.h"
+StringBuilder &operator<<(StringBuilder &r_sb, const String &p_string) {
+ r_sb.append(p_string);
+ return r_sb;
+}
+
+StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
+ r_sb.append(p_cstring);
+ return r_sb;
+}
+
#define CS_INDENT " " // 4 whitespaces
#define INDENT1 CS_INDENT
@@ -60,50 +68,74 @@
#define OPEN_BLOCK "{\n"
#define CLOSE_BLOCK "}\n"
-#define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK INDENT3
-#define OPEN_BLOCK_L3 INDENT3 OPEN_BLOCK INDENT4
+#define OPEN_BLOCK_L1 INDENT1 OPEN_BLOCK
+#define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK
+#define OPEN_BLOCK_L3 INDENT3 OPEN_BLOCK
#define CLOSE_BLOCK_L2 INDENT2 CLOSE_BLOCK
#define CLOSE_BLOCK_L3 INDENT3 CLOSE_BLOCK
+#define CLOSE_BLOCK_L4 INDENT4 CLOSE_BLOCK
-#define CS_FIELD_MEMORYOWN "memoryOwn"
+#define CS_PARAM_MEMORYOWN "memoryOwn"
#define CS_PARAM_METHODBIND "method"
#define CS_PARAM_INSTANCE "ptr"
-#define CS_SMETHOD_GETINSTANCE "GetPtr"
+#define CS_STATIC_METHOD_GETINSTANCE "GetPtr"
#define CS_METHOD_CALL "Call"
+#define CS_PROPERTY_SINGLETON "Singleton"
+
+#define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor"
+#define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind"
+#define CS_STATIC_FIELD_SIGNAL_NAME_PREFIX "SignalName_"
-#define GLUE_HEADER_FILE "glue_header.h"
#define ICALL_PREFIX "godot_icall_"
-#define SINGLETON_ICALL_SUFFIX "_get_singleton"
-#define ICALL_GET_METHODBIND "__ClassDB_get_method"
+#define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method"
+#define ICALL_CLASSDB_GET_CONSTRUCTOR "ClassDB_get_constructor"
#define C_LOCAL_RET "ret"
#define C_LOCAL_VARARG_RET "vararg_ret"
#define C_LOCAL_PTRCALL_ARGS "call_args"
-#define C_MACRO_OBJECT_CONSTRUCT "GODOTSHARP_INSTANCE_OBJECT"
-
-#define C_NS_MONOUTILS "GDMonoUtils"
-#define C_NS_MONOINTERNALS "GDMonoInternals"
-#define C_METHOD_TIE_MANAGED_TO_UNMANAGED C_NS_MONOINTERNALS "::tie_managed_to_unmanaged"
-#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS "::unmanaged_get_managed"
-
-#define C_NS_MONOMARSHAL "GDMonoMarshal"
-#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_CALLABLE C_NS_MONOMARSHAL "::managed_to_callable"
-#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL "::callable_to_managed"
-#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
-#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
-
-#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
+
+#define C_CLASS_NATIVE_FUNCS "NativeFuncs"
+#define C_NS_MONOUTILS "InteropUtils"
+#define C_METHOD_TIE_MANAGED_TO_UNMANAGED "NativeInterop." C_NS_MONOUTILS ".TieManagedToUnmanaged"
+#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS ".UnmanagedGetManaged"
+#define C_METHOD_ENGINE_GET_SINGLETON "NativeInterop." 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_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"
+#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToManaged"
// Types that will be ignored by the generator and won't be available in C#.
const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
-const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
+typedef String string;
+
+void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) {
+ // C interface for enums is the same as that of 'uint32_t'. Remember to apply
+ // 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_out = "%5return (%2)%0(%1);";
+
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ r_enum_itype.c_in = "%5%0 %1_in = %1;\n";
+ r_enum_itype.c_out = "%5return (%0)%1;\n";
+ r_enum_itype.c_type = "long";
+ r_enum_itype.c_arg_in = "&%s_in";
+ }
+ r_enum_itype.c_type_in = "int";
+ r_enum_itype.c_type_out = r_enum_itype.c_type_in;
+ r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name];
+}
static String fix_doc_description(const String &p_bbcode) {
// This seems to be the correct way to do this. It's the same EditorHelp does.
@@ -794,47 +826,29 @@ void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumI
}
}
-void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
+Error BindingsGenerator::_populate_method_icalls_table(const TypeInterface &p_itype) {
for (const MethodInterface &imethod : p_itype.methods) {
if (imethod.is_virtual) {
continue;
}
- const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
+ const TypeInterface *return_type = _get_type_or_null(imethod.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
- String im_sig = "IntPtr " CS_PARAM_METHODBIND;
- String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr";
+ String im_unique_sig = get_ret_unique_sig(return_type) + ",CallMethodBind";
if (!imethod.is_static) {
- im_sig += ", IntPtr " CS_PARAM_INSTANCE;
- im_unique_sig += ",IntPtr";
+ im_unique_sig += ",CallInstance";
}
// Get arguments information
int i = 0;
for (const ArgumentInterface &iarg : imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
-
- im_sig += ", ";
- im_sig += arg_type->im_type_in;
- im_sig += " arg";
- im_sig += itos(i + 1);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
im_unique_sig += ",";
- im_unique_sig += get_unique_sig(*arg_type);
-
- i++;
- }
-
- String im_type_out = return_type->im_type_out;
-
- if (return_type->ret_as_byref_arg) {
- // Doesn't affect the unique signature
- im_type_out = "void";
-
- im_sig += ", ";
- im_sig += return_type->im_type_out;
- im_sig += " argRet";
+ im_unique_sig += get_arg_unique_sig(*arg_type);
i++;
}
@@ -845,7 +859,15 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
icall_method += "_";
icall_method += itos(method_icalls.size());
- InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, im_type_out, im_sig, im_unique_sig);
+ InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, im_unique_sig);
+
+ im_icall.is_vararg = imethod.is_vararg;
+ im_icall.is_static = imethod.is_static;
+ im_icall.return_type = imethod.return_type;
+
+ for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
+ im_icall.argument_types.push_back(F->get().type);
+ }
List<InternalCall>::Element *match = method_icalls.find(im_icall);
@@ -859,6 +881,8 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
method_icalls_map.insert(&imethod, &added->get());
}
}
+
+ return OK;
}
void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
@@ -874,7 +898,7 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array check.</param>\n"); \
p_output.append(INDENT2 "/// <returns>Whether or not the array is empty.</returns>\n"); \
p_output.append(INDENT2 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(OPEN_BLOCK_L2); \
p_output.append(INDENT3 "return instance == null || instance.Length == 0;\n"); \
p_output.append(INDENT2 CLOSE_BLOCK);
@@ -886,7 +910,7 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
p_output.append(INDENT2 "/// <param name=\"delimiter\">The delimiter to use between items.</param>\n"); \
p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
p_output.append(INDENT2 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(OPEN_BLOCK_L2); \
p_output.append(INDENT3 "return String.Join(delimiter, instance);\n"); \
p_output.append(INDENT2 CLOSE_BLOCK);
@@ -897,7 +921,7 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
p_output.append(INDENT2 "public static string Stringify(this " #m_type "[] instance)\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(OPEN_BLOCK_L2); \
p_output.append(INDENT3 "return \"[\" + instance.Join() + \"]\";\n"); \
p_output.append(INDENT2 CLOSE_BLOCK);
@@ -989,7 +1013,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n" INDENT1 "public static partial class ");
p_output.append(enum_class_name);
- p_output.append("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK_L1);
}
if (ienum.is_flags) {
@@ -999,7 +1023,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n" INDENT1 "public enum ");
p_output.append(enum_proxy_name);
p_output.append(" : long");
- p_output.append("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK_L1);
const ConstantInterface &last = ienum.constants.back()->get();
for (const ConstantInterface &iconstant : ienum.constants) {
@@ -1106,41 +1130,39 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
- // Generate sources from compressed files
+ // Generate native calls
StringBuilder cs_icalls_content;
cs_icalls_content.append("using System;\n"
- "using System.Runtime.CompilerServices;\n"
+ "using System.Diagnostics.CodeAnalysis;\n"
+ "using System.Runtime.InteropServices;\n"
+ "using Godot.NativeInterop;\n"
"\n");
cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
+ cs_icalls_content.append("#if NET\n");
+ cs_icalls_content.append(INDENT1 "[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ cs_icalls_content.append("#endif\n");
cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 "{");
cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
- cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
- cs_icalls_content.append(MEMBER_BEGIN "internal static uint bindings_version = ");
- cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.append(MEMBER_BEGIN "internal static uint cs_glue_version = ");
- cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+ cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_CORE)) + ";\n");
-#define ADD_INTERNAL_CALL(m_icall) \
- if (!m_icall.editor_only) { \
- cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal static extern "); \
- cs_icalls_content.append(m_icall.im_type_out + " "); \
- cs_icalls_content.append(m_icall.name + "("); \
- cs_icalls_content.append(m_icall.im_sig + ");\n"); \
- }
+ cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
- for (const InternalCall &internal_call : core_custom_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
- for (const InternalCall &internal_call : method_icalls) {
- ADD_INTERNAL_CALL(internal_call);
+ for (const InternalCall &icall : method_icalls) {
+ if (icall.editor_only) {
+ continue;
+ }
+ Error err = _generate_cs_native_calls(icall, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
}
-#undef ADD_INTERNAL_CALL
-
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
String internal_methods_file = path::join(base_gen_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
@@ -1152,6 +1174,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(internal_methods_file);
+ // Generate GeneratedIncludes.props
+
StringBuilder includes_props_content;
includes_props_content.append("<Project>\n"
" <ItemGroup>\n");
@@ -1215,39 +1239,40 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
+ // Generate native calls
+
StringBuilder cs_icalls_content;
cs_icalls_content.append("using System;\n"
- "using System.Runtime.CompilerServices;\n"
+ "using System.Diagnostics.CodeAnalysis;\n"
+ "using System.Runtime.InteropServices;\n"
+ "using Godot.NativeInterop;\n"
"\n");
cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
+ cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
+ cs_icalls_content.append("#if NET\n");
+ cs_icalls_content.append(INDENT1 "[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ cs_icalls_content.append("#endif\n");
+ cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" OPEN_BLOCK_L1);
cs_icalls_content.append(INDENT2 "internal static ulong godot_api_hash = ");
- cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
- cs_icalls_content.append(INDENT2 "internal static uint bindings_version = ");
- cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.append(INDENT2 "internal static uint cs_glue_version = ");
- cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
- cs_icalls_content.append("\n");
+ cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_EDITOR)) + ";\n");
-#define ADD_INTERNAL_CALL(m_icall) \
- if (m_icall.editor_only) { \
- cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal static extern "); \
- cs_icalls_content.append(m_icall.im_type_out + " "); \
- cs_icalls_content.append(m_icall.name + "("); \
- cs_icalls_content.append(m_icall.im_sig + ");\n"); \
- }
+ cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
- for (const InternalCall &internal_call : editor_custom_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
- for (const InternalCall &internal_call : method_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
+ cs_icalls_content.append("\n");
-#undef ADD_INTERNAL_CALL
+ for (const InternalCall &icall : method_icalls) {
+ if (!icall.editor_only) {
+ continue;
+ }
+ Error err = _generate_cs_native_calls(icall, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
+ }
cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
@@ -1260,6 +1285,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
compile_items.push_back(internal_methods_file);
+ // Generate GeneratedIncludes.props
+
StringBuilder includes_props_content;
includes_props_content.append("<Project>\n"
" <ItemGroup>\n");
@@ -1343,12 +1370,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
CRASH_COND(itype.is_singleton);
}
- List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
-
_log("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
- String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
-
StringBuilder output;
output.append("using System;\n"); // IntPtr
@@ -1491,53 +1514,96 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add the type name and the singleton pointer as static fields
output.append(MEMBER_BEGIN "private static Godot.Object singleton;\n");
- output.append(MEMBER_BEGIN "public static Godot.Object Singleton\n" INDENT2 "{\n" INDENT3
- "get\n" INDENT3 "{\n" INDENT4 "if (singleton == null)\n" INDENT5
- "singleton = Engine.GetSingleton(typeof(");
- output.append(itype.proxy_name);
- output.append(").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
- output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output << MEMBER_BEGIN "public static Godot.Object " CS_PROPERTY_SINGLETON "\n" INDENT2 "{\n"
+ << INDENT3 "get\n" INDENT3 "{\n" INDENT4 "if (singleton == null)\n"
+ << INDENT5 "singleton = " C_METHOD_ENGINE_GET_SINGLETON "(typeof("
+ << itype.proxy_name
+ << ").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n";
+
+ output.append(MEMBER_BEGIN "private static readonly StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
+ } else {
+ // IMPORTANT: We also generate the static fields for Godot.Object instead of declaring
+ // them manually in the `Object.base.cs` partial class declaration, because they're
+ // required by other static fields in this generated partial class declaration.
+ // Static fields are initialized in order of declaration, but when they're in different
+ // partial class declarations then it becomes harder to tell (Rider warns about this).
- output.append(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
- output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.append("." ICALL_PREFIX);
- output.append(itype.name);
- output.append(SINGLETON_ICALL_SUFFIX "();\n");
- } else if (is_derived_type) {
- // Add member fields
+ // Add native name static field
- output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(MEMBER_BEGIN "private static readonly StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
- // Add default constructor
if (itype.is_instantiable) {
- output.append(MEMBER_BEGIN "public ");
- output.append(itype.proxy_name);
- output.append("() : this(");
- output.append(itype.memory_own ? "true" : "false");
-
- // The default constructor may also be called by the engine when instancing existing native objects
- // The engine will initialize the pointer field of the managed side before calling the constructor
- // This is why we only allocate a new native object from the constructor if the pointer field is not set
- output.append(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
- output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.append("." + ctor_method);
- output.append("(this);\n" INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2);
- } else {
- // Hide the constructor
+ // Add native constructor static field
+
+ String get_constructor_method = ICALL_CLASSDB_GET_CONSTRUCTOR;
+
+ if (itype.is_singleton) {
+ // Singletons are static classes. They don't derive Godot.Object,
+ // so we need to specify the type to call the static method.
+ get_constructor_method = "Object." + get_constructor_method;
+ }
+
+ output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
+
+ << "#if NET\n"
+
+ << INDENT2 "private static unsafe readonly delegate* unmanaged<IntPtr> "
+ << CS_STATIC_FIELD_NATIVE_CTOR " = " << get_constructor_method
+ << "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
+
+ << "#else\n"
+
+ // Get rid of this one once we switch to .NET 5/6
+ << INDENT2 "private static readonly IntPtr " CS_STATIC_FIELD_NATIVE_CTOR
+ << " = " << get_constructor_method << "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
+
+ << "#endif\n";
+ }
+
+ if (is_derived_type) {
+ // Add default constructor
+ if (itype.is_instantiable) {
+ output << MEMBER_BEGIN "public " << itype.proxy_name << "() : this("
+ << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L2;
+
+ // The default constructor may also be called by the engine when instancing existing native objects
+ // The engine will initialize the pointer field of the managed side before calling the constructor
+ // This is why we only allocate a new native object from the constructor if the pointer field is not set
+ output << INDENT3 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" OPEN_BLOCK_L3
+
+ << "#if NET\n"
+
+ << INDENT4 "unsafe\n" INDENT4 OPEN_BLOCK
+ << INDENT5 BINDINGS_PTR_FIELD " = " CS_STATIC_FIELD_NATIVE_CTOR "();\n"
+ << CLOSE_BLOCK_L4
+
+ << "#else\n"
+
+ // Get rid of this one once we switch to .NET 5/6
+ << INDENT4 BINDINGS_PTR_FIELD " = _gd__invoke_class_constructor(" CS_STATIC_FIELD_NATIVE_CTOR ");\n"
+
+ << "#endif\n"
+
+ << INDENT4 C_METHOD_TIE_MANAGED_TO_UNMANAGED "(this, " BINDINGS_PTR_FIELD ");\n"
+ << CLOSE_BLOCK_L3
+ << INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2;
+ } else {
+ // Hide the constructor
+ output.append(MEMBER_BEGIN "internal ");
+ output.append(itype.proxy_name);
+ output.append("() {}\n");
+ }
+
+ // Add.. em.. trick constructor. Sort of.
output.append(MEMBER_BEGIN "internal ");
output.append(itype.proxy_name);
- output.append("() {}\n");
+ output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ") {}\n");
}
-
- // Add.. em.. trick constructor. Sort of.
- output.append(MEMBER_BEGIN "internal ");
- output.append(itype.proxy_name);
- output.append("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
}
int method_bind_count = 0;
@@ -1553,22 +1619,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'.");
}
- if (itype.is_singleton) {
- InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
-
- if (!find_icall_by_name(singleton_icall.name, custom_icalls)) {
- custom_icalls.push_back(singleton_icall);
- }
- }
-
- if (is_derived_type && itype.is_instantiable) {
- InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
-
- if (!find_icall_by_name(ctor_icall.name, custom_icalls)) {
- custom_icalls.push_back(ctor_icall);
- }
- }
-
output.append(INDENT1 CLOSE_BLOCK /* class */
CLOSE_BLOCK /* namespace */);
@@ -1669,7 +1719,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(prop_cs_type);
p_output.append(" ");
p_output.append(p_iprop.proxy_name);
- p_output.append("\n" INDENT2 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK_L2);
if (getter) {
p_output.append(INDENT3 "get\n"
@@ -1677,7 +1727,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
- OPEN_BLOCK_L3);
+ OPEN_BLOCK_L3 INDENT4);
p_output.append("return ");
p_output.append(getter->proxy_name + "(");
@@ -1706,7 +1756,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
- OPEN_BLOCK_L3);
+ OPEN_BLOCK_L3 INDENT4);
p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
@@ -1734,7 +1784,8 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
}
Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
- const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
+ const TypeInterface *return_type = _get_type_or_null(p_imethod.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
ERR_FAIL_COND_V_MSG(return_type->is_singleton, ERR_BUG,
"Method return type is a singleton: '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1745,10 +1796,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
"' from the editor API. Core API cannot have dependencies on the editor API.");
}
- String method_bind_field = "__method_bind_" + itos(p_method_bind_count);
+ String method_bind_field = CS_STATIC_FIELD_METHOD_BIND_PREFIX + itos(p_method_bind_count);
String arguments_sig;
- String cs_in_statements;
+ StringBuilder cs_in_statements;
+ bool cs_in_is_unsafe = false;
String icall_params = method_bind_field;
if (!p_imethod.is_static) {
@@ -1760,7 +1812,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Retrieve information from the arguments
const ArgumentInterface &first = p_imethod.arguments.front()->get();
for (const ArgumentInterface &iarg : p_imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1816,24 +1869,20 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arg_in = iarg.name;
arg_in += "_in";
- cs_in_statements += arg_cs_type;
- cs_in_statements += " ";
- cs_in_statements += arg_in;
- cs_in_statements += " = ";
- cs_in_statements += iarg.name;
+ cs_in_statements << INDENT3 << arg_cs_type << " " << arg_in << " = " << iarg.name;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
- cs_in_statements += ".HasValue ? ";
+ cs_in_statements << ".HasValue ? ";
} else {
- cs_in_statements += " != null ? ";
+ cs_in_statements << " != null ? ";
}
- cs_in_statements += iarg.name;
+ cs_in_statements << iarg.name;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
- cs_in_statements += ".Value : ";
+ cs_in_statements << ".Value : ";
} else {
- cs_in_statements += " : ";
+ cs_in_statements << " : ";
}
String cs_type = arg_cs_type;
@@ -1843,8 +1892,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String def_arg = sformat(iarg.default_argument, cs_type);
- cs_in_statements += def_arg;
- cs_in_statements += ";\n" INDENT3;
+ cs_in_statements << def_arg << ";\n";
icall_params += arg_type->cs_in.is_empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
@@ -1857,16 +1905,25 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
} else {
icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
}
+
+ cs_in_is_unsafe |= arg_type->cs_in_is_unsafe;
}
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static readonly IntPtr ");
- p_output.append(method_bind_field);
- p_output.append(" = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
- p_output.append(p_imethod.name);
- p_output.append("\");\n");
+ p_output << MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static readonly IntPtr "
+ << method_bind_field << " = ";
+
+ if (p_itype.is_singleton) {
+ // Singletons are static classes. They don't derive Godot.Object,
+ // so we need to specify the type to call the static method.
+ p_output << "Object.";
+ }
+
+ p_output << ICALL_CLASSDB_GET_METHOD "(" BINDINGS_NATIVE_NAME_FIELD ", \""
+ << p_imethod.name
+ << "\");\n";
}
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
@@ -1919,6 +1976,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("virtual ");
}
+ if (cs_in_is_unsafe) {
+ p_output.append("unsafe ");
+ }
+
String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters);
p_output.append(return_cs_type + " ");
@@ -1929,11 +1990,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Godot virtual method must be overridden, therefore we return a default value by default.
if (return_type->cname == name_cache.type_void) {
- p_output.append("return;\n" CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L2);
} else {
- p_output.append("return default(");
- p_output.append(return_cs_type);
- p_output.append(");\n" CLOSE_BLOCK_L2);
+ p_output.append(INDENT3 "return default;\n" CLOSE_BLOCK_L2);
}
return OK; // Won't increment method bind count
@@ -1942,7 +2001,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (p_imethod.requires_object_call) {
// Fallback to Godot's object.Call(string, params)
- p_output.append(CS_METHOD_CALL "(\"");
+ p_output.append(INDENT3 CS_METHOD_CALL "(\"");
p_output.append(p_imethod.name);
p_output.append("\"");
@@ -1966,15 +2025,16 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
im_call += im_icall->name;
if (p_imethod.arguments.size()) {
- p_output.append(cs_in_statements);
+ p_output.append(cs_in_statements.as_string());
}
if (return_type->cname == name_cache.type_void) {
- p_output.append(im_call + "(" + icall_params + ");\n");
+ p_output << INDENT3 << im_call << "(" << icall_params << ");\n";
} else if (return_type->cs_out.is_empty()) {
- p_output.append("return " + im_call + "(" + icall_params + ");\n");
+ p_output << INDENT3 "return " << im_call << "(" << icall_params << ");\n";
} else {
- p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_cs_type, return_type->im_type_out));
+ p_output.append(sformat(return_type->cs_out, im_call, icall_params,
+ return_cs_type, return_type->c_type_out, String(), INDENT3));
p_output.append("\n");
}
@@ -1992,7 +2052,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// Retrieve information from the arguments
const ArgumentInterface &first = p_isignal.arguments.front()->get();
for (const ArgumentInterface &iarg : p_isignal.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "'.");
@@ -2058,7 +2119,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here.
// Cached signal name (StringName)
- p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static StringName __signal_name_");
+ p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN
+ "private static readonly StringName " CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
p_output.append(p_isignal.name);
p_output.append(" = \"");
p_output.append(p_isignal.name);
@@ -2075,21 +2137,21 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(delegate_name);
p_output.append(" ");
p_output.append(p_isignal.proxy_name);
- p_output.append("\n" OPEN_BLOCK_L2);
+ p_output.append("\n" OPEN_BLOCK_L2 INDENT3);
if (p_itype.is_singleton) {
- p_output.append("add => Singleton.Connect(__signal_name_");
+ p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
} else {
- p_output.append("add => Connect(__signal_name_");
+ p_output.append("add => Connect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
}
p_output.append(p_isignal.name);
p_output.append(", new Callable(value));\n");
if (p_itype.is_singleton) {
- p_output.append(INDENT3 "remove => Singleton.Disconnect(__signal_name_");
+ p_output.append(INDENT3 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
} else {
- p_output.append(INDENT3 "remove => Disconnect(__signal_name_");
+ p_output.append(INDENT3 "remove => Disconnect(" CS_STATIC_FIELD_SIGNAL_NAME_PREFIX);
}
p_output.append(p_isignal.name);
@@ -2100,388 +2162,218 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
return OK;
}
-Error BindingsGenerator::generate_glue(const String &p_output_dir) {
- ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
-
- bool dir_exists = DirAccess::exists(p_output_dir);
- ERR_FAIL_COND_V_MSG(!dir_exists, ERR_FILE_BAD_PATH, "The output directory does not exist.");
-
- StringBuilder output;
-
- output.append("/* THIS FILE IS GENERATED DO NOT EDIT */\n");
- output.append("#include \"" GLUE_HEADER_FILE "\"\n");
- output.append("\n#ifdef MONO_GLUE_ENABLED\n");
-
- generated_icall_funcs.clear();
-
- for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) {
- const TypeInterface &itype = type_elem.value;
-
- bool is_derived_type = itype.base_name != StringName();
+Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output) {
+ bool ret_void = p_icall.return_type.cname == name_cache.type_void;
- if (!is_derived_type) {
- // Some Object assertions
- CRASH_COND(itype.cname != name_cache.type_Object);
- CRASH_COND(!itype.is_instantiable);
- CRASH_COND(itype.api_type != ClassDB::API_CORE);
- CRASH_COND(itype.is_singleton);
- }
-
- List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
-
- OS::get_singleton()->print("Generating %s...\n", itype.name.utf8().get_data());
-
- String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
-
- for (const MethodInterface &imethod : itype.methods) {
- Error method_err = _generate_glue_method(itype, imethod, output);
- ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
- "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
- }
-
- if (itype.is_singleton) {
- String singleton_icall_name = ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX;
- InternalCall singleton_icall = InternalCall(itype.api_type, singleton_icall_name, "IntPtr");
-
- if (!find_icall_by_name(singleton_icall.name, custom_icalls)) {
- custom_icalls.push_back(singleton_icall);
- }
+ const TypeInterface *return_type = _get_type_or_null(p_icall.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
- output.append("Object* ");
- output.append(singleton_icall_name);
- output.append("() " OPEN_BLOCK "\treturn Engine::get_singleton()->get_singleton_object(\"");
- output.append(itype.proxy_name);
- output.append("\");\n" CLOSE_BLOCK "\n");
- }
+ StringBuilder c_func_sig;
+ StringBuilder c_in_statements;
+ StringBuilder c_args_var_content;
- if (is_derived_type && itype.is_instantiable) {
- InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
+ c_func_sig << "IntPtr " CS_PARAM_METHODBIND;
- if (!find_icall_by_name(ctor_icall.name, custom_icalls)) {
- custom_icalls.push_back(ctor_icall);
- }
-
- output.append("Object* ");
- output.append(ctor_method);
- output.append("(MonoObject* obj) " OPEN_BLOCK
- "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
- output.append(itype.name);
- output.append("\");\n"
- "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
- "\treturn instance;\n" CLOSE_BLOCK "\n");
- }
+ if (!p_icall.is_static) {
+ c_func_sig += ", IntPtr " CS_PARAM_INSTANCE;
}
- output.append("namespace GodotSharpBindings\n" OPEN_BLOCK "\n");
-
- output.append("uint64_t get_core_api_hash() { return ");
- output.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "U; }\n");
-
- output.append("#ifdef TOOLS_ENABLED\n"
- "uint64_t get_editor_api_hash() { return ");
- output.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + "U; }\n");
- output.append("#endif // TOOLS_ENABLED\n");
-
- output.append("uint32_t get_bindings_version() { return ");
- output.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
-
- output.append("uint32_t get_cs_glue_version() { return ");
- output.append(String::num_uint64(CS_GLUE_VERSION) + "; }\n");
-
- output.append("\nvoid register_generated_icalls() " OPEN_BLOCK);
- output.append("\tgodot_register_glue_header_icalls();\n");
-
-#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
- { \
- output.append("\tGDMonoUtils::add_internal_call("); \
- output.append("\"" BINDINGS_NAMESPACE "."); \
- output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
- output.append("::"); \
- output.append(m_icall.name); \
- output.append("\", "); \
- output.append(m_icall.name); \
- output.append(");\n"); \
- }
-
- bool tools_sequence = false;
- for (const InternalCall &internal_call : core_custom_icalls) {
- if (tools_sequence) {
- if (!internal_call.editor_only) {
- tools_sequence = false;
- output.append("#endif\n");
- }
- } else {
- if (internal_call.editor_only) {
- output.append("#ifdef TOOLS_ENABLED\n");
- tools_sequence = true;
- }
- }
-
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
-
- if (tools_sequence) {
- tools_sequence = false;
- output.append("#endif\n");
- }
-
- output.append("#ifdef TOOLS_ENABLED\n");
- for (const InternalCall &internal_call : editor_custom_icalls) {
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
- output.append("#endif // TOOLS_ENABLED\n");
-
- for (const InternalCall &internal_call : method_icalls) {
- if (tools_sequence) {
- if (!internal_call.editor_only) {
- tools_sequence = false;
- output.append("#endif\n");
- }
- } else {
- if (internal_call.editor_only) {
- output.append("#ifdef TOOLS_ENABLED\n");
- tools_sequence = true;
- }
- }
-
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
-
- if (tools_sequence) {
- tools_sequence = false;
- output.append("#endif\n");
- }
-
-#undef ADD_INTERNAL_CALL_REGISTRATION
-
- output.append(CLOSE_BLOCK "\n} // namespace GodotSharpBindings\n");
-
- output.append("\n#endif // MONO_GLUE_ENABLED\n");
-
- Error save_err = _save_file(path::join(p_output_dir, "mono_glue.gen.cpp"), output);
- if (save_err != OK) {
- return save_err;
- }
-
- OS::get_singleton()->print("Mono glue generated successfully\n");
-
- return OK;
-}
-
-uint32_t BindingsGenerator::get_version() {
- return BINDINGS_GENERATOR_VERSION;
-}
-
-Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
- Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
-
- file->store_string(p_content.as_string());
-
- return OK;
-}
-
-Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, StringBuilder &p_output) {
- if (p_imethod.is_virtual) {
- return OK; // Ignore
- }
-
- bool ret_void = p_imethod.return_type.cname == name_cache.type_void;
-
- const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
-
- String argc_str = itos(p_imethod.arguments.size());
-
- String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND;
- if (!p_imethod.is_static) {
- c_func_sig += ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
- }
- String c_in_statements;
- String c_args_var_content;
-
// Get arguments information
int i = 0;
- for (const ArgumentInterface &iarg : p_imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ for (const TypeReference &arg_type_ref : p_icall.argument_types) {
+ const TypeInterface *arg_type = _get_type_or_null(arg_type_ref);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Return type not found
String c_param_name = "arg" + itos(i + 1);
- if (p_imethod.is_vararg) {
- if (i < p_imethod.arguments.size() - 1) {
- c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
- c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(";
- c_in_statements += itos(i);
- c_in_statements += sformat(", &%s_in);\n", c_param_name);
+ if (p_icall.is_vararg) {
+ if (i < p_icall.get_arguments_count() - 1) {
+ string c_in_vararg = arg_type->c_in_vararg;
+
+ if (arg_type->is_object_type) {
+ c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromGodotObject(%1);\n";
+ }
+
+ ERR_FAIL_COND_V_MSG(c_in_vararg.is_empty(), ERR_BUG,
+ "VarArg support not implemented for parameter type: " + arg_type->name);
+
+ c_in_statements
+ << sformat(c_in_vararg, return_type->c_type, c_param_name,
+ String(), String(), String(), INDENT4)
+ << INDENT4 C_LOCAL_PTRCALL_ARGS "[" << itos(i)
+ << "] = new IntPtr(&" << c_param_name << "_in);\n";
}
} else {
if (i > 0) {
- c_args_var_content += ", ";
+ c_args_var_content << ", ";
}
if (arg_type->c_in.size()) {
- c_in_statements += sformat(arg_type->c_in, arg_type->c_type, c_param_name);
+ c_in_statements << sformat(arg_type->c_in, arg_type->c_type, c_param_name,
+ String(), String(), String(), INDENT3);
}
- c_args_var_content += sformat(arg_type->c_arg_in, c_param_name);
+ c_args_var_content << sformat(arg_type->c_arg_in, c_param_name);
}
- c_func_sig += ", ";
- c_func_sig += arg_type->c_type_in;
- c_func_sig += " ";
- c_func_sig += c_param_name;
+ c_func_sig << ", " << arg_type->c_type_in << " " << c_param_name;
i++;
}
- if (return_type->ret_as_byref_arg) {
- c_func_sig += ", ";
- c_func_sig += return_type->c_type_in;
- c_func_sig += " ";
- c_func_sig += "arg_ret";
-
- i++;
- }
+ String icall_method = p_icall.name;
- HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
- ERR_FAIL_NULL_V(match, ERR_BUG);
+ // Generate icall function
- const InternalCall *im_icall = match->value;
- String icall_method = im_icall->name;
+ r_output << MEMBER_BEGIN "internal static unsafe " << (ret_void ? "void" : return_type->c_type_out) << " "
+ << icall_method << "(" << c_func_sig.as_string() << ") " OPEN_BLOCK;
- if (!generated_icall_funcs.find(im_icall)) {
- generated_icall_funcs.push_back(im_icall);
+ if (!ret_void && (!p_icall.is_vararg || return_type->cname != name_cache.type_Variant)) {
+ String ptrcall_return_type;
+ String initialization;
- if (im_icall->editor_only) {
- p_output.append("#ifdef TOOLS_ENABLED\n");
+ if (return_type->is_object_type) {
+ ptrcall_return_type = return_type->is_ref_counted ? "godot_ref" : return_type->c_type;
+ initialization = " = default";
+ } else {
+ ptrcall_return_type = return_type->c_type;
}
- // Generate icall function
+ r_output << INDENT3;
- p_output.append((ret_void || return_type->ret_as_byref_arg) ? "void " : return_type->c_type_out + " ");
- p_output.append(icall_method);
- p_output.append("(");
- p_output.append(c_func_sig);
- p_output.append(") " OPEN_BLOCK);
+ if (return_type->is_ref_counted || return_type->c_type_is_disposable_struct) {
+ r_output << "using ";
- if (!ret_void) {
- String ptrcall_return_type;
- String initialization;
-
- if (p_imethod.is_vararg && return_type->cname != name_cache.type_Variant) {
- // VarArg methods always return Variant, but there are some cases in which MethodInfo provides
- // a specific return type. We trust this information is valid. We need a temporary local to keep
- // the Variant alive until the method returns. Otherwise, if the returned Variant holds a RefPtr,
- // it could be deleted too early. This is the case with GDScript.new() which returns OBJECT.
- // Alternatively, we could just return Variant, but that would result in a worse API.
- p_output.append("\tVariant " C_LOCAL_VARARG_RET ";\n");
+ if (initialization.is_empty()) {
+ initialization = " = default";
}
+ } else if (return_type->c_ret_needs_default_initialization) {
+ initialization = " = default";
+ }
- if (return_type->is_object_type) {
- ptrcall_return_type = return_type->is_ref_counted ? "Ref<RefCounted>" : return_type->c_type;
- initialization = return_type->is_ref_counted ? "" : " = nullptr";
- } else {
- ptrcall_return_type = return_type->c_type;
- }
+ r_output << ptrcall_return_type << " " C_LOCAL_RET << initialization << ";\n";
+ }
- p_output.append("\t" + ptrcall_return_type);
- p_output.append(" " C_LOCAL_RET);
- p_output.append(initialization + ";\n");
+ if (!p_icall.is_static) {
+ r_output << INDENT3 "if (" CS_PARAM_INSTANCE " == IntPtr.Zero)\n"
+ << INDENT4 "throw new ArgumentNullException(nameof(" CS_PARAM_INSTANCE "));\n";
+ }
- String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()";
+ String argc_str = itos(p_icall.get_arguments_count());
- if (!p_imethod.is_static) {
- if (return_type->ret_as_byref_arg) {
- p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
- p_output.append(fail_ret);
- p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
- } else {
- p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
- p_output.append(fail_ret);
- p_output.append(");\n");
- }
- }
- } else {
- if (!p_imethod.is_static) {
- p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
- }
- }
+ 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";
- if (p_imethod.arguments.size()) {
- if (p_imethod.is_vararg) {
- String vararg_arg = "arg" + argc_str;
- String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg
-
- p_output.append("\tint vararg_length = mono_array_length(");
- p_output.append(vararg_arg);
- p_output.append(");\n\tint total_length = ");
- p_output.append(real_argc_str);
- p_output.append(" + vararg_length;\n"
- "\tArgumentsVector<Variant> varargs(vararg_length);\n"
- "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n");
- p_output.append(c_in_statements);
- p_output.append("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
- "\t\tMonoObject* elem = mono_array_get(");
- p_output.append(vararg_arg);
- p_output.append(", MonoObject*, i);\n"
- "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
- "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
- p_output.append(real_argc_str);
- p_output.append(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK);
- } else {
- p_output.append(c_in_statements);
- p_output.append("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
- p_output.append(argc_str + "] = { ");
- p_output.append(c_args_var_content + " };\n");
- }
- }
+ // MethodBind Call
+ r_output << base_indent;
- if (p_imethod.is_vararg) {
- p_output.append("\tCallable::CallError vcall_error;\n\t");
+ // VarArg methods always return Variant, but there are some cases in which MethodInfo provides
+ // a specific return type. We trust this information is valid. We need a temporary local to keep
+ // the Variant alive until the method returns. Otherwise, if the returned Variant holds a RefPtr,
+ // it could be deleted too early. This is the case with GDScript.new() which returns OBJECT.
+ // Alternatively, we could just return Variant, but that would result in a worse API.
if (!ret_void) {
- // See the comment on the C_LOCAL_VARARG_RET declaration
if (return_type->cname != name_cache.type_Variant) {
- p_output.append(C_LOCAL_VARARG_RET " = ");
+ r_output << "using godot_variant " << C_LOCAL_VARARG_RET " = ";
} else {
- p_output.append(C_LOCAL_RET " = ");
+ r_output << "using godot_variant " << C_LOCAL_RET " = ";
}
}
- p_output.append(CS_PARAM_METHODBIND "->call(");
- p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
- p_output.append(", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr");
- p_output.append(", total_length, vcall_error);\n");
+ 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";
if (!ret_void) {
- // See the comment on the C_LOCAL_VARARG_RET declaration
if (return_type->cname != name_cache.type_Variant) {
- p_output.append("\t" C_LOCAL_RET " = " C_LOCAL_VARARG_RET ";\n");
+ if (return_type->cname == name_cache.enum_Error) {
+ 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);
+ r_output << base_indent << C_LOCAL_RET " = " C_LOCAL_VARARG_RET ";\n";
+ }
}
}
} else {
- p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(");
- p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
- p_output.append(", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, ");
- p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n");
+ // MethodBind PtrCall
+ r_output << base_indent << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_ptrcall("
+ << CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
+ << ", " << (p_icall.get_arguments_count() ? C_LOCAL_PTRCALL_ARGS : "null")
+ << ", " << (!ret_void ? "&" C_LOCAL_RET ");\n" : "null);\n");
}
+ // Return statement
+
if (!ret_void) {
if (return_type->c_out.is_empty()) {
- p_output.append("\treturn " C_LOCAL_RET ";\n");
- } else if (return_type->ret_as_byref_arg) {
- p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name, "arg_ret"));
+ r_output << base_indent << "return " C_LOCAL_RET ";\n";
} else {
- p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name));
+ r_output << sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET,
+ return_type->name, String(), String(), base_indent);
}
}
+ };
+
+ if (p_icall.get_arguments_count()) {
+ if (p_icall.is_vararg) {
+ String vararg_arg = "arg" + argc_str;
+ String real_argc_str = itos(p_icall.get_arguments_count() - 1); // Arguments count without vararg
+
+ p_icall.get_arguments_count();
+
+ r_output << INDENT3 "int vararg_length = " << vararg_arg << ".Length;\n"
+ << INDENT3 "int total_length = " << real_argc_str << " + vararg_length;\n";
+
+ r_output << INDENT3 "Span<godot_variant> varargs_span = vararg_length <= VarArgsSpanThreshold ?\n"
+ << INDENT4 "stackalloc godot_variant[VarArgsSpanThreshold].Cleared() :\n"
+ << INDENT4 "new godot_variant[vararg_length];\n";
+
+ r_output << INDENT3 "Span<IntPtr> " C_LOCAL_PTRCALL_ARGS "_span = total_length <= VarArgsSpanThreshold ?\n"
+ << INDENT4 "stackalloc IntPtr[VarArgsSpanThreshold] :\n"
+ << INDENT4 "new IntPtr[total_length];\n";
+
+ r_output << INDENT3 "using var variantSpanDisposer = new VariantSpanDisposer(varargs_span);\n";
+
+ r_output << INDENT3 "fixed (godot_variant* varargs = &MemoryMarshal.GetReference(varargs_span))\n"
+ << INDENT3 "fixed (IntPtr* " C_LOCAL_PTRCALL_ARGS " = "
+ "&MemoryMarshal.GetReference(" C_LOCAL_PTRCALL_ARGS "_span))\n"
+ << OPEN_BLOCK_L3;
+
+ r_output << c_in_statements.as_string();
- p_output.append(CLOSE_BLOCK "\n");
+ r_output << INDENT4 "for (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
+ << INDENT5 "varargs[i] = " C_METHOD_MANAGED_TO_VARIANT "(" << vararg_arg << "[i]);\n"
+ << INDENT5 C_LOCAL_PTRCALL_ARGS "[" << real_argc_str << " + i] = new IntPtr(&varargs[i]);\n"
+ << CLOSE_BLOCK_L4;
- if (im_icall->editor_only) {
- p_output.append("#endif // TOOLS_ENABLED\n");
+ generate_call_and_return_stmts(INDENT4);
+
+ r_output << CLOSE_BLOCK_L3;
+ } else {
+ r_output << c_in_statements.as_string();
+
+ r_output << INDENT3 "void** " C_LOCAL_PTRCALL_ARGS " = stackalloc void*["
+ << argc_str << "] { " << c_args_var_content.as_string() << " };\n";
+
+ generate_call_and_return_stmts(INDENT3);
}
+ } else {
+ generate_call_and_return_stmts(INDENT3);
}
+ r_output << CLOSE_BLOCK_L2;
+
+ return OK;
+}
+
+Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
+
+ file->store_string(p_content.as_string());
+
return OK;
}
@@ -2514,27 +2406,6 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(con
return nullptr;
}
-const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placeholder(const TypeReference &p_typeref) {
- const TypeInterface *found = _get_type_or_null(p_typeref);
-
- if (found) {
- return found;
- }
-
- ERR_PRINT(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'.");
-
- HashMap<StringName, TypeInterface>::ConstIterator match = placeholder_types.find(p_typeref.cname);
-
- if (match) {
- return &match->value;
- }
-
- TypeInterface placeholder;
- TypeInterface::create_placeholder_type(placeholder, p_typeref.cname);
-
- return &placeholder_types.insert(placeholder.cname, placeholder)->value;
-}
-
const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters) {
if (p_generic_type_parameters.is_empty()) {
return "";
@@ -2548,7 +2419,8 @@ const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface
int i = 0;
String params = "<";
for (const TypeReference &param_type : p_generic_type_parameters) {
- const TypeInterface *param_itype = _get_type_or_placeholder(param_type);
+ const TypeInterface *param_itype = _get_type_or_null(param_type);
+ ERR_FAIL_NULL_V(param_itype, "");
ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "",
"Generic type parameter is a singleton: '" + param_itype->name + "'.");
@@ -2666,8 +2538,6 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
case Variant::RECT2:
case Variant::VECTOR3:
case Variant::RID:
- case Variant::ARRAY:
- case Variant::DICTIONARY:
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
case Variant::PACKED_INT64_ARRAY:
@@ -2680,6 +2550,10 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
case Variant::CALLABLE:
case Variant::SIGNAL:
return p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ case Variant::ARRAY:
+ return p_arg_type.name == Variant::get_type_name(p_val.get_type()) || p_arg_type.cname == name_cache.type_Array_generic;
+ case Variant::DICTIONARY:
+ return p_arg_type.name == Variant::get_type_name(p_val.get_type()) || p_arg_type.cname == name_cache.type_Dictionary_generic;
case Variant::OBJECT:
return p_arg_type.is_object_type;
case Variant::VECTOR2I:
@@ -2744,18 +2618,24 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted);
itype.memory_own = itype.is_ref_counted;
- itype.c_out = "\treturn ";
+ itype.c_out = "%5return ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
- itype.c_out += itype.is_ref_counted ? "(%1.ptr());\n" : "(%1);\n";
+ itype.c_out += itype.is_ref_counted ? "(%1._reference);\n" : "(%1);\n";
- itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)";
+ itype.cs_type = itype.proxy_name;
+
+ if (itype.is_singleton) {
+ itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")";
+ } else {
+ itype.cs_in = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)";
+ }
- itype.c_type = "Object*";
+ itype.cs_out = "%5return (%2)%0(%1);";
+
+ itype.c_arg_in = "(void*)%s";
+ itype.c_type = "IntPtr";
itype.c_type_in = itype.c_type;
- itype.c_type_out = "MonoObject*";
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = "IntPtr";
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_out = "Object";
// Populate properties
@@ -2887,7 +2767,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
} else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) {
- imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ imethod.return_type.cname = Variant::get_type_name(return_info.type) + "_@generic";
imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string));
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type.cname = return_info.hint_string;
@@ -2919,7 +2799,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
@@ -3027,7 +2907,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
@@ -3246,7 +3126,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false,
"Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value.");
- r_iarg.default_argument = "null";
+ r_iarg.default_argument = "default";
break;
case Variant::ARRAY:
r_iarg.default_argument = "new %s { }";
@@ -3325,7 +3205,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "default";
break;
default:
- CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type()));
+ ERR_FAIL_V_MSG(false, "Unexpected Variant type: " + itos(p_val.get_type()));
break;
}
@@ -3341,20 +3221,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
TypeInterface itype;
-#define INSERT_STRUCT_TYPE(m_type) \
- { \
- itype = TypeInterface::create_value_type(String(#m_type)); \
- itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \
- itype.c_out = "\t*%3 = MARSHALLED_OUT(" #m_type ", %1);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type_in = "GDMonoMarshal::M_" #m_type "*"; \
- itype.c_type_out = "GDMonoMarshal::M_" #m_type; \
- itype.cs_in = "ref %s"; \
- /* in cs_out, im_type_out (%3) includes the 'out ' part */ \
- itype.cs_out = "%0(%1, %3 argRet); return argRet;"; \
- itype.im_type_out = "out " + itype.cs_type; \
- itype.ret_as_byref_arg = true; \
- builtin_types.insert(itype.cname, itype); \
+#define INSERT_STRUCT_TYPE(m_type) \
+ { \
+ 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; \
+ builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2)
@@ -3370,56 +3244,56 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_STRUCT_TYPE(AABB)
INSERT_STRUCT_TYPE(Color)
INSERT_STRUCT_TYPE(Plane)
+ INSERT_STRUCT_TYPE(Vector4)
+ INSERT_STRUCT_TYPE(Vector4i)
+ INSERT_STRUCT_TYPE(Projection)
#undef INSERT_STRUCT_TYPE
// bool
itype = TypeInterface::create_value_type(String("bool"));
- {
- // MonoBoolean <---> bool
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "bool";
- itype.c_type_in = "MonoBoolean";
- itype.c_type_out = itype.c_type_in;
- itype.c_arg_in = "&%s_in";
- }
- itype.im_type_in = itype.name;
- itype.im_type_out = itype.name;
+ itype.c_type = "godot_bool";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
+ itype.c_arg_in = "&%s";
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromBool(%1);\n";
builtin_types.insert(itype.cname, itype);
// Integer types
{
// C interface for 'uint32_t' is the same as that of enums. Remember to apply
// any of the changes done here to 'TypeInterface::postsetup_enum_type' as well.
-#define INSERT_INT_TYPE(m_name, m_c_type_in_out, m_c_type) \
- { \
- itype = TypeInterface::create_value_type(String(m_name)); \
- { \
- itype.c_in = "\t%0 %1_in = (%0)%1;\n"; \
- itype.c_out = "\treturn (%0)%1;\n"; \
- itype.c_type = #m_c_type; \
- itype.c_arg_in = "&%s_in"; \
- } \
- itype.c_type_in = #m_c_type_in_out; \
- itype.c_type_out = itype.c_type_in; \
- itype.im_type_in = itype.name; \
- itype.im_type_out = itype.name; \
- builtin_types.insert(itype.cname, itype); \
+#define INSERT_INT_TYPE(m_name) \
+ { \
+ itype = TypeInterface::create_value_type(String(m_name)); \
+ if (itype.name != "long" && itype.name != "ulong") { \
+ itype.c_in = "%5%0 %1_in = %1;\n"; \
+ itype.c_out = "%5return (%0)%1;\n"; \
+ itype.c_type = "long"; \
+ itype.c_arg_in = "&%s_in"; \
+ } else { \
+ itype.c_arg_in = "&%s"; \
+ } \
+ itype.c_type_in = itype.name; \
+ itype.c_type_out = itype.name; \
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromInt(%1);\n"; \
+ builtin_types.insert(itype.cname, itype); \
}
// The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type'
- INSERT_INT_TYPE("sbyte", int8_t, int64_t);
- INSERT_INT_TYPE("short", int16_t, int64_t);
- INSERT_INT_TYPE("int", int32_t, int64_t);
- INSERT_INT_TYPE("long", int64_t, int64_t);
- INSERT_INT_TYPE("byte", uint8_t, int64_t);
- INSERT_INT_TYPE("ushort", uint16_t, int64_t);
- INSERT_INT_TYPE("uint", uint32_t, int64_t);
- INSERT_INT_TYPE("ulong", uint64_t, int64_t);
+ INSERT_INT_TYPE("sbyte");
+ INSERT_INT_TYPE("short");
+ INSERT_INT_TYPE("int");
+ INSERT_INT_TYPE("long");
+ INSERT_INT_TYPE("byte");
+ INSERT_INT_TYPE("ushort");
+ INSERT_INT_TYPE("uint");
+ INSERT_INT_TYPE("ulong");
}
+#undef INSERT_INT_TYPE
+
// Floating point types
{
// float
@@ -3427,18 +3301,17 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "float";
itype.cname = itype.name;
itype.proxy_name = "float";
+ itype.cs_type = itype.proxy_name;
{
// The expected type for 'float' in ptrcall is 'double'
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_in = "%5%0 %1_in = %1;\n";
+ itype.c_out = "%5return (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "float";
- itype.c_type_out = "float";
itype.c_arg_in = "&%s_in";
}
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_in = itype.proxy_name;
+ itype.c_type_out = itype.proxy_name;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
builtin_types.insert(itype.cname, itype);
// double
@@ -3446,15 +3319,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "double";
itype.cname = itype.name;
itype.proxy_name = "double";
- {
- itype.c_type = "double";
- itype.c_type_in = "double";
- itype.c_type_out = "double";
- itype.c_arg_in = "&%s";
- }
itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type = "double";
+ itype.c_arg_in = "&%s";
+ itype.c_type_in = itype.proxy_name;
+ itype.c_type_out = itype.proxy_name;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
builtin_types.insert(itype.cname, itype);
}
@@ -3463,15 +3333,15 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "String";
itype.cname = itype.name;
itype.proxy_name = "string";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
- itype.c_out = "\treturn " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "MonoString*";
- itype.c_type_out = "MonoString*";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
+ itype.c_out = "%5return " C_METHOD_MONOSTR_FROM_GODOT "(&%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_string";
+ itype.c_type_in = itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue(" C_METHOD_MONOSTR_TO_GODOT "(%1));\n";
builtin_types.insert(itype.cname, itype);
// StringName
@@ -3479,17 +3349,18 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "StringName";
itype.cname = itype.name;
itype.proxy_name = "StringName";
- itype.c_in = "\t%0 %1_in = %1 ? *%1 : StringName();\n";
- itype.c_out = "\treturn memnew(StringName(%1));\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "StringName." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in = "ref %0.NativeValue";
+ // 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_type = "godot_string_name";
+ itype.c_type_in = "ref " + 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_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
builtin_types.insert(itype.cname, itype);
// NodePath
@@ -3497,15 +3368,17 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "NodePath";
itype.cname = itype.name;
itype.proxy_name = "NodePath";
- itype.c_out = "\treturn memnew(NodePath(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in = "ref %0.NativeValue";
+ // 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_type = "godot_node_path";
+ itype.c_type_in = "ref " + 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;
builtin_types.insert(itype.cname, itype);
// RID
@@ -3513,15 +3386,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "RID";
itype.cname = itype.name;
itype.proxy_name = "RID";
- itype.c_out = "\treturn memnew(RID(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.c_arg_in = "&%s";
+ itype.c_type = itype.cs_type;
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
builtin_types.insert(itype.cname, itype);
// Variant
@@ -3529,29 +3398,26 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Variant";
itype.cname = itype.name;
itype.proxy_name = "object";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n";
- itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "MonoObject*";
- itype.c_type_out = "MonoObject*";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "object";
- itype.im_type_out = 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_arg_in = "&%s_in";
+ itype.c_type = "godot_variant";
+ itype.c_type_in = itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
builtin_types.insert(itype.cname, itype);
// Callable
itype = TypeInterface::create_value_type(String("Callable"));
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(*%1);\n";
- itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_CALLABLE "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type_in = "GDMonoMarshal::M_Callable*";
- itype.c_type_out = "GDMonoMarshal::M_Callable";
itype.cs_in = "ref %s";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.im_type_out = "out " + itype.cs_type;
- itype.ret_as_byref_arg = true;
+ 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_arg_in = "&%s_in";
+ itype.c_type = "godot_callable";
+ itype.c_type_in = "ref " + itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
builtin_types.insert(itype.cname, itype);
// Signal
@@ -3559,19 +3425,15 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Signal";
itype.cname = itype.name;
itype.proxy_name = "SignalInfo";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(*%1);\n";
- itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_SIGNAL "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "GDMonoMarshal::M_SignalInfo*";
- itype.c_type_out = "GDMonoMarshal::M_SignalInfo";
- itype.cs_in = "ref %s";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.cs_type;
- itype.im_type_out = "out " + itype.cs_type;
- itype.ret_as_byref_arg = true;
+ itype.cs_in = "ref %s";
+ 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";
+ itype.c_type = "godot_signal";
+ itype.c_type_in = "ref " + itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
builtin_types.insert(itype.cname, itype);
// VarArg (fictitious type to represent variable arguments)
@@ -3579,46 +3441,44 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "VarArg";
itype.cname = itype.name;
itype.proxy_name = "object[]";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(Array) "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = "Array";
- itype.c_type_in = "MonoArray*";
itype.cs_type = "params object[]";
- itype.im_type_in = "object[]";
+ // 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";
+ itype.c_type_in = "object[]";
builtin_types.insert(itype.cname, itype);
-#define INSERT_ARRAY_FULL(m_name, m_type, m_proxy_t) \
- { \
- itype = TypeInterface(); \
- itype.name = #m_name; \
- itype.cname = itype.name; \
- itype.proxy_name = #m_proxy_t "[]"; \
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
- itype.c_out = "\treturn " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type = #m_type; \
- itype.c_type_in = "MonoArray*"; \
- itype.c_type_out = "MonoArray*"; \
- itype.cs_type = itype.proxy_name; \
- itype.im_type_in = itype.proxy_name; \
- itype.im_type_out = itype.proxy_name; \
- builtin_types.insert(itype.name, itype); \
+#define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \
+ { \
+ itype = TypeInterface(); \
+ itype.name = #m_name; \
+ itype.cname = itype.name; \
+ 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_arg_in = "&%s_in"; \
+ itype.c_type = #m_managed_type; \
+ itype.c_type_in = itype.proxy_name; \
+ itype.c_type_out = itype.proxy_name; \
+ itype.c_type_is_disposable_struct = true; \
+ builtin_types.insert(itype.name, itype); \
}
-#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
+#define INSERT_ARRAY(m_type, m_managed_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_managed_type, m_proxy_t)
- INSERT_ARRAY(PackedInt32Array, int);
- INSERT_ARRAY(PackedInt64Array, long);
- INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, byte);
+ INSERT_ARRAY(PackedInt32Array, godot_packed_int32_array, int);
+ INSERT_ARRAY(PackedInt64Array, godot_packed_int64_array, long);
+ INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, godot_packed_byte_array, byte);
- INSERT_ARRAY(PackedFloat32Array, float);
- INSERT_ARRAY(PackedFloat64Array, double);
+ INSERT_ARRAY(PackedFloat32Array, godot_packed_float32_array, float);
+ INSERT_ARRAY(PackedFloat64Array, godot_packed_float64_array, double);
- INSERT_ARRAY(PackedStringArray, string);
+ INSERT_ARRAY(PackedStringArray, godot_packed_string_array, string);
- INSERT_ARRAY(PackedColorArray, Color);
- INSERT_ARRAY(PackedVector2Array, Vector2);
- INSERT_ARRAY(PackedVector3Array, Vector3);
+ INSERT_ARRAY(PackedColorArray, godot_packed_color_array, Color);
+ INSERT_ARRAY(PackedVector2Array, godot_packed_vector2_array, Vector2);
+ INSERT_ARRAY(PackedVector3Array, godot_packed_vector3_array, Vector3);
#undef INSERT_ARRAY
@@ -3628,15 +3488,23 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.type_parameter_count = 1;
- itype.c_out = "\treturn memnew(Array(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
- itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in = "ref %0.NativeValue";
+ itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_array_new_copy(%1);\n";
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_array";
+ itype.c_type_in = "ref " + 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;
+ builtin_types.insert(itype.cname, itype);
+
+ // Array_@generic
+ // Re-use Array's itype
+ itype.name = "Array_@generic";
+ itype.cname = itype.name;
+ itype.cs_out = "%5return new %2(%0(%1));";
builtin_types.insert(itype.cname, itype);
// Dictionary
@@ -3645,15 +3513,23 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.type_parameter_count = 2;
- itype.c_out = "\treturn memnew(Dictionary(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
- itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in = "ref %0.NativeValue";
+ itype.c_in = "%5using %0 %1_in = " C_CLASS_NATIVE_FUNCS ".godotsharp_dictionary_new_copy(%1);\n";
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_dictionary";
+ itype.c_type_in = "ref " + 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;
+ builtin_types.insert(itype.cname, itype);
+
+ // Dictionary_@generic
+ // Re-use Dictionary's itype
+ itype.name = "Dictionary_@generic";
+ itype.cname = itype.name;
+ itype.cs_out = "%5return new %2(%0(%1));";
builtin_types.insert(itype.cname, itype);
// void (fictitious type to represent the return type of methods that do not return anything)
@@ -3661,12 +3537,10 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "void";
itype.cname = itype.name;
itype.proxy_name = itype.name;
- itype.c_type = itype.name;
+ itype.cs_type = itype.proxy_name;
+ itype.c_type = itype.proxy_name;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.c_type;
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
}
@@ -3791,21 +3665,18 @@ void BindingsGenerator::_initialize() {
// Generate internal calls (after populating type interfaces and global constants)
- core_custom_icalls.clear();
- editor_custom_icalls.clear();
-
for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
- _generate_method_icalls(E.value);
+ const TypeInterface &itype = E.value;
+ Error err = _populate_method_icalls_table(itype);
+ ERR_FAIL_COND_MSG(err != OK, "Failed to generate icalls table for type: " + itype.name);
}
initialized = true;
}
static String generate_all_glue_option = "--generate-mono-glue";
-static String generate_cs_glue_option = "--generate-mono-cs-glue";
-static String generate_cpp_glue_option = "--generate-mono-cpp-glue";
-static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, String cpp_dir_path) {
+static void handle_cmdline_options(String glue_dir_path) {
BindingsGenerator bindings_generator;
bindings_generator.set_log_print_enabled(true);
@@ -3814,43 +3685,25 @@ static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, Str
return;
}
- if (glue_dir_path.length()) {
- if (bindings_generator.generate_glue(glue_dir_path) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
- }
-
- if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
- }
- }
+ CRASH_COND(glue_dir_path.is_empty());
- if (cs_dir_path.length()) {
- if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
- ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
- }
+ if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
}
+}
- if (cpp_dir_path.length()) {
- if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
- ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
- }
- }
+static void cleanup_and_exit_godot() {
+ // Exit once done
+ Main::cleanup(true);
+ ::exit(0);
}
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
- const int NUM_OPTIONS = 2;
-
String glue_dir_path;
- String cs_dir_path;
- String cpp_dir_path;
-
- int options_left = NUM_OPTIONS;
-
- bool exit_godot = false;
const List<String>::Element *elem = p_cmdline_args.front();
- while (elem && options_left) {
+ while (elem) {
if (elem->get() == generate_all_glue_option) {
const List<String>::Element *path_elem = elem->next();
@@ -3859,48 +3712,20 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue').");
- exit_godot = true;
- }
-
- --options_left;
- } else if (elem->get() == generate_cs_glue_option) {
- const List<String>::Element *path_elem = elem->next();
-
- if (path_elem) {
- cs_dir_path = path_elem->get();
- elem = elem->next();
- } else {
- ERR_PRINT(generate_cs_glue_option + ": No output directory specified.");
- exit_godot = true;
+ // Exit once done with invalid command line arguments
+ cleanup_and_exit_godot();
}
- --options_left;
- } else if (elem->get() == generate_cpp_glue_option) {
- const List<String>::Element *path_elem = elem->next();
-
- if (path_elem) {
- cpp_dir_path = path_elem->get();
- elem = elem->next();
- } else {
- ERR_PRINT(generate_cpp_glue_option + ": No output directory specified.");
- exit_godot = true;
- }
-
- --options_left;
+ break;
}
elem = elem->next();
}
- if (glue_dir_path.length() || cs_dir_path.length() || cpp_dir_path.length()) {
- handle_cmdline_options(glue_dir_path, cs_dir_path, cpp_dir_path);
- exit_godot = true;
- }
-
- if (exit_godot) {
+ if (glue_dir_path.length()) {
+ handle_cmdline_options(glue_dir_path);
// Exit once done
- Main::cleanup(true);
- ::exit(0);
+ cleanup_and_exit_godot();
}
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index ee170e4558..1e1e8be178 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -229,6 +229,23 @@ class BindingsGenerator {
bool is_ref_counted = false;
/**
+ * Determines whether the native return value of this type must be disposed
+ * by the generated internal call (think of `godot_string`, whose destructor
+ * must be called). Some structs that are disposable may still disable this
+ * flag if the ownership is transferred.
+ */
+ bool c_type_is_disposable_struct = false;
+
+ /**
+ * Determines whether the native return value of this type must be zero initialized
+ * before its address is passed to ptrcall. This is required for types whose destructor
+ * is called before being assigned the return value by `PtrToArg::encode`, e.g.:
+ * Array, Dictionary, String, StringName.
+ * It's not necessary to set this to `true` if [c_type_is_disposable_struct] is already `true`.
+ */
+ bool c_ret_needs_default_initialization = false;
+
+ /**
* Used only by Object-derived types.
* Determines if this type is not abstract (incomplete).
* e.g.: CanvasItem cannot be instantiated.
@@ -242,33 +259,36 @@ class BindingsGenerator {
*/
bool memory_own = false;
- /**
- * This must be set to true for any struct bigger than 32-bits. Those cannot be passed/returned by value
- * with internal calls, so we must use pointers instead. Returns must be replace with out parameters.
- * In this case, [c_out] and [cs_out] must have a different format, explained below.
- * The Mono IL interpreter icall trampolines don't support passing structs bigger than 32-bits by value (at least not on WASM).
- */
- bool ret_as_byref_arg = false;
-
// !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name]
// !! When renaming those fields, make sure to rename their references in the comments
// --- C INTERFACE ---
- static const char *DEFAULT_VARARG_C_IN;
-
/**
* One or more statements that manipulate 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].
- * For variadic methods, this field is required and, if empty, [DEFAULT_VARARG_C_IN] is used instead.
* Formatting elements:
* %0: [c_type] of the parameter
* %1: name of the parameter
+ * %2-4: reserved
+ * %5: indentation text
*/
String c_in;
/**
+ * One or more statements that manipulate 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:
+ * %0: [c_type] of the parameter
+ * %1: name of the parameter
+ * %2-4: reserved
+ * %5: indentation text
+ */
+ String c_in_vararg;
+
+ /**
* Determines the expression that will be passed as argument to ptrcall.
* By default the value equals the name of the parameter,
* this varies for types that require special manipulation via [c_in].
@@ -291,7 +311,8 @@ class BindingsGenerator {
* %0: [c_type_out] of the return type
* %1: name of the variable to be returned
* %2: [name] of the return type
- * %3: name of the parameter that must be assigned the return value
+ * %3-4: reserved
+ * %5: indentation text
*/
String c_out;
@@ -330,6 +351,7 @@ class BindingsGenerator {
* %0 or %s: name of the parameter
*/
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.
@@ -338,7 +360,9 @@ class BindingsGenerator {
* %0: internal method name
* %1: internal method call arguments without surrounding parenthesis
* %2: [cs_type] of the return type
- * %3: [im_type_out] of the return type
+ * %3: [c_type_out] of the return type
+ * %4: reserved
+ * %5: indentation text
*/
String cs_out;
@@ -348,16 +372,6 @@ class BindingsGenerator {
*/
String cs_type;
- /**
- * Type used for parameters of internal call methods.
- */
- String im_type_in;
-
- /**
- * Type used for the return type of internal call methods.
- */
- String im_type_out;
-
const DocData::ClassDoc *class_doc = nullptr;
List<ConstantInterface> constants;
@@ -432,8 +446,8 @@ class BindingsGenerator {
itype.c_type = itype.name;
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_in = itype.proxy_name + "*";
+ itype.c_type_out = itype.proxy_name;
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
}
@@ -467,65 +481,27 @@ class BindingsGenerator {
return itype;
}
- static void create_placeholder_type(TypeInterface &r_itype, const StringName &p_cname) {
- r_itype.name = p_cname;
- r_itype.cname = p_cname;
- r_itype.proxy_name = r_itype.name;
-
- r_itype.c_type = r_itype.name;
- r_itype.c_type_in = "MonoObject*";
- r_itype.c_type_out = "MonoObject*";
- r_itype.cs_type = r_itype.proxy_name;
- r_itype.im_type_in = r_itype.proxy_name;
- r_itype.im_type_out = r_itype.proxy_name;
- }
-
- static void postsetup_enum_type(TypeInterface &r_enum_itype) {
- // C interface for enums is the same as that of 'uint32_t'. Remember to apply
- // any of the changes done here to the 'uint32_t' type interface as well.
-
- r_enum_itype.c_arg_in = "&%s_in";
- {
- // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
- r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- r_enum_itype.c_out = "\treturn (%0)%1;\n";
- r_enum_itype.c_type = "int64_t";
- }
- r_enum_itype.c_type_in = "int32_t";
- r_enum_itype.c_type_out = r_enum_itype.c_type_in;
-
- r_enum_itype.cs_type = r_enum_itype.proxy_name;
- r_enum_itype.cs_in = "(int)%s";
- r_enum_itype.cs_out = "return (%2)%0(%1);";
- r_enum_itype.im_type_in = "int";
- r_enum_itype.im_type_out = "int";
- r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name];
- }
+ static void postsetup_enum_type(TypeInterface &r_enum_itype);
TypeInterface() {}
};
struct InternalCall {
String name;
- String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq]
- String im_sig; // Signature for the C# method declaration
String unique_sig; // Unique signature to avoid duplicates in containers
bool editor_only = false;
- InternalCall() {}
+ bool is_vararg = false;
+ bool is_static = false;
+ TypeReference return_type;
+ List<TypeReference> argument_types;
- InternalCall(const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
- name = p_name;
- im_type_out = p_im_type_out;
- im_sig = p_im_sig;
- unique_sig = p_unique_sig;
- editor_only = false;
- }
+ _FORCE_INLINE_ int get_arguments_count() const { return argument_types.size(); }
+
+ InternalCall() {}
- InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
+ InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_unique_sig = String()) {
name = p_name;
- im_type_out = p_im_type_out;
- im_sig = p_im_sig;
unique_sig = p_unique_sig;
editor_only = api_type == ClassDB::API_EDITOR;
}
@@ -540,7 +516,6 @@ class BindingsGenerator {
HashMap<StringName, TypeInterface> obj_types;
- HashMap<StringName, TypeInterface> placeholder_types;
HashMap<StringName, TypeInterface> builtin_types;
HashMap<StringName, TypeInterface> enum_types;
@@ -548,13 +523,9 @@ class BindingsGenerator {
List<ConstantInterface> global_constants;
List<InternalCall> method_icalls;
+ /// Stores the unique internal calls from [method_icalls] that are assigned to each method.
HashMap<const MethodInterface *, const InternalCall *> method_icalls_map;
- List<const InternalCall *> generated_icall_funcs;
-
- List<InternalCall> core_custom_icalls;
- List<InternalCall> editor_custom_icalls;
-
HashMap<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
@@ -571,6 +542,8 @@ class BindingsGenerator {
StringName type_String = StaticCString::create("String");
StringName type_StringName = StaticCString::create("StringName");
StringName type_NodePath = StaticCString::create("NodePath");
+ StringName type_Array_generic = StaticCString::create("Array_@generic");
+ StringName type_Dictionary_generic = StaticCString::create("Dictionary_@generic");
StringName type_at_GlobalScope = StaticCString::create("@GlobalScope");
StringName enum_Error = StaticCString::create("Error");
@@ -595,12 +568,14 @@ class BindingsGenerator {
StringName type_Vector4i = StaticCString::create("Vector4i");
// Object not included as it must be checked for all derived classes
- static constexpr int nullable_types_count = 17;
+ static constexpr int nullable_types_count = 18;
StringName nullable_types[nullable_types_count] = {
type_String,
type_StringName,
type_NodePath,
+ type_Array_generic,
+ type_Dictionary_generic,
StaticCString::create(_STR(Array)),
StaticCString::create(_STR(Dictionary)),
StaticCString::create(_STR(Callable)),
@@ -636,17 +611,6 @@ class BindingsGenerator {
NameCache name_cache;
- const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
- const List<InternalCall>::Element *it = p_list.front();
- while (it) {
- if (it->get().name == p_name) {
- return it;
- }
- it = it->next();
- }
- return nullptr;
- }
-
const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const {
for (const ConstantInterface &E : p_constants) {
if (E.name == p_name) {
@@ -657,18 +621,38 @@ class BindingsGenerator {
return nullptr;
}
- inline String get_unique_sig(const TypeInterface &p_type) {
- if (p_type.is_ref_counted) {
- return "Ref";
- } else if (p_type.is_object_type) {
+ inline String get_arg_unique_sig(const TypeInterface &p_type) {
+ // For parameters, we treat reference and non-reference derived types the same.
+ if (p_type.is_object_type) {
return "Obj";
} else if (p_type.is_enum) {
return "int";
+ } else if (p_type.cname == name_cache.type_Array_generic) {
+ return "Array";
+ } else if (p_type.cname == name_cache.type_Dictionary_generic) {
+ return "Dictionary";
}
return p_type.name;
}
+ inline String get_ret_unique_sig(const TypeInterface *p_type) {
+ // Reference derived return types are treated differently.
+ if (p_type->is_ref_counted) {
+ return "Ref";
+ } else if (p_type->is_object_type) {
+ return "Obj";
+ } else if (p_type->is_enum) {
+ return "int";
+ } else if (p_type->cname == name_cache.type_Array_generic) {
+ return "Array";
+ } else if (p_type->cname == name_cache.type_Dictionary_generic) {
+ return "Dictionary";
+ }
+
+ return p_type->name;
+ }
+
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
@@ -682,10 +666,9 @@ class BindingsGenerator {
int _determine_enum_prefix(const EnumInterface &p_ienum);
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
- void _generate_method_icalls(const TypeInterface &p_itype);
+ Error _populate_method_icalls_table(const TypeInterface &p_itype);
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
- const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters);
@@ -706,11 +689,11 @@ class BindingsGenerator {
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);
+ Error _generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output);
+
void _generate_array_extensions(StringBuilder &p_output);
void _generate_global_constants(StringBuilder &p_output);
- Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output);
-
Error _save_file(const String &p_path, const StringBuilder &p_content);
void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
@@ -721,15 +704,12 @@ public:
Error generate_cs_core_project(const String &p_proj_dir);
Error generate_cs_editor_project(const String &p_proj_dir);
Error generate_cs_api(const String &p_output_dir);
- Error generate_glue(const String &p_output_dir);
_FORCE_INLINE_ bool is_log_print_enabled() { return log_print_enabled; }
_FORCE_INLINE_ void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
_FORCE_INLINE_ bool is_initialized() { return initialized; }
- static uint32_t get_version();
-
static void handle_cmdline_args(const List<String> &p_cmdline_args);
BindingsGenerator() {
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index f830c7ffe1..102d27378f 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -46,7 +46,6 @@
#include "main/main.h"
#include "../csharp_script.h"
-#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/macos_utils.h"
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
new file mode 100644
index 0000000000..3103fa78c7
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
@@ -0,0 +1,7 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=gdnative/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=godotsharp/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=icall/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=quat/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=vcall/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index a412047196..c32895baab 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -1,47 +1,28 @@
using System;
using System.Collections.Generic;
using System.Collections;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot.Collections
{
- internal class ArraySafeHandle : SafeHandle
- {
- public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
- {
- this.handle = handle;
- }
-
- public override bool IsInvalid
- {
- get { return handle == IntPtr.Zero; }
- }
-
- protected override bool ReleaseHandle()
- {
- Array.godot_icall_Array_Dtor(handle);
- return true;
- }
- }
-
/// <summary>
/// Wrapper around Godot's Array class, an array of Variant
/// typed elements allocated in the engine in C++. Useful when
/// interfacing with the engine. Otherwise prefer .NET collections
/// such as <see cref="System.Array"/> or <see cref="List{T}"/>.
/// </summary>
- public class Array : IList, IDisposable
+ public sealed class Array : IList, IDisposable
{
- private ArraySafeHandle _safeHandle;
- private bool _disposed = false;
+ internal godot_array NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Array"/>.
/// </summary>
public Array()
{
- _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
+ godot_icall_Array_Ctor(out NativeValue);
}
/// <summary>
@@ -58,6 +39,7 @@ namespace Godot.Collections
Add(element);
}
+ // TODO: This must be removed. Lots of silent mistakes as it takes pretty much anything.
/// <summary>
/// Constructs a new <see cref="Array"/> from the given objects.
/// </summary>
@@ -69,25 +51,37 @@ namespace Godot.Collections
{
throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
}
- _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array));
+
+ godot_icall_Array_Ctor_MonoArray(array, out NativeValue);
}
- internal Array(ArraySafeHandle handle)
+ private Array(godot_array nativeValueToOwn)
{
- _safeHandle = handle;
+ NativeValue = nativeValueToOwn;
}
- internal Array(IntPtr handle)
+ // Explicit name to make it very clear
+ internal static Array CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn)
+ => new Array(nativeValueToOwn);
+
+ ~Array()
{
- _safeHandle = new ArraySafeHandle(handle);
+ Dispose(false);
}
- internal IntPtr GetPtr()
+ /// <summary>
+ /// Disposes of this <see cref="Array"/>.
+ /// </summary>
+ public void Dispose()
{
- if (_disposed)
- throw new ObjectDisposedException(GetType().FullName);
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
- return _safeHandle.DangerousGetHandle();
+ public void Dispose(bool disposing)
+ {
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.Dispose();
}
/// <summary>
@@ -97,7 +91,9 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array Duplicate(bool deep = false)
{
- return new Array(godot_icall_Array_Duplicate(GetPtr(), deep));
+ godot_array newArray;
+ godot_icall_Array_Duplicate(ref NativeValue, deep, out newArray);
+ return CreateTakingOwnershipOfDisposableValue(newArray);
}
/// <summary>
@@ -107,7 +103,7 @@ namespace Godot.Collections
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
{
- return godot_icall_Array_Resize(GetPtr(), newSize);
+ return godot_icall_Array_Resize(ref NativeValue, newSize);
}
/// <summary>
@@ -115,7 +111,7 @@ namespace Godot.Collections
/// </summary>
public void Shuffle()
{
- godot_icall_Array_Shuffle(GetPtr());
+ godot_icall_Array_Shuffle(ref NativeValue);
}
/// <summary>
@@ -126,26 +122,9 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array operator +(Array left, Array right)
{
- return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr()));
- }
-
- // IDisposable
-
- /// <summary>
- /// Disposes of this <see cref="Array"/>.
- /// </summary>
- public void Dispose()
- {
- if (_disposed)
- return;
-
- if (_safeHandle != null)
- {
- _safeHandle.Dispose();
- _safeHandle = null;
- }
-
- _disposed = true;
+ godot_array newArray;
+ godot_icall_Array_Concatenate(ref left.NativeValue, ref right.NativeValue, out newArray);
+ return CreateTakingOwnershipOfDisposableValue(newArray);
}
// IList
@@ -160,8 +139,16 @@ namespace Godot.Collections
/// <value>The object at the given <paramref name="index"/>.</value>
public object this[int index]
{
- get => godot_icall_Array_At(GetPtr(), index);
- set => godot_icall_Array_SetAt(GetPtr(), index, value);
+ get
+ {
+ godot_icall_Array_At(ref NativeValue, index, out godot_variant elem);
+ unsafe
+ {
+ using (elem)
+ return Marshaling.variant_to_mono_object(&elem);
+ }
+ }
+ set => godot_icall_Array_SetAt(ref NativeValue, index, value);
}
/// <summary>
@@ -170,19 +157,19 @@ namespace Godot.Collections
/// </summary>
/// <param name="value">The object to add.</param>
/// <returns>The new size after adding the object.</returns>
- public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
+ public int Add(object value) => godot_icall_Array_Add(ref NativeValue, value);
/// <summary>
/// Checks if this <see cref="Array"/> contains the given object.
/// </summary>
/// <param name="value">The item to look for.</param>
/// <returns>Whether or not this array contains the given object.</returns>
- public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
+ public bool Contains(object value) => godot_icall_Array_Contains(ref NativeValue, value);
/// <summary>
/// Erases all items from this <see cref="Array"/>.
/// </summary>
- public void Clear() => godot_icall_Array_Clear(GetPtr());
+ public void Clear() => godot_icall_Array_Clear(ref NativeValue);
/// <summary>
/// Searches this <see cref="Array"/> for an object
@@ -190,7 +177,7 @@ namespace Godot.Collections
/// </summary>
/// <param name="value">The object to search for.</param>
/// <returns>The index of the object, or -1 if not found.</returns>
- public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
+ public int IndexOf(object value) => godot_icall_Array_IndexOf(ref NativeValue, value);
/// <summary>
/// Inserts a new object at a given position in the array.
@@ -200,20 +187,20 @@ namespace Godot.Collections
/// </summary>
/// <param name="index">The index to insert at.</param>
/// <param name="value">The object to insert.</param>
- public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
+ public void Insert(int index, object value) => godot_icall_Array_Insert(ref NativeValue, index, value);
/// <summary>
/// Removes the first occurrence of the specified <paramref name="value"/>
/// from this <see cref="Array"/>.
/// </summary>
/// <param name="value">The value to remove.</param>
- public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
+ public void Remove(object value) => godot_icall_Array_Remove(ref NativeValue, value);
/// <summary>
/// Removes an element from this <see cref="Array"/> by index.
/// </summary>
/// <param name="index">The index of the element to remove.</param>
- public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
+ public void RemoveAt(int index) => godot_icall_Array_RemoveAt(ref NativeValue, index);
// ICollection
@@ -222,7 +209,7 @@ namespace Godot.Collections
/// This is also known as the size or length of the array.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count => godot_icall_Array_Count(GetPtr());
+ public int Count => godot_icall_Array_Count(ref NativeValue);
object ICollection.SyncRoot => this;
@@ -243,7 +230,7 @@ namespace Godot.Collections
throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
// Internal call may throw ArgumentException
- godot_icall_Array_CopyTo(GetPtr(), array, index);
+ godot_icall_Array_CopyTo(ref NativeValue, array, index);
}
// IEnumerable
@@ -268,73 +255,71 @@ namespace Godot.Collections
/// <returns>A string representation of this array.</returns>
public override string ToString()
{
- return godot_icall_Array_ToString(GetPtr());
+ return godot_icall_Array_ToString(ref NativeValue);
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Ctor();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Dtor(IntPtr ptr);
+ internal static extern void godot_icall_Array_Ctor(out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Array_At(IntPtr ptr, int index);
+ internal static extern void godot_icall_Array_Ctor_MonoArray(System.Array array, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
+ internal static extern void godot_icall_Array_At(ref godot_array ptr, int index, out godot_variant elem);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
+ internal static extern void godot_icall_Array_SetAt(ref godot_array ptr, int index, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_Count(IntPtr ptr);
+ internal static extern int godot_icall_Array_Count(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_Add(IntPtr ptr, object item);
+ internal static extern int godot_icall_Array_Add(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Clear(IntPtr ptr);
+ internal static extern void godot_icall_Array_Clear(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right);
+ internal static extern void godot_icall_Array_Concatenate(ref godot_array left, ref godot_array right, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Array_Contains(IntPtr ptr, object item);
+ internal static extern bool godot_icall_Array_Contains(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
+ internal static extern void godot_icall_Array_CopyTo(ref godot_array ptr, System.Array array, int arrayIndex);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep);
+ internal static extern void godot_icall_Array_Duplicate(ref godot_array ptr, bool deep, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_IndexOf(IntPtr ptr, object item);
+ internal static extern int godot_icall_Array_IndexOf(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
+ internal static extern void godot_icall_Array_Insert(ref godot_array ptr, int index, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Array_Remove(IntPtr ptr, object item);
+ internal static extern bool godot_icall_Array_Remove(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
+ internal static extern void godot_icall_Array_RemoveAt(ref godot_array ptr, int index);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
+ internal static extern Error godot_icall_Array_Resize(ref godot_array ptr, int newSize);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_Array_Shuffle(IntPtr ptr);
+ internal static extern Error godot_icall_Array_Shuffle(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
+ internal static extern string godot_icall_Array_ToString(ref godot_array ptr);
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_Array_ToString(IntPtr ptr);
+ internal interface IGenericGodotArray
+ {
+ Array UnderlyingArray { get; }
+ Type TypeOfElements { get; }
}
+ // TODO: Now we should be able to avoid boxing
/// <summary>
/// Typed wrapper around Godot's Array class, an array of Variant
/// typed elements allocated in the engine in C++. Useful when
@@ -342,24 +327,29 @@ namespace Godot.Collections
/// such as arrays or <see cref="List{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
- public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
+ [SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
+ public sealed class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>, IGenericGodotArray
{
- private Array _objectArray;
+ private readonly Array _underlyingArray;
- internal static int elemTypeEncoding;
- internal static IntPtr elemTypeClass;
+ internal ref godot_array NativeValue => ref _underlyingArray.NativeValue;
- static Array()
- {
- Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
- }
+ // ReSharper disable StaticMemberInGenericType
+ // Warning is about unique static fields being created for each generic type combination:
+ // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
+ // In our case this is exactly what we want.
+ private static readonly Type TypeOfElements = typeof(T);
+ // ReSharper restore StaticMemberInGenericType
+
+ Array IGenericGodotArray.UnderlyingArray => _underlyingArray;
+ Type IGenericGodotArray.TypeOfElements => TypeOfElements;
/// <summary>
/// Constructs a new empty <see cref="Array{T}"/>.
/// </summary>
public Array()
{
- _objectArray = new Array();
+ _underlyingArray = new Array();
}
/// <summary>
@@ -372,7 +362,7 @@ namespace Godot.Collections
if (collection == null)
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
- _objectArray = new Array(collection);
+ _underlyingArray = new Array(collection);
}
/// <summary>
@@ -386,7 +376,8 @@ namespace Godot.Collections
{
throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
}
- _objectArray = new Array(array);
+
+ _underlyingArray = new Array(array);
}
/// <summary>
@@ -395,23 +386,12 @@ namespace Godot.Collections
/// <param name="array">The untyped array to construct from.</param>
public Array(Array array)
{
- _objectArray = array;
- }
-
- internal Array(IntPtr handle)
- {
- _objectArray = new Array(handle);
- }
-
- internal Array(ArraySafeHandle handle)
- {
- _objectArray = new Array(handle);
+ _underlyingArray = array;
}
- internal IntPtr GetPtr()
- {
- return _objectArray.GetPtr();
- }
+ // Explicit name to make it very clear
+ internal static Array<T> CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn)
+ => new Array<T>(Array.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn));
/// <summary>
/// Converts this typed <see cref="Array{T}"/> to an untyped <see cref="Array"/>.
@@ -419,7 +399,7 @@ namespace Godot.Collections
/// <param name="from">The typed array to convert.</param>
public static explicit operator Array(Array<T> from)
{
- return from._objectArray;
+ return from._underlyingArray;
}
/// <summary>
@@ -429,7 +409,7 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array<T> Duplicate(bool deep = false)
{
- return new Array<T>(_objectArray.Duplicate(deep));
+ return new Array<T>(_underlyingArray.Duplicate(deep));
}
/// <summary>
@@ -439,7 +419,7 @@ namespace Godot.Collections
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
{
- return _objectArray.Resize(newSize);
+ return _underlyingArray.Resize(newSize);
}
/// <summary>
@@ -447,7 +427,7 @@ namespace Godot.Collections
/// </summary>
public void Shuffle()
{
- _objectArray.Shuffle();
+ _underlyingArray.Shuffle();
}
/// <summary>
@@ -458,7 +438,7 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array<T> operator +(Array<T> left, Array<T> right)
{
- return new Array<T>(left._objectArray + right._objectArray);
+ return new Array<T>(left._underlyingArray + right._underlyingArray);
}
// IList<T>
@@ -469,8 +449,16 @@ namespace Godot.Collections
/// <value>The value at the given <paramref name="index"/>.</value>
public T this[int index]
{
- get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); }
- set { _objectArray[index] = value; }
+ get
+ {
+ Array.godot_icall_Array_At(ref _underlyingArray.NativeValue, index, out godot_variant elem);
+ unsafe
+ {
+ using (elem)
+ return (T)Marshaling.variant_to_mono_object_of_type(&elem, TypeOfElements);
+ }
+ }
+ set => _underlyingArray[index] = value;
}
/// <summary>
@@ -481,7 +469,7 @@ namespace Godot.Collections
/// <returns>The index of the item, or -1 if not found.</returns>
public int IndexOf(T item)
{
- return _objectArray.IndexOf(item);
+ return _underlyingArray.IndexOf(item);
}
/// <summary>
@@ -494,7 +482,7 @@ namespace Godot.Collections
/// <param name="item">The item to insert.</param>
public void Insert(int index, T item)
{
- _objectArray.Insert(index, item);
+ _underlyingArray.Insert(index, item);
}
/// <summary>
@@ -503,7 +491,7 @@ namespace Godot.Collections
/// <param name="index">The index of the element to remove.</param>
public void RemoveAt(int index)
{
- _objectArray.RemoveAt(index);
+ _underlyingArray.RemoveAt(index);
}
// ICollection<T>
@@ -513,10 +501,7 @@ namespace Godot.Collections
/// This is also known as the size or length of the array.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count
- {
- get { return _objectArray.Count; }
- }
+ public int Count => _underlyingArray.Count;
bool ICollection<T>.IsReadOnly => false;
@@ -528,7 +513,7 @@ namespace Godot.Collections
/// <returns>The new size after adding the item.</returns>
public void Add(T item)
{
- _objectArray.Add(item);
+ _underlyingArray.Add(item);
}
/// <summary>
@@ -536,7 +521,7 @@ namespace Godot.Collections
/// </summary>
public void Clear()
{
- _objectArray.Clear();
+ _underlyingArray.Clear();
}
/// <summary>
@@ -546,7 +531,7 @@ namespace Godot.Collections
/// <returns>Whether or not this array contains the given item.</returns>
public bool Contains(T item)
{
- return _objectArray.Contains(item);
+ return _underlyingArray.Contains(item);
}
/// <summary>
@@ -563,17 +548,14 @@ namespace Godot.Collections
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
- // TODO This may be quite slow because every element access is an internal call.
- // It could be moved entirely to an internal call if we find out how to do the cast there.
-
- int count = _objectArray.Count;
+ int count = _underlyingArray.Count;
if (array.Length < (arrayIndex + count))
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
for (int i = 0; i < count; i++)
{
- array[arrayIndex] = (T)this[i];
+ array[arrayIndex] = this[i];
arrayIndex++;
}
}
@@ -586,7 +568,7 @@ namespace Godot.Collections
/// <returns>A <see langword="bool"/> indicating success or failure.</returns>
public bool Remove(T item)
{
- return Array.godot_icall_Array_Remove(GetPtr(), item);
+ return Array.godot_icall_Array_Remove(ref _underlyingArray.NativeValue, item);
}
// IEnumerable<T>
@@ -597,23 +579,20 @@ namespace Godot.Collections
/// <returns>An enumerator.</returns>
public IEnumerator<T> GetEnumerator()
{
- int count = _objectArray.Count;
+ int count = _underlyingArray.Count;
for (int i = 0; i < count; i++)
{
- yield return (T)this[i];
+ yield return this[i];
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Converts this <see cref="Array{T}"/> to a string.
/// </summary>
/// <returns>A string representation of this array.</returns>
- public override string ToString() => _objectArray.ToString();
+ public override string ToString() => _underlyingArray.ToString();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 1dca9e6ea7..187d910f9f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -4,11 +4,53 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
internal static class DelegateUtils
{
+ // TODO: Move somewhere else once we need to for things other than delegates
+ internal static void FreeGCHandle(IntPtr delegateGCHandle)
+ => GCHandle.FromIntPtr(delegateGCHandle).Free();
+
+ internal static bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
+ {
+ var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
+ var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target;
+ return @delegateA == @delegateB;
+ }
+
+ internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc, godot_variant* ret)
+ {
+ // TODO: Optimize
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
+ var managedArgs = new object[argc];
+
+ var parameterInfos = @delegate.Method.GetParameters();
+
+ var paramsLength = parameterInfos.Length;
+
+ if (argc != paramsLength)
+ {
+ throw new InvalidOperationException(
+ $"The delegate expects {paramsLength} arguments, but received {argc}.");
+ }
+
+ for (uint i = 0; i < argc; i++)
+ {
+ managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
+ args[i], parameterInfos[i].ParameterType);
+ }
+
+ object invokeRet = @delegate.DynamicInvoke(managedArgs);
+
+ *ret = Marshaling.mono_object_to_variant(invokeRet);
+ }
+
+ // TODO: Check if we should be using BindingFlags.DeclaredOnly (would give better reflection performance).
+
private enum TargetKind : uint
{
Static,
@@ -16,7 +58,10 @@ namespace Godot
CompilerGenerated
}
- internal static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData)
+ internal static bool TrySerializeDelegateWithGCHandle(IntPtr delegateGCHandle, Collections.Array serializedData)
+ => TrySerializeDelegate((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target, serializedData);
+
+ private static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData)
{
if (@delegate is MulticastDelegate multicastDelegate)
{
@@ -72,12 +117,14 @@ namespace Godot
return true;
}
}
+ // ReSharper disable once RedundantNameQualifier
case Godot.Object godotObject:
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
writer.Write((ulong)TargetKind.GodotObject);
+ // ReSharper disable once RedundantCast
writer.Write((ulong)godotObject.GetInstanceId());
SerializeType(writer, @delegate.GetType());
@@ -93,7 +140,7 @@ namespace Godot
{
Type targetType = target.GetType();
- if (targetType.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) != null)
+ if (targetType.IsDefined(typeof(CompilerGeneratedAttribute), true))
{
// Compiler generated. Probably a closure. Try to serialize it.
@@ -213,6 +260,13 @@ namespace Godot
}
}
+ private static bool TryDeserializeDelegateWithGCHandle(Collections.Array serializedData, out IntPtr delegateGCHandle)
+ {
+ bool res = TryDeserializeDelegate(serializedData, out Delegate @delegate);
+ delegateGCHandle = GCHandle.ToIntPtr(GCHandle.Alloc(@delegate));
+ return res;
+ }
+
private static bool TryDeserializeDelegate(Collections.Array serializedData, out Delegate @delegate)
{
if (serializedData.Count == 1)
@@ -276,6 +330,7 @@ namespace Godot
case TargetKind.GodotObject:
{
ulong objectId = reader.ReadUInt64();
+ // ReSharper disable once RedundantNameQualifier
Godot.Object godotObject = GD.InstanceFromId(objectId);
if (godotObject == null)
return false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index e80b6af68f..d0c7e4523b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -2,46 +2,28 @@ using System;
using System.Collections.Generic;
using System.Collections;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using Godot.NativeInterop;
using System.Diagnostics.CodeAnalysis;
namespace Godot.Collections
{
- internal class DictionarySafeHandle : SafeHandle
- {
- public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
- {
- this.handle = handle;
- }
-
- public override bool IsInvalid
- {
- get { return handle == IntPtr.Zero; }
- }
-
- protected override bool ReleaseHandle()
- {
- Dictionary.godot_icall_Dictionary_Dtor(handle);
- return true;
- }
- }
-
/// <summary>
/// Wrapper around Godot's Dictionary class, a dictionary of Variant
/// typed elements allocated in the engine in C++. Useful when
/// interfacing with the engine.
/// </summary>
- public class Dictionary : IDictionary, IDisposable
+ public sealed class Dictionary :
+ IDictionary,
+ IDisposable
{
- private DictionarySafeHandle _safeHandle;
- private bool _disposed = false;
+ internal godot_dictionary NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Dictionary"/>.
/// </summary>
public Dictionary()
{
- _safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
+ godot_icall_Dictionary_Ctor(out NativeValue);
}
/// <summary>
@@ -58,22 +40,18 @@ namespace Godot.Collections
Add(entry.Key, entry.Value);
}
- internal Dictionary(DictionarySafeHandle handle)
+ private Dictionary(godot_dictionary nativeValueToOwn)
{
- _safeHandle = handle;
+ NativeValue = nativeValueToOwn;
}
- internal Dictionary(IntPtr handle)
- {
- _safeHandle = new DictionarySafeHandle(handle);
- }
+ // Explicit name to make it very clear
+ internal static Dictionary CreateTakingOwnershipOfDisposableValue(godot_dictionary nativeValueToOwn)
+ => new Dictionary(nativeValueToOwn);
- internal IntPtr GetPtr()
+ ~Dictionary()
{
- if (_disposed)
- throw new ObjectDisposedException(GetType().FullName);
-
- return _safeHandle.DangerousGetHandle();
+ Dispose(false);
}
/// <summary>
@@ -81,16 +59,14 @@ namespace Godot.Collections
/// </summary>
public void Dispose()
{
- if (_disposed)
- return;
-
- if (_safeHandle != null)
- {
- _safeHandle.Dispose();
- _safeHandle = null;
- }
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
- _disposed = true;
+ public void Dispose(bool disposing)
+ {
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.Dispose();
}
/// <summary>
@@ -100,7 +76,9 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary Duplicate(bool deep = false)
{
- return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep));
+ godot_dictionary newDictionary;
+ godot_icall_Dictionary_Duplicate(ref NativeValue, deep, out newDictionary);
+ return CreateTakingOwnershipOfDisposableValue(newDictionary);
}
// IDictionary
@@ -112,8 +90,9 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
- return new Array(new ArraySafeHandle(handle));
+ godot_array keysArray;
+ godot_icall_Dictionary_Keys(ref NativeValue, out keysArray);
+ return Array.CreateTakingOwnershipOfDisposableValue(keysArray);
}
}
@@ -124,16 +103,19 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
- return new Array(new ArraySafeHandle(handle));
+ godot_array valuesArray;
+ godot_icall_Dictionary_Values(ref NativeValue, out valuesArray);
+ return Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
private (Array keys, Array values, int count) GetKeyValuePairs()
{
- int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle);
- Array keys = new Array(new ArraySafeHandle(keysHandle));
- Array values = new Array(new ArraySafeHandle(valuesHandle));
+ godot_array keysArray;
+ godot_array valuesArray;
+ int count = godot_icall_Dictionary_KeyValuePairs(ref NativeValue, out keysArray, out valuesArray);
+ var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray);
+ var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
return (keys, values, count);
}
@@ -147,8 +129,16 @@ namespace Godot.Collections
/// <value>The object at the given <paramref name="key"/>.</value>
public object this[object key]
{
- get => godot_icall_Dictionary_GetValue(GetPtr(), key);
- set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
+ get
+ {
+ godot_icall_Dictionary_GetValue(ref NativeValue, key, out godot_variant value);
+ unsafe
+ {
+ using (value)
+ return Marshaling.variant_to_mono_object(&value);
+ }
+ }
+ set => godot_icall_Dictionary_SetValue(ref NativeValue, key, value);
}
/// <summary>
@@ -157,19 +147,19 @@ namespace Godot.Collections
/// </summary>
/// <param name="key">The key at which to add the object.</param>
/// <param name="value">The object to add.</param>
- public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
+ public void Add(object key, object value) => godot_icall_Dictionary_Add(ref NativeValue, key, value);
/// <summary>
/// Erases all items from this <see cref="Dictionary"/>.
/// </summary>
- public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
+ public void Clear() => godot_icall_Dictionary_Clear(ref NativeValue);
/// <summary>
/// Checks if this <see cref="Dictionary"/> contains the given key.
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>Whether or not this dictionary contains the given key.</returns>
- public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+ public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(ref NativeValue, key);
/// <summary>
/// Gets an enumerator for this <see cref="Dictionary"/>.
@@ -181,7 +171,7 @@ namespace Godot.Collections
/// Removes an element from this <see cref="Dictionary"/> by key.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
- public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ public void Remove(object key) => godot_icall_Dictionary_RemoveKey(ref NativeValue, key);
// ICollection
@@ -194,7 +184,7 @@ namespace Godot.Collections
/// This is also known as the size or length of the dictionary.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count => godot_icall_Dictionary_Count(GetPtr());
+ public int Count => godot_icall_Dictionary_Count(ref NativeValue);
/// <summary>
/// Copies the elements of this <see cref="Dictionary"/> to the given
@@ -258,8 +248,17 @@ namespace Godot.Collections
private void UpdateEntry()
{
_dirty = false;
- godot_icall_Dictionary_KeyValuePairAt(_dictionary.GetPtr(), _index, out object key, out object value);
- _entry = new DictionaryEntry(key, value);
+ godot_icall_Dictionary_KeyValuePairAt(ref _dictionary.NativeValue, _index, out var vKey, out var vValue);
+ unsafe
+ {
+ using (vKey)
+ using (vValue)
+ {
+ var key = Marshaling.variant_to_mono_object(&vKey);
+ var value = Marshaling.variant_to_mono_object(&vValue);
+ _entry = new DictionaryEntry(key, value);
+ }
+ }
}
public object Key => Entry.Key;
@@ -286,76 +285,70 @@ namespace Godot.Collections
/// <returns>A string representation of this dictionary.</returns>
public override string ToString()
{
- return godot_icall_Dictionary_ToString(GetPtr());
+ return godot_icall_Dictionary_ToString(ref NativeValue);
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Ctor();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Dtor(IntPtr ptr);
+ internal static extern void godot_icall_Dictionary_Ctor(out godot_dictionary dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
+ internal static extern void godot_icall_Dictionary_GetValue(ref godot_dictionary ptr, object key, out godot_variant value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass);
+ internal static extern void godot_icall_Dictionary_SetValue(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
+ internal static extern void godot_icall_Dictionary_Keys(ref godot_dictionary ptr, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
+ internal static extern void godot_icall_Dictionary_Values(ref godot_dictionary ptr, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
+ internal static extern int godot_icall_Dictionary_KeyValuePairs(ref godot_dictionary ptr, out godot_array keys, out godot_array values);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Dictionary_Count(IntPtr ptr);
+ internal static extern void godot_icall_Dictionary_KeyValuePairAt(ref godot_dictionary ptr, int index, out godot_variant key, out godot_variant value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values);
+ internal static extern void godot_icall_Dictionary_Add(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value);
+ internal static extern int godot_icall_Dictionary_Count(ref godot_dictionary ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass);
+ internal static extern void godot_icall_Dictionary_Clear(ref godot_dictionary ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
+ internal static extern bool godot_icall_Dictionary_Contains(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Clear(IntPtr ptr);
+ internal static extern bool godot_icall_Dictionary_ContainsKey(ref godot_dictionary ptr, object key);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
+ internal static extern void godot_icall_Dictionary_Duplicate(ref godot_dictionary ptr, bool deep, out godot_dictionary dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
+ internal static extern bool godot_icall_Dictionary_RemoveKey(ref godot_dictionary ptr, object key);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep);
+ internal static extern bool godot_icall_Dictionary_Remove(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
+ internal static extern bool godot_icall_Dictionary_TryGetValue(ref godot_dictionary ptr, object key, out godot_variant value);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass);
+ internal static extern string godot_icall_Dictionary_ToString(ref godot_dictionary ptr);
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_Dictionary_ToString(IntPtr ptr);
+ internal interface IGenericGodotDictionary
+ {
+ Dictionary UnderlyingDictionary { get; }
+ Type TypeOfKeys { get; }
+ Type TypeOfValues { get; }
}
+ // TODO: Now we should be able to avoid boxing
+
/// <summary>
/// Typed wrapper around Godot's Dictionary class, a dictionary of Variant
/// typed elements allocated in the engine in C++. Useful when
@@ -364,24 +357,32 @@ namespace Godot.Collections
/// </summary>
/// <typeparam name="TKey">The type of the dictionary's keys.</typeparam>
/// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
- public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>
+ public sealed class Dictionary<TKey, TValue> :
+ IDictionary<TKey, TValue>, IGenericGodotDictionary
{
- private readonly Dictionary _objectDict;
+ private readonly Dictionary _underlyingDict;
- internal static int valTypeEncoding;
- internal static IntPtr valTypeClass;
+ internal ref godot_dictionary NativeValue => ref _underlyingDict.NativeValue;
- static Dictionary()
- {
- Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass);
- }
+ // ReSharper disable StaticMemberInGenericType
+ // Warning is about unique static fields being created for each generic type combination:
+ // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
+ // In our case this is exactly what we want.
+ private static readonly Type TypeOfKeys = typeof(TKey);
+
+ private static readonly Type TypeOfValues = typeof(TValue);
+ // ReSharper restore StaticMemberInGenericType
+
+ Dictionary IGenericGodotDictionary.UnderlyingDictionary => _underlyingDict;
+ Type IGenericGodotDictionary.TypeOfKeys => TypeOfKeys;
+ Type IGenericGodotDictionary.TypeOfValues => TypeOfValues;
/// <summary>
/// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
public Dictionary()
{
- _objectDict = new Dictionary();
+ _underlyingDict = new Dictionary();
}
/// <summary>
@@ -391,19 +392,13 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
{
- _objectDict = new Dictionary();
+ _underlyingDict = new Dictionary();
if (dictionary == null)
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
- // TODO: Can be optimized
-
- IntPtr godotDictionaryPtr = GetPtr();
-
foreach (KeyValuePair<TKey, TValue> entry in dictionary)
- {
- Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
- }
+ Add(entry.Key, entry.Value);
}
/// <summary>
@@ -413,18 +408,12 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(Dictionary dictionary)
{
- _objectDict = dictionary;
+ _underlyingDict = dictionary;
}
- internal Dictionary(IntPtr handle)
- {
- _objectDict = new Dictionary(handle);
- }
-
- internal Dictionary(DictionarySafeHandle handle)
- {
- _objectDict = new Dictionary(handle);
- }
+ // Explicit name to make it very clear
+ internal static Dictionary<TKey, TValue> CreateTakingOwnershipOfDisposableValue(godot_dictionary nativeValueToOwn)
+ => new Dictionary<TKey, TValue>(Dictionary.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn));
/// <summary>
/// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>.
@@ -432,12 +421,7 @@ namespace Godot.Collections
/// <param name="from">The typed dictionary to convert.</param>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
{
- return from._objectDict;
- }
-
- internal IntPtr GetPtr()
- {
- return _objectDict.GetPtr();
+ return from._underlyingDict;
}
/// <summary>
@@ -447,7 +431,7 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary<TKey, TValue> Duplicate(bool deep = false)
{
- return new Dictionary<TKey, TValue>(_objectDict.Duplicate(deep));
+ return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep));
}
// IDictionary<TKey, TValue>
@@ -458,8 +442,16 @@ namespace Godot.Collections
/// <value>The value at the given <paramref name="key"/>.</value>
public TValue this[TKey key]
{
- get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(_objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); }
- set { _objectDict[key] = value; }
+ get
+ {
+ Dictionary.godot_icall_Dictionary_GetValue(ref _underlyingDict.NativeValue, key, out godot_variant value);
+ unsafe
+ {
+ using (value)
+ return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues);
+ }
+ }
+ set => _underlyingDict[key] = value;
}
/// <summary>
@@ -469,8 +461,9 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(_objectDict.GetPtr());
- return new Array<TKey>(new ArraySafeHandle(handle));
+ godot_array keyArray;
+ Dictionary.godot_icall_Dictionary_Keys(ref _underlyingDict.NativeValue, out keyArray);
+ return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray);
}
}
@@ -481,15 +474,25 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = Dictionary.godot_icall_Dictionary_Values(_objectDict.GetPtr());
- return new Array<TValue>(new ArraySafeHandle(handle));
+ godot_array valuesArray;
+ Dictionary.godot_icall_Dictionary_Values(ref _underlyingDict.NativeValue, out valuesArray);
+ return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
{
- Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass);
- return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
+ Dictionary.godot_icall_Dictionary_KeyValuePairAt(ref _underlyingDict.NativeValue, index, out var vKey, out var vValue);
+ unsafe
+ {
+ using (vKey)
+ using (vValue)
+ {
+ var key = Marshaling.variant_to_mono_object_of_type(&vKey, TypeOfKeys);
+ var value = Marshaling.variant_to_mono_object_of_type(&vValue, TypeOfValues);
+ return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
+ }
+ }
}
/// <summary>
@@ -500,7 +503,7 @@ namespace Godot.Collections
/// <param name="value">The object to add.</param>
public void Add(TKey key, TValue value)
{
- _objectDict.Add(key, value);
+ _underlyingDict.Add(key, value);
}
/// <summary>
@@ -510,7 +513,7 @@ namespace Godot.Collections
/// <returns>Whether or not this dictionary contains the given key.</returns>
public bool ContainsKey(TKey key)
{
- return _objectDict.Contains(key);
+ return _underlyingDict.Contains(key);
}
/// <summary>
@@ -519,7 +522,7 @@ namespace Godot.Collections
/// <param name="key">The key of the element to remove.</param>
public bool Remove(TKey key)
{
- return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ return Dictionary.godot_icall_Dictionary_RemoveKey(ref _underlyingDict.NativeValue, key);
}
/// <summary>
@@ -530,8 +533,18 @@ namespace Godot.Collections
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass);
- value = found ? (TValue)retValue : default;
+ bool found = Dictionary.godot_icall_Dictionary_TryGetValue(ref _underlyingDict.NativeValue, key, out godot_variant retValue);
+
+ unsafe
+ {
+ using (retValue)
+ {
+ value = found ?
+ (TValue)Marshaling.variant_to_mono_object_of_type(&retValue, TypeOfValues) :
+ default;
+ }
+ }
+
return found;
}
@@ -542,16 +555,13 @@ namespace Godot.Collections
/// This is also known as the size or length of the dictionary.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count
- {
- get { return _objectDict.Count; }
- }
+ public int Count => _underlyingDict.Count;
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
- _objectDict.Add(item.Key, item.Value);
+ _underlyingDict.Add(item.Key, item.Value);
}
/// <summary>
@@ -559,12 +569,12 @@ namespace Godot.Collections
/// </summary>
public void Clear()
{
- _objectDict.Clear();
+ _underlyingDict.Clear();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
- return _objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
+ return _underlyingDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
}
/// <summary>
@@ -595,8 +605,7 @@ namespace Godot.Collections
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
- return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
- ;
+ return Dictionary.godot_icall_Dictionary_Remove(ref _underlyingDict.NativeValue, item.Key, item.Value);
}
// IEnumerable<KeyValuePair<TKey, TValue>>
@@ -613,15 +622,12 @@ namespace Godot.Collections
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string.
/// </summary>
/// <returns>A string representation of this dictionary.</returns>
- public override string ToString() => _objectDict.ToString();
+ public override string ToString() => _underlyingDict.ToString();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
index df130a5c77..7922f38ac5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using Godot.Collections;
+using Godot.NativeInterop;
namespace Godot
{
@@ -12,10 +13,12 @@ namespace Godot
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
public Array<T> GetNodesInGroup<T>(StringName group) where T : class
{
- return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), StringName.GetPtr(group), typeof(T)));
+ godot_array array;
+ godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), ref group.NativeValue, typeof(T), out array);
+ return Array<T>.CreateTakingOwnershipOfDisposableValue(array);
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType);
+ internal static extern void godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, ref godot_string_name group, Type elemType, out godot_array dest);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 236d0666bc..e8ea8f379b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -6,6 +6,7 @@ using real_t = System.Single;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -26,9 +27,10 @@ namespace Godot
/// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param>
/// <param name="allowObjects">If objects should be decoded.</param>
/// <returns>The decoded <c>Variant</c>.</returns>
- public static object Bytes2Var(byte[] bytes, bool allowObjects = false)
+ public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false)
{
- return godot_icall_GD_bytes2var(bytes, allowObjects);
+ using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes);
+ return godot_icall_GD_bytes2var(&varBytes, allowObjects);
}
/// <summary>
@@ -527,7 +529,7 @@ namespace Godot
/// <returns>If the class exists in <see cref="ClassDB"/>.</returns>
public static bool TypeExists(StringName type)
{
- return godot_icall_GD_type_exists(StringName.GetPtr(type));
+ return godot_icall_GD_type_exists(ref type.NativeValue);
}
/// <summary>
@@ -539,9 +541,14 @@ namespace Godot
/// <param name="var">Variant that will be encoded.</param>
/// <param name="fullObjects">If objects should be serialized.</param>
/// <returns>The <c>Variant</c> encoded as an array of bytes.</returns>
- public static byte[] Var2Bytes(object var, bool fullObjects = false)
+ public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false)
{
- return godot_icall_GD_var2bytes(var, fullObjects);
+ godot_packed_byte_array varBytes;
+ godot_icall_GD_var2bytes(var, fullObjects, &varBytes);
+ using (varBytes)
+ {
+ return Marshaling.PackedByteArray_to_mono_array(&varBytes);
+ }
}
/// <summary>
@@ -576,7 +583,7 @@ namespace Godot
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects);
+ internal static extern unsafe object godot_icall_GD_bytes2var(godot_packed_byte_array* bytes, bool allowObjects);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object godot_icall_GD_convert(object what, Variant.Type type);
@@ -636,10 +643,10 @@ namespace Godot
internal static extern object godot_icall_GD_str2var(string str);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_GD_type_exists(IntPtr type);
+ internal static extern bool godot_icall_GD_type_exists(ref godot_string_name type);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern byte[] godot_icall_GD_var2bytes(object what, bool fullObjects);
+ internal static extern unsafe void godot_icall_GD_var2bytes(object what, bool fullObjects, godot_packed_byte_array* bytes);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern string godot_icall_GD_var2str(object var);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
index 50ae2eb112..733a8ac114 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
@@ -6,149 +6,8 @@ namespace Godot
internal static class MarshalUtils
{
/// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericArray(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Collections.Array<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericDictionary(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Collections.Dictionary<,>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="List{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsSystemGenericList(Type type) =>
- type.GetGenericTypeDefinition() == typeof(List<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsSystemGenericDictionary(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="IEnumerable{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="ICollection{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="IDictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
-
- /// <summary>
/// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
/// </summary>
private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
-
- /// <summary>
- /// Returns the generic type definition of <paramref name="type"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition)
- {
- genericTypeDefinition = type.GetGenericTypeDefinition();
- }
-
- /// <summary>
- /// Gets the element type for the given <paramref name="arrayType"/>.
- /// </summary>
- /// <param name="arrayType">Type for the generic array.</param>
- /// <param name="elementType">Element type for the generic array.</param>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="arrayType"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void ArrayGetElementType(Type arrayType, out Type elementType)
- {
- elementType = arrayType.GetGenericArguments()[0];
- }
-
- /// <summary>
- /// Gets the key type and the value type for the given <paramref name="dictionaryType"/>.
- /// </summary>
- /// <param name="dictionaryType">The type for the generic dictionary.</param>
- /// <param name="keyType">Key type for the generic dictionary.</param>
- /// <param name="valueType">Value type for the generic dictionary.</param>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="dictionaryType"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
- {
- var genericArgs = dictionaryType.GetGenericArguments();
- keyType = genericArgs[0];
- valueType = genericArgs[1];
- }
-
- /// <summary>
- /// Constructs a new <see cref="Type"/> from <see cref="Collections.Array{T}"/>
- /// where the generic type for the elements is <paramref name="elemType"/>.
- /// </summary>
- /// <param name="elemType">Element type for the array.</param>
- /// <returns>The generic array type with the specified element type.</returns>
- private static Type MakeGenericArrayType(Type elemType)
- {
- return typeof(Collections.Array<>).MakeGenericType(elemType);
- }
-
- /// <summary>
- /// Constructs a new <see cref="Type"/> from <see cref="Collections.Dictionary{TKey, TValue}"/>
- /// where the generic type for the keys is <paramref name="keyType"/> and
- /// for the values is <paramref name="valueType"/>.
- /// </summary>
- /// <param name="keyType">Key type for the dictionary.</param>
- /// <param name="valueType">Key type for the dictionary.</param>
- /// <returns>The generic dictionary type with the specified key and value types.</returns>
- private static Type MakeGenericDictionaryType(Type keyType, Type valueType)
- {
- return typeof(Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
- }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
new file mode 100644
index 0000000000..6ee8cbc0bc
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -0,0 +1,438 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+
+#endif
+
+namespace Godot.NativeInterop
+{
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_bool
+ {
+ public byte _value;
+
+ public unsafe godot_bool(bool value) => _value = *(byte*)&value;
+
+ public static unsafe implicit operator bool(godot_bool godotBool) => *(bool*)&godotBool._value;
+ public static implicit operator godot_bool(bool @bool) => new godot_bool(@bool);
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_ref : IDisposable
+ {
+ internal IntPtr _reference;
+
+ public void Dispose()
+ {
+ if (_reference == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_ref_destroy(ref this);
+ _reference = IntPtr.Zero;
+ }
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ internal enum godot_variant_call_error_error
+ {
+ GODOT_CALL_ERROR_CALL_OK = 0,
+ GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD,
+ GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT,
+ GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS,
+ GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS,
+ GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_variant_call_error
+ {
+ godot_variant_call_error_error error;
+ int argument;
+ int expected;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_variant : IDisposable
+ {
+ // 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;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ internal unsafe 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 AABB* _aabb;
+ [FieldOffset(0)] public Basis* _basis;
+ [FieldOffset(0)] public Transform3D* _transform3d;
+ [FieldOffset(0)] public Vector4* _vector4;
+ [FieldOffset(0)] public Vector4i* _vector4i;
+ [FieldOffset(0)] public Projection* _projection;
+ [FieldOffset(0)] private godot_variant_data_mem _mem;
+
+ // The following fields are not in the C++ union, but this is how they're stored in _mem.
+ [FieldOffset(0)] public godot_string_name _m_string_name;
+ [FieldOffset(0)] public godot_string _m_string;
+ [FieldOffset(0)] public Vector3 _m_vector3;
+ [FieldOffset(0)] public Vector3i _m_vector3i;
+ [FieldOffset(0)] public Vector2 _m_vector2;
+ [FieldOffset(0)] public Vector2i _m_vector2i;
+ [FieldOffset(0)] public Rect2 _m_rect2;
+ [FieldOffset(0)] public Rect2i _m_rect2i;
+ [FieldOffset(0)] public Plane _m_plane;
+ [FieldOffset(0)] public Quaternion _m_quaternion;
+ [FieldOffset(0)] public Color _m_color;
+ [FieldOffset(0)] public godot_node_path _m_node_path;
+ [FieldOffset(0)] public RID _m_rid;
+ [FieldOffset(0)] public godot_variant_obj_data _m_obj_data;
+ [FieldOffset(0)] public godot_callable _m_callable;
+ [FieldOffset(0)] public godot_signal _m_signal;
+ [FieldOffset(0)] public godot_dictionary _m_dictionary;
+ [FieldOffset(0)] public godot_array _m_array;
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_variant_obj_data
+ {
+ public UInt64 id;
+ public IntPtr obj;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ private struct godot_variant_data_mem
+ {
+#pragma warning disable 169
+ private real_t _mem0;
+ private real_t _mem1;
+ private real_t _mem2;
+ private real_t _mem3;
+#pragma warning restore 169
+ }
+ }
+
+ public void Dispose()
+ {
+ switch (_type)
+ {
+ case Variant.Type.Nil:
+ case Variant.Type.Bool:
+ case Variant.Type.Int:
+ case Variant.Type.Float:
+ case Variant.Type.Vector2:
+ case Variant.Type.Vector2i:
+ case Variant.Type.Rect2:
+ case Variant.Type.Rect2i:
+ case Variant.Type.Vector3:
+ case Variant.Type.Vector3i:
+ case Variant.Type.Plane:
+ case Variant.Type.Quaternion:
+ case Variant.Type.Color:
+ case Variant.Type.Rid:
+ return;
+ }
+
+ NativeFuncs.godotsharp_variant_destroy(ref this);
+ _type = Variant.Type.Nil;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_string : IDisposable
+ {
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_string_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_string_name : IDisposable
+ {
+ internal IntPtr _data;
+
+ public void Dispose()
+ {
+ if (_data == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_string_name_destroy(ref this);
+ _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) =>
+ // This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++.
+ name._data == IntPtr.Zero;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_node_path : IDisposable
+ {
+ internal IntPtr _data;
+
+ public void Dispose()
+ {
+ if (_data == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_node_path_destroy(ref this);
+ _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
+ internal 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()
+ {
+ if (_name._data == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_signal_destroy(ref this);
+ _name._data = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_callable : IDisposable
+ {
+ [FieldOffset(0)] public godot_string_name _method;
+
+ // There's padding here on 32-bit
+
+ [FieldOffset(8)] public UInt64 _objectId;
+ [FieldOffset(8)] public IntPtr _custom;
+
+ public void Dispose()
+ {
+ if (_method._data == IntPtr.Zero && _custom == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_callable_destroy(ref this);
+ _method._data = IntPtr.Zero;
+ _custom = IntPtr.Zero;
+ }
+ }
+
+ // A correctly constructed value needs to call the native default constructor to allocate `_p`.
+ // Don't pass a C# default constructed `godot_array` to native code, unless it's going to
+ // 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
+ internal struct godot_array : IDisposable
+ {
+ internal IntPtr _p;
+
+ public void Dispose()
+ {
+ if (_p == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_array_destroy(ref this);
+ _p = IntPtr.Zero;
+ }
+ }
+
+ // IMPORTANT:
+ // A correctly constructed value needs to call the native default constructor to allocate `_p`.
+ // Don't pass a C# default constructed `godot_dictionary` to native code, unless it's going to
+ // 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
+ internal struct godot_dictionary : IDisposable
+ {
+ internal IntPtr _p;
+
+ public void Dispose()
+ {
+ if (_p == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_dictionary_destroy(ref this);
+ _p = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_byte_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_byte_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_int32_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_int32_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_int64_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_int64_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_float32_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_float32_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_float64_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_float64_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_string_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_string_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_vector2_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_vector2_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_vector3_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_vector3_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct godot_packed_color_array : IDisposable
+ {
+ internal IntPtr _writeProxy;
+ internal IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_packed_color_array_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
new file mode 100644
index 0000000000..08d49bb937
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot.NativeInterop
+{
+ internal static class InteropUtils
+ {
+ public static Object UnmanagedGetManaged(IntPtr unmanaged)
+ {
+ // TODO: Move to C#
+ return internal_unmanaged_get_managed(unmanaged);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern Object internal_unmanaged_get_managed(IntPtr unmanaged);
+
+ public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged)
+ {
+ // TODO: Move to C#
+ internal_tie_managed_to_unmanaged(managed, unmanaged);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_tie_managed_to_unmanaged(Object managed, IntPtr unmanaged);
+
+ public static unsafe Object EngineGetSingleton(string name)
+ {
+ using godot_string src = Marshaling.mono_string_to_godot(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
new file mode 100644
index 0000000000..9b6f9633d1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -0,0 +1,1370 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ // We want to use full name qualifiers here even if redundant for clarity
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ internal static class Marshaling
+ {
+ public static unsafe void SetFieldValue(FieldInfo fieldInfo, object obj, godot_variant* value)
+ {
+ var valueObj = variant_to_mono_object_of_type(value, fieldInfo.FieldType);
+ fieldInfo.SetValue(obj, valueObj);
+ }
+
+ public static Variant.Type managed_to_variant_type(Type type, ref bool r_nil_is_variant)
+ {
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ return Variant.Type.Bool;
+ case TypeCode.Char:
+ return Variant.Type.Int;
+ case TypeCode.SByte:
+ return Variant.Type.Int;
+ case TypeCode.Int16:
+ return Variant.Type.Int;
+ case TypeCode.Int32:
+ return Variant.Type.Int;
+ case TypeCode.Int64:
+ return Variant.Type.Int;
+ case TypeCode.Byte:
+ return Variant.Type.Int;
+ case TypeCode.UInt16:
+ return Variant.Type.Int;
+ case TypeCode.UInt32:
+ return Variant.Type.Int;
+ case TypeCode.UInt64:
+ return Variant.Type.Int;
+ case TypeCode.Single:
+ return Variant.Type.Float;
+ case TypeCode.Double:
+ return Variant.Type.Float;
+ case TypeCode.String:
+ return Variant.Type.String;
+ default:
+ {
+ if (type == typeof(Vector2))
+ return Variant.Type.Vector2;
+
+ if (type == typeof(Vector2i))
+ return Variant.Type.Vector2i;
+
+ if (type == typeof(Rect2))
+ return Variant.Type.Rect2;
+
+ if (type == typeof(Rect2i))
+ return Variant.Type.Rect2i;
+
+ if (type == typeof(Transform2D))
+ return Variant.Type.Transform2d;
+
+ if (type == typeof(Vector3))
+ return Variant.Type.Vector3;
+
+ if (type == typeof(Vector3i))
+ return Variant.Type.Vector3i;
+
+ if (type == typeof(Vector4))
+ return Variant.Type.Vector4;
+
+ if (type == typeof(Vector4i))
+ return Variant.Type.Vector4i;
+
+ if (type == typeof(Basis))
+ return Variant.Type.Basis;
+
+ if (type == typeof(Quaternion))
+ return Variant.Type.Quaternion;
+
+ if (type == typeof(Transform3D))
+ return Variant.Type.Transform3d;
+
+ if (type == typeof(Projection))
+ return Variant.Type.Projection;
+
+ if (type == typeof(AABB))
+ return Variant.Type.Aabb;
+
+ if (type == typeof(Color))
+ return Variant.Type.Color;
+
+ if (type == typeof(Plane))
+ return Variant.Type.Plane;
+
+ if (type == typeof(Callable))
+ return Variant.Type.Callable;
+
+ if (type == typeof(SignalInfo))
+ return Variant.Type.Signal;
+
+ if (type.IsEnum)
+ return Variant.Type.Int;
+
+ if (type.IsArray || type.IsSZArray)
+ {
+ if (type == typeof(Byte[]))
+ return Variant.Type.PackedByteArray;
+
+ if (type == typeof(Int32[]))
+ return Variant.Type.PackedInt32Array;
+
+ if (type == typeof(Int64[]))
+ return Variant.Type.PackedInt64Array;
+
+ if (type == typeof(float[]))
+ return Variant.Type.PackedFloat32Array;
+
+ if (type == typeof(double[]))
+ return Variant.Type.PackedFloat64Array;
+
+ if (type == typeof(string[]))
+ return Variant.Type.PackedStringArray;
+
+ if (type == typeof(Vector2[]))
+ return Variant.Type.PackedVector2Array;
+
+ if (type == typeof(Vector3[]))
+ return Variant.Type.PackedVector3Array;
+
+ if (type == typeof(Color[]))
+ return Variant.Type.PackedColorArray;
+
+ if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ return Variant.Type.Array;
+
+ if (type == typeof(object[]))
+ return Variant.Type.Array;
+ }
+ else if (type.IsGenericType)
+ {
+ var genericTypeDefinition = type.GetGenericTypeDefinition();
+
+ if (genericTypeDefinition == typeof(Collections.Dictionary<,>))
+ return Variant.Type.Dictionary;
+
+ if (genericTypeDefinition == typeof(Collections.Array<>))
+ return Variant.Type.Array;
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>))
+ return Variant.Type.Dictionary;
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.List<>))
+ return Variant.Type.Array;
+
+ if (genericTypeDefinition == typeof(IDictionary<,>))
+ return Variant.Type.Dictionary;
+
+ if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>))
+ return Variant.Type.Array;
+ }
+ else if (type == typeof(object))
+ {
+ r_nil_is_variant = true;
+ return Variant.Type.Nil;
+ }
+ else
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ return Variant.Type.Object;
+
+ if (typeof(StringName) == type)
+ return Variant.Type.StringName;
+
+ if (typeof(NodePath) == type)
+ return Variant.Type.NodePath;
+
+ if (typeof(RID) == type)
+ return Variant.Type.Rid;
+
+ if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type)
+ return Variant.Type.Dictionary;
+
+ if (typeof(Collections.Array) == type ||
+ typeof(System.Collections.ICollection) == type ||
+ typeof(System.Collections.IEnumerable) == type)
+ {
+ return Variant.Type.Array;
+ }
+ }
+
+ break;
+ }
+ }
+
+ r_nil_is_variant = false;
+
+ // Unknown
+ 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);
+ }
+
+ // TODO: Only called from C++. Remove once no longer needed.
+ private static unsafe void mono_object_to_variant_out(object p_obj, bool p_fail_with_err, godot_variant* r_ret)
+ => *r_ret = mono_object_to_variant_impl(p_obj, p_fail_with_err);
+
+ private static unsafe godot_variant mono_object_to_variant_impl(object p_obj, bool p_fail_with_err = true)
+ {
+ if (p_obj == null)
+ return new godot_variant();
+
+ switch (p_obj)
+ {
+ case bool @bool:
+ return VariantUtils.CreateFromBool(@bool);
+ case char @char:
+ return VariantUtils.CreateFromInt(@char);
+ case SByte @int8:
+ return VariantUtils.CreateFromInt(@int8);
+ case Int16 @int16:
+ return VariantUtils.CreateFromInt(@int16);
+ case Int32 @int32:
+ return VariantUtils.CreateFromInt(@int32);
+ case Int64 @int64:
+ return VariantUtils.CreateFromInt(@int64);
+ case Byte @uint8:
+ return VariantUtils.CreateFromInt(@uint8);
+ case UInt16 @uint16:
+ return VariantUtils.CreateFromInt(@uint16);
+ case UInt32 @uint32:
+ return VariantUtils.CreateFromInt(@uint32);
+ case UInt64 @uint64:
+ return VariantUtils.CreateFromInt(@uint64);
+ case float @float:
+ return VariantUtils.CreateFromFloat(@float);
+ case double @double:
+ return VariantUtils.CreateFromFloat(@double);
+ case Vector2 @vector2:
+ return VariantUtils.CreateFromVector2(@vector2);
+ case Vector2i @vector2i:
+ return VariantUtils.CreateFromVector2i(@vector2i);
+ case Rect2 @rect2:
+ return VariantUtils.CreateFromRect2(@rect2);
+ case Rect2i @rect2i:
+ return VariantUtils.CreateFromRect2i(@rect2i);
+ case Transform2D @transform2D:
+ return VariantUtils.CreateFromTransform2D(@transform2D);
+ case Vector3 @vector3:
+ return VariantUtils.CreateFromVector3(@vector3);
+ case Vector3i @vector3i:
+ return VariantUtils.CreateFromVector3i(@vector3i);
+ case Vector4 @vector4:
+ return VariantUtils.CreateFromVector4(@vector4);
+ case Vector4i @vector4i:
+ return VariantUtils.CreateFromVector4i(@vector4i);
+ case Basis @basis:
+ return VariantUtils.CreateFromBasis(@basis);
+ case Quaternion @quaternion:
+ return VariantUtils.CreateFromQuaternion(@quaternion);
+ case Transform3D @transform3d:
+ return VariantUtils.CreateFromTransform3D(@transform3d);
+ case Projection @projection:
+ return VariantUtils.CreateFromProjection(@projection);
+ case AABB @aabb:
+ return VariantUtils.CreateFromAABB(@aabb);
+ case Color @color:
+ return VariantUtils.CreateFromColor(@color);
+ case Plane @plane:
+ return VariantUtils.CreateFromPlane(@plane);
+ case Callable @callable:
+ return VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue(
+ ConvertCallableToNative(ref @callable));
+ case SignalInfo @signalInfo:
+ return VariantUtils.CreateFromSignalTakingOwnershipOfDisposableValue(
+ ConvertSignalToNative(ref @signalInfo));
+ case Enum @enum:
+ return VariantUtils.CreateFromInt(Convert.ToInt64(@enum));
+ case string @string:
+ {
+ return VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue(
+ mono_string_to_godot(@string));
+ }
+ case Byte[] byteArray:
+ {
+ using godot_packed_byte_array array = mono_array_to_PackedByteArray(byteArray);
+ return VariantUtils.CreateFromPackedByteArray(&array);
+ }
+ case Int32[] int32Array:
+ {
+ using godot_packed_int32_array array = mono_array_to_PackedInt32Array(int32Array);
+ return VariantUtils.CreateFromPackedInt32Array(&array);
+ }
+ case Int64[] int64Array:
+ {
+ using godot_packed_int64_array array = mono_array_to_PackedInt64Array(int64Array);
+ return VariantUtils.CreateFromPackedInt64Array(&array);
+ }
+ case float[] floatArray:
+ {
+ using godot_packed_float32_array array = mono_array_to_PackedFloat32Array(floatArray);
+ return VariantUtils.CreateFromPackedFloat32Array(&array);
+ }
+ case double[] doubleArray:
+ {
+ using godot_packed_float64_array array = mono_array_to_PackedFloat64Array(doubleArray);
+ return VariantUtils.CreateFromPackedFloat64Array(&array);
+ }
+ case string[] stringArray:
+ {
+ using godot_packed_string_array array = mono_array_to_PackedStringArray(stringArray);
+ return VariantUtils.CreateFromPackedStringArray(&array);
+ }
+ case Vector2[] vector2Array:
+ {
+ using godot_packed_vector2_array array = mono_array_to_PackedVector2Array(vector2Array);
+ return VariantUtils.CreateFromPackedVector2Array(&array);
+ }
+ case Vector3[] vector3Array:
+ {
+ using godot_packed_vector3_array array = mono_array_to_PackedVector3Array(vector3Array);
+ return VariantUtils.CreateFromPackedVector3Array(&array);
+ }
+ case Color[] colorArray:
+ {
+ using godot_packed_color_array array = mono_array_to_PackedColorArray(colorArray);
+ return VariantUtils.CreateFromPackedColorArray(&array);
+ }
+ case Godot.Object[] godotObjectArray:
+ {
+ // ReSharper disable once CoVariantArrayConversion
+ using godot_array array = mono_array_to_Array(godotObjectArray);
+ return VariantUtils.CreateFromArray(&array);
+ }
+ case object[] objectArray: // Last one to avoid catching others like string[] and Godot.Object[]
+ {
+ // The pattern match for `object[]` catches arrays on any reference type,
+ // 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);
+ }
+
+ 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();
+ }
+ }
+ case Godot.Object godotObject:
+ return VariantUtils.CreateFromGodotObject(godotObject.NativeInstance);
+ case StringName stringName:
+ return VariantUtils.CreateFromStringName(ref stringName.NativeValue);
+ case NodePath nodePath:
+ return VariantUtils.CreateFromNodePath(ref nodePath.NativeValue);
+ case RID rid:
+ return VariantUtils.CreateFromRID(rid);
+ case Collections.Dictionary godotDictionary:
+ return VariantUtils.CreateFromDictionary(godotDictionary.NativeValue);
+ case Collections.Array godotArray:
+ return VariantUtils.CreateFromArray(godotArray.NativeValue);
+ case Collections.IGenericGodotDictionary genericGodotDictionary:
+ {
+ var godotDict = genericGodotDictionary.UnderlyingDictionary;
+ if (godotDict == null)
+ return new godot_variant();
+ return VariantUtils.CreateFromDictionary(godotDict.NativeValue);
+ }
+ case Collections.IGenericGodotArray genericGodotArray:
+ {
+ var godotArray = genericGodotArray.UnderlyingArray;
+ if (godotArray == null)
+ return new godot_variant();
+ return VariantUtils.CreateFromArray(godotArray.NativeValue);
+ }
+ default:
+ {
+ var type = p_obj.GetType();
+
+ if (type.IsGenericType)
+ {
+ var genericTypeDefinition = type.GetGenericTypeDefinition();
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>))
+ {
+ // TODO: Validate key and value types are compatible with Variant
+#if NET
+ Collections.IGenericGodotDictionary genericGodotDictionary = IDictionaryToGenericGodotDictionary((dynamic)p_obj);
+#else
+ var genericArguments = type.GetGenericArguments();
+
+ // With .NET Standard we need a package reference for Microsoft.CSharp in order to
+ // use dynamic, so we have this workaround for now until we switch to .NET 5/6.
+ var method = typeof(Marshaling).GetMethod(nameof(IDictionaryToGenericGodotDictionary),
+ BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!
+ .MakeGenericMethod(genericArguments[0], genericArguments[1]);
+
+ var genericGodotDictionary = (Collections.IGenericGodotDictionary)method
+ .Invoke(null, new[] {p_obj});
+#endif
+
+ var godotDict = genericGodotDictionary.UnderlyingDictionary;
+ if (godotDict == null)
+ return new godot_variant();
+ return VariantUtils.CreateFromDictionary(godotDict.NativeValue);
+ }
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.List<>))
+ {
+ // TODO: Validate element type is compatible with Variant
+#if NET
+ var nativeGodotArray = mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj));
+#else
+ // With .NET Standard we need a package reference for Microsoft.CSharp in order to
+ // use dynamic, so we have this workaround for now until we switch to .NET 5/6.
+ // Also CollectionsMarshal.AsSpan is not available with .NET Standard.
+
+ var collection = (System.Collections.ICollection)p_obj;
+ var array = new object[collection.Count];
+ collection.CopyTo(array, 0);
+ var nativeGodotArray = mono_array_to_Array(array);
+#endif
+ return VariantUtils.CreateFromArray(&nativeGodotArray);
+ }
+ }
+
+ break;
+ }
+ }
+
+ 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();
+ }
+ }
+
+ private static Collections.Dictionary<TKey, TValue> IDictionaryToGenericGodotDictionary<TKey, TValue>
+ (IDictionary<TKey, TValue> dictionary) => new(dictionary);
+
+ public static unsafe string variant_to_mono_string(godot_variant* p_var)
+ {
+ 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);
+ }
+ default:
+ {
+ using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var);
+ return mono_string_from_godot(&godotString);
+ }
+ }
+ }
+
+ public static unsafe object variant_to_mono_object_of_type(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))
+ {
+ case TypeCode.Boolean:
+ return VariantUtils.ConvertToBool(p_var);
+ case TypeCode.Char:
+ return VariantUtils.ConvertToChar(p_var);
+ case TypeCode.SByte:
+ return VariantUtils.ConvertToInt8(p_var);
+ case TypeCode.Int16:
+ return VariantUtils.ConvertToInt16(p_var);
+ case TypeCode.Int32:
+ return VariantUtils.ConvertToInt32(p_var);
+ case TypeCode.Int64:
+ return VariantUtils.ConvertToInt64(p_var);
+ case TypeCode.Byte:
+ return VariantUtils.ConvertToUInt8(p_var);
+ case TypeCode.UInt16:
+ return VariantUtils.ConvertToUInt16(p_var);
+ case TypeCode.UInt32:
+ return VariantUtils.ConvertToUInt32(p_var);
+ case TypeCode.UInt64:
+ return VariantUtils.ConvertToUInt64(p_var);
+ case TypeCode.Single:
+ return VariantUtils.ConvertToFloat32(p_var);
+ case TypeCode.Double:
+ return VariantUtils.ConvertToFloat64(p_var);
+ case TypeCode.String:
+ return variant_to_mono_string(p_var);
+ default:
+ {
+ if (type == typeof(Vector2))
+ return VariantUtils.ConvertToVector2(p_var);
+
+ if (type == typeof(Vector2i))
+ return VariantUtils.ConvertToVector2i(p_var);
+
+ if (type == typeof(Rect2))
+ return VariantUtils.ConvertToRect2(p_var);
+
+ if (type == typeof(Rect2i))
+ return VariantUtils.ConvertToRect2i(p_var);
+
+ if (type == typeof(Transform2D))
+ return VariantUtils.ConvertToTransform2D(p_var);
+
+ if (type == typeof(Vector3))
+ return VariantUtils.ConvertToVector3(p_var);
+
+ if (type == typeof(Vector3i))
+ return VariantUtils.ConvertToVector3i(p_var);
+
+ if (type == typeof(Vector4))
+ return VariantUtils.ConvertToVector4(p_var);
+
+ if (type == typeof(Vector4i))
+ return VariantUtils.ConvertToVector4i(p_var);
+
+ if (type == typeof(Basis))
+ return VariantUtils.ConvertToBasis(p_var);
+
+ if (type == typeof(Quaternion))
+ return VariantUtils.ConvertToQuaternion(p_var);
+
+ if (type == typeof(Transform3D))
+ return VariantUtils.ConvertToTransform3D(p_var);
+
+ if (type == typeof(Projection))
+ return VariantUtils.ConvertToProjection(p_var);
+
+ if (type == typeof(AABB))
+ return VariantUtils.ConvertToAABB(p_var);
+
+ if (type == typeof(Color))
+ return VariantUtils.ConvertToColor(p_var);
+
+ if (type == typeof(Plane))
+ return VariantUtils.ConvertToPlane(p_var);
+
+ if (type == typeof(Callable))
+ {
+ using godot_callable callable = NativeFuncs.godotsharp_variant_as_callable(p_var);
+ return ConvertCallableToManaged(&callable);
+ }
+
+ if (type == typeof(SignalInfo))
+ {
+ using godot_signal signal = NativeFuncs.godotsharp_variant_as_signal(p_var);
+ return ConvertSignalToManaged(&signal);
+ }
+
+ if (type.IsEnum)
+ {
+ var enumUnderlyingType = type.GetEnumUnderlyingType();
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ return VariantUtils.ConvertToInt8(p_var);
+ case TypeCode.Int16:
+ return VariantUtils.ConvertToInt16(p_var);
+ case TypeCode.Int32:
+ return VariantUtils.ConvertToInt32(p_var);
+ case TypeCode.Int64:
+ return VariantUtils.ConvertToInt64(p_var);
+ case TypeCode.Byte:
+ return VariantUtils.ConvertToUInt8(p_var);
+ case TypeCode.UInt16:
+ return VariantUtils.ConvertToUInt16(p_var);
+ case TypeCode.UInt32:
+ return VariantUtils.ConvertToUInt32(p_var);
+ case TypeCode.UInt64:
+ return VariantUtils.ConvertToUInt64(p_var);
+ default:
+ {
+ GD.PushError("Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
+ type.FullName + " : " + enumUnderlyingType.FullName + ".");
+ return null;
+ }
+ }
+ }
+
+ if (type.IsArray || type.IsSZArray)
+ return variant_to_mono_array_of_type(p_var, type);
+ else if (type.IsGenericType)
+ return variant_to_mono_object_of_genericinst(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 res;
+
+ break;
+ }
+ }
+
+ GD.PushError("Attempted to convert Variant to unsupported type. Name: " +
+ type.FullName + ".");
+ return null;
+ }
+
+ private static unsafe object variant_to_mono_array_of_type(godot_variant* p_var, Type type)
+ {
+ if (type == typeof(Byte[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var);
+ return PackedByteArray_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(Int32[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var);
+ return PackedInt32Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(Int64[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var);
+ return PackedInt64Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(float[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var);
+ return PackedFloat32Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(double[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var);
+ return PackedFloat64Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(string[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var);
+ return PackedStringArray_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(Vector2[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var);
+ return PackedVector2Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(Vector3[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var);
+ return PackedVector3Array_to_mono_array(&packedArray);
+ }
+
+ if (type == typeof(Color[]))
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var);
+ return PackedColorArray_to_mono_array(&packedArray);
+ }
+
+ if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Array_to_mono_array_of_type(&godotArray, type);
+ }
+
+ if (type == typeof(object[]))
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Array_to_mono_array(&godotArray);
+ }
+
+ GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " +
+ type.GetElementType()!.FullName + ".");
+ return null;
+ }
+
+ private static unsafe bool variant_to_mono_object_of_class(godot_variant* p_var, Type type, out object res)
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ {
+ res = InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var));
+ return true;
+ }
+
+ if (typeof(StringName) == type)
+ {
+ res = StringName.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToStringName(p_var));
+ return true;
+ }
+
+ if (typeof(NodePath) == type)
+ {
+ res = NodePath.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToNodePath(p_var));
+ return true;
+ }
+
+ if (typeof(RID) == type)
+ {
+ res = VariantUtils.ConvertToRID(p_var);
+ return true;
+ }
+
+ if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type)
+ {
+ res = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToDictionary(p_var));
+ return true;
+ }
+
+ if (typeof(Collections.Array) == type ||
+ typeof(System.Collections.ICollection) == type ||
+ typeof(System.Collections.IEnumerable) == type)
+ {
+ res = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToArray(p_var));
+ return true;
+ }
+
+ res = null;
+ return false;
+ }
+
+ private static unsafe object variant_to_mono_object_of_genericinst(godot_variant* p_var, Type type)
+ {
+ static object variant_to_generic_godot_collections_dictionary(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);
+ }
+
+ static object variant_to_generic_godot_collections_array(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);
+ }
+
+ var genericTypeDefinition = type.GetGenericTypeDefinition();
+
+ if (genericTypeDefinition == typeof(Collections.Dictionary<,>))
+ return variant_to_generic_godot_collections_dictionary(p_var, type);
+
+ if (genericTypeDefinition == typeof(Collections.Array<>))
+ return variant_to_generic_godot_collections_array(p_var, type);
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>))
+ {
+ using var godotDictionary = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToDictionary(p_var));
+
+ var dictionary = (System.Collections.IDictionary)Activator.CreateInstance(type,
+ BindingFlags.Public | BindingFlags.Instance, null,
+ args: new object[]
+ {
+ /* capacity: */ godotDictionary.Count
+ }, null);
+
+ foreach (System.Collections.DictionaryEntry pair in godotDictionary)
+ dictionary.Add(pair.Key, pair.Value);
+
+ return dictionary;
+ }
+
+ if (genericTypeDefinition == typeof(System.Collections.Generic.List<>))
+ {
+ using var godotArray = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ VariantUtils.ConvertToArray(p_var));
+
+ var list = (System.Collections.IList)Activator.CreateInstance(type,
+ BindingFlags.Public | BindingFlags.Instance, null,
+ args: new object[]
+ {
+ /* capacity: */ godotArray.Count
+ }, null);
+
+ foreach (object elem in godotArray)
+ list.Add(elem);
+
+ return list;
+ }
+
+ if (genericTypeDefinition == typeof(IDictionary<,>))
+ {
+ var genericArgs = type.GetGenericArguments();
+ var keyType = genericArgs[0];
+ var valueType = genericArgs[1];
+ var genericGodotDictionaryType = typeof(Collections.Dictionary<,>)
+ .MakeGenericType(keyType, valueType);
+
+ return variant_to_generic_godot_collections_dictionary(p_var, genericGodotDictionaryType);
+ }
+
+ if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>))
+ {
+ var elementType = type.GetGenericArguments()[0];
+ var genericGodotArrayType = typeof(Collections.Array<>)
+ .MakeGenericType(elementType);
+
+ return variant_to_generic_godot_collections_array(p_var, genericGodotArrayType);
+ }
+
+ return null;
+ }
+
+ public static unsafe object variant_to_mono_object(godot_variant* p_var)
+ {
+ switch ((*p_var)._type)
+ {
+ case Variant.Type.Bool:
+ return (bool)(*p_var)._data._bool;
+ case Variant.Type.Int:
+ return (*p_var)._data._int;
+ case Variant.Type.Float:
+ {
+#if REAL_T_IS_DOUBLE
+ return (*p_var)._data._float;
+#else
+ return (float)(*p_var)._data._float;
+#endif
+ }
+ case Variant.Type.String:
+ return mono_string_from_godot(&(*p_var)._data._m_string);
+ case Variant.Type.Vector2:
+ return (*p_var)._data._m_vector2;
+ case Variant.Type.Vector2i:
+ return (*p_var)._data._m_vector2i;
+ case Variant.Type.Rect2:
+ return (*p_var)._data._m_rect2;
+ case Variant.Type.Rect2i:
+ return (*p_var)._data._m_rect2i;
+ case Variant.Type.Vector3:
+ return (*p_var)._data._m_vector3;
+ case Variant.Type.Vector3i:
+ return (*p_var)._data._m_vector3i;
+ case Variant.Type.Transform2d:
+ return *(*p_var)._data._transform2d;
+ case Variant.Type.Vector4:
+ return *(*p_var)._data._vector4;
+ case Variant.Type.Vector4i:
+ return *(*p_var)._data._vector4i;
+ case Variant.Type.Plane:
+ return (*p_var)._data._m_plane;
+ case Variant.Type.Quaternion:
+ return (*p_var)._data._m_quaternion;
+ case Variant.Type.Aabb:
+ return *(*p_var)._data._aabb;
+ case Variant.Type.Basis:
+ return *(*p_var)._data._basis;
+ case Variant.Type.Transform3d:
+ return *(*p_var)._data._transform3d;
+ case Variant.Type.Projection:
+ return *(*p_var)._data._projection;
+ case Variant.Type.Color:
+ return (*p_var)._data._m_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));
+ }
+ 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));
+ }
+ case Variant.Type.Rid:
+ return (*p_var)._data._m_rid;
+ case Variant.Type.Object:
+ return InteropUtils.UnmanagedGetManaged((*p_var)._data._m_obj_data.obj);
+ case Variant.Type.Callable:
+ return ConvertCallableToManaged(&(*p_var)._data._m_callable);
+ case Variant.Type.Signal:
+ return ConvertSignalToManaged(&(*p_var)._data._m_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));
+ }
+ 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));
+ }
+ case Variant.Type.PackedByteArray:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var);
+ return PackedByteArray_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedInt32Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var);
+ return PackedInt32Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedInt64Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var);
+ return PackedInt64Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedFloat32Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var);
+ return PackedFloat32Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedFloat64Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var);
+ return PackedFloat64Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedStringArray:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var);
+ return PackedStringArray_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedVector2Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var);
+ return PackedVector2Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedVector3Array:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var);
+ return PackedVector3Array_to_mono_array(&packedArray);
+ }
+ case Variant.Type.PackedColorArray:
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var);
+ return PackedColorArray_to_mono_array(&packedArray);
+ }
+ default:
+ return null;
+ }
+ }
+
+ // String
+
+ public static unsafe godot_string mono_string_to_godot(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);
+ return dest;
+ }
+ }
+
+ public static unsafe string mono_string_from_godot(godot_string* p_string)
+ {
+ if ((*p_string)._ptr == IntPtr.Zero)
+ return string.Empty;
+
+ const int sizeOfChar32 = 4;
+ byte* bytes = (byte*)(*p_string)._ptr;
+ int size = *((int*)(*p_string)._ptr - 1);
+ if (size == 0)
+ return string.Empty;
+ size -= 1; // zero at the end
+ int sizeInBytes = size * sizeOfChar32;
+ return System.Text.Encoding.UTF32.GetString(bytes, sizeInBytes);
+ }
+
+ // Callable
+
+ public static godot_callable ConvertCallableToNative(ref 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;
+ }
+ }
+ else
+ {
+ unsafe
+ {
+ 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()
+ };
+ }
+ }
+ }
+
+ public static unsafe Callable ConvertCallableToManaged(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))
+ {
+ if (delegateGCHandle != IntPtr.Zero)
+ {
+ return new Callable((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target);
+ }
+ else
+ {
+ return new Callable(
+ InteropUtils.UnmanagedGetManaged(godotObject),
+ StringName.CreateTakingOwnershipOfDisposableValue(name));
+ }
+ }
+
+ // Some other unsupported callable
+ return new Callable();
+ }
+
+ // SignalInfo
+
+ 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 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
+ };
+ }
+ }
+
+ public static unsafe SignalInfo ConvertSignalToManaged(godot_signal* p_signal)
+ {
+ var owner = GD.InstanceFromId((*p_signal)._objectId);
+ var name = StringName.CreateTakingOwnershipOfDisposableValue(
+ 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)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = new object[length];
+
+ array.CopyTo(ret, 0); // variant_to_mono_object handled by Collections.Array
+
+ return ret;
+ }
+
+ public static unsafe object Array_to_mono_array_of_type(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);
+
+ array.CopyTo((object[])ret, 0); // variant_to_mono_object handled by Collections.Array
+
+ return ret;
+ }
+
+ public static godot_array mono_array_to_Array(Span<object> p_array)
+ {
+ if (p_array.IsEmpty)
+ {
+ godot_array ret;
+ Collections.Array.godot_icall_Array_Ctor(out ret);
+ return ret;
+ }
+
+ using var array = new Collections.Array();
+ array.Resize(p_array.Length);
+
+ for (int i = 0; i < p_array.Length; i++)
+ array[i] = p_array[i];
+
+ godot_array src = array.NativeValue;
+ unsafe
+ {
+ return NativeFuncs.godotsharp_array_new_copy(&src);
+ }
+ }
+
+ // PackedByteArray
+
+ public static unsafe byte[] PackedByteArray_to_mono_array(godot_packed_byte_array* p_array)
+ {
+ byte* buffer = (byte*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ 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<byte> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_byte_array();
+ fixed (byte* src = p_array)
+ return NativeFuncs.godotsharp_packed_byte_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedInt32Array
+
+ public static unsafe int[] PackedInt32Array_to_mono_array(godot_packed_int32_array* p_array)
+ {
+ int* buffer = (int*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(int);
+ var array = new int[size];
+ fixed (int* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_int32_array mono_array_to_PackedInt32Array(Span<int> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_int32_array();
+ fixed (int* src = p_array)
+ return NativeFuncs.godotsharp_packed_int32_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedInt64Array
+
+ public static unsafe long[] PackedInt64Array_to_mono_array(godot_packed_int64_array* p_array)
+ {
+ long* buffer = (long*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(long);
+ var array = new long[size];
+ fixed (long* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_int64_array mono_array_to_PackedInt64Array(Span<long> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_int64_array();
+ fixed (long* src = p_array)
+ return NativeFuncs.godotsharp_packed_int64_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedFloat32Array
+
+ public static unsafe float[] PackedFloat32Array_to_mono_array(godot_packed_float32_array* p_array)
+ {
+ float* buffer = (float*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(float);
+ var array = new float[size];
+ fixed (float* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_float32_array mono_array_to_PackedFloat32Array(Span<float> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_float32_array();
+ fixed (float* src = p_array)
+ return NativeFuncs.godotsharp_packed_float32_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedFloat64Array
+
+ public static unsafe double[] PackedFloat64Array_to_mono_array(godot_packed_float64_array* p_array)
+ {
+ double* buffer = (double*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(double);
+ var array = new double[size];
+ fixed (double* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_float64_array mono_array_to_PackedFloat64Array(Span<double> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_float64_array();
+ fixed (double* src = p_array)
+ return NativeFuncs.godotsharp_packed_float64_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedStringArray
+
+ public static unsafe string[] PackedStringArray_to_mono_array(godot_packed_string_array* p_array)
+ {
+ godot_string* buffer = (godot_string*)(*p_array)._ptr;
+ if (buffer == null)
+ return new string[] { };
+ int size = *((int*)(*p_array)._ptr - 1);
+ var array = new string[size];
+ for (int i = 0; i < size; i++)
+ array[i] = mono_string_from_godot(&buffer[i]);
+ return array;
+ }
+
+ public static unsafe godot_packed_string_array mono_array_to_PackedStringArray(Span<string> p_array)
+ {
+ godot_packed_string_array dest = new godot_packed_string_array();
+
+ if (p_array.IsEmpty)
+ return dest;
+
+ /* TODO: Replace godotsharp_packed_string_array_add with a single internal call to
+ get the write address. We can't use `dest._ptr` directly for writing due to COW. */
+
+ 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);
+ }
+
+ return dest;
+ }
+
+ // PackedVector2Array
+
+ public static unsafe Vector2[] PackedVector2Array_to_mono_array(godot_packed_vector2_array* p_array)
+ {
+ Vector2* buffer = (Vector2*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(Vector2);
+ var array = new Vector2[size];
+ fixed (Vector2* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_vector2_array mono_array_to_PackedVector2Array(Span<Vector2> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_vector2_array();
+ fixed (Vector2* src = p_array)
+ return NativeFuncs.godotsharp_packed_vector2_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedVector3Array
+
+ public static unsafe Vector3[] PackedVector3Array_to_mono_array(godot_packed_vector3_array* p_array)
+ {
+ Vector3* buffer = (Vector3*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(Vector3);
+ var array = new Vector3[size];
+ fixed (Vector3* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_vector3_array mono_array_to_PackedVector3Array(Span<Vector3> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_vector3_array();
+ fixed (Vector3* src = p_array)
+ return NativeFuncs.godotsharp_packed_vector3_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedColorArray
+
+ public static unsafe Color[] PackedColorArray_to_mono_array(godot_packed_color_array* p_array)
+ {
+ Color* buffer = (Color*)(*p_array)._ptr;
+ int size = *((int*)(*p_array)._ptr - 1);
+ int sizeInBytes = size * sizeof(Color);
+ var array = new Color[size];
+ fixed (Color* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_color_array mono_array_to_PackedColorArray(Span<Color> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_color_array();
+ fixed (Color* src = p_array)
+ return NativeFuncs.godotsharp_packed_color_array_new_mem_copy(src, p_array.Length);
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
new file mode 100644
index 0000000000..2f1056219d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -0,0 +1,346 @@
+using System;
+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
+ internal static unsafe partial class NativeFuncs
+ {
+ private const string GodotDllName = "__Internal";
+
+ // Custom functions
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname, char* p_methodname);
+
+#if NET
+ [DllImport(GodotDllName)]
+ public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(ref godot_string_name p_classname);
+#else
+ // Workaround until we switch to .NET 5/6
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_get_class_constructor(ref godot_string_name p_classname);
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_invoke_class_constructor(IntPtr p_creation_func);
+#endif
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name);
+
+ [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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_node_path_new_from_string(godot_node_path* dest, godot_string* name);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_string_name_as_string(godot_string* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_int32_array godotsharp_packed_int32_array_new_mem_copy(int* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_int64_array godotsharp_packed_int64_array_new_mem_copy(long* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_float32_array godotsharp_packed_float32_array_new_mem_copy(float* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_float64_array godotsharp_packed_float64_array_new_mem_copy(double* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_vector2_array godotsharp_packed_vector2_array_new_mem_copy(Vector2* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_vector3_array godotsharp_packed_vector3_array_new_mem_copy(Vector3* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_color_array godotsharp_packed_color_array_new_mem_copy(Color* p_src, int p_length);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_string_array_add(godot_packed_string_array* r_dest, godot_string* p_element);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, godot_callable* r_callable);
+
+ [DllImport(GodotDllName)]
+ public static extern bool godotsharp_callable_get_data_for_marshalling(godot_callable* p_callable, IntPtr* r_delegate_handle, IntPtr* r_object, godot_string_name* r_name);
+
+ // GDNative functions
+
+ // gdnative.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_method_bind_ptrcall(IntPtr p_method_bind, IntPtr p_instance, void** p_args, void* p_ret);
+
+ [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);
+
+ // variant.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_string_name(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_object(godot_variant* r_dest, IntPtr p_obj);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_transform2d(godot_variant* r_dest, Transform2D* p_t2d);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_vector4(godot_variant* r_dest, Vector4* p_vec4);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_vector4i(godot_variant* r_dest, Vector4i* p_vec4i);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_basis(godot_variant* r_dest, Basis* p_basis);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_transform3d(godot_variant* r_dest, Transform3D* p_trans);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_projection(godot_variant* r_dest, Projection* p_proj);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_aabb(godot_variant* r_dest, AABB* p_aabb);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_dictionary(godot_variant* r_dest, godot_dictionary* p_dict);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_array(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_packed_int32_array(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_packed_float32_array(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_packed_string_array(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_new_packed_vector3_array(godot_variant* r_dest, 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);
+
+ [DllImport(GodotDllName)]
+ public static extern bool godotsharp_variant_as_bool(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Int64 godotsharp_variant_as_int(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern double godotsharp_variant_as_float(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_string godotsharp_variant_as_string(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector2 godotsharp_variant_as_vector2(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector2i godotsharp_variant_as_vector2i(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Rect2 godotsharp_variant_as_rect2(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Rect2i godotsharp_variant_as_rect2i(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector3 godotsharp_variant_as_vector3(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector3i godotsharp_variant_as_vector3i(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Transform2D godotsharp_variant_as_transform2d(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector4 godotsharp_variant_as_vector4(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Vector4i godotsharp_variant_as_vector4i(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Plane godotsharp_variant_as_plane(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Quaternion godotsharp_variant_as_quaternion(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern AABB godotsharp_variant_as_aabb(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Basis godotsharp_variant_as_basis(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Transform3D godotsharp_variant_as_transform3d(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Projection godotsharp_variant_as_projection(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern Color godotsharp_variant_as_color(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_string_name godotsharp_variant_as_string_name(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_node_path godotsharp_variant_as_node_path(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern RID godotsharp_variant_as_rid(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_callable godotsharp_variant_as_callable(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_signal godotsharp_variant_as_signal(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_dictionary godotsharp_variant_as_dictionary(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_array godotsharp_variant_as_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_float32_array godotsharp_variant_as_packed_float32_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_float64_array godotsharp_variant_as_packed_float64_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array(godot_variant* p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(godot_variant* p_self);
+
+ // string.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_string_new_with_utf16_chars(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);
+
+ // node_path.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_node_path_new_copy(godot_node_path* r_dest, godot_node_path* p_src);
+
+ // array.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_array_new_copy(godot_array* r_dest, godot_array* p_src);
+
+ // dictionary.h
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_dictionary_new_copy(godot_dictionary* r_dest, godot_dictionary* p_src);
+
+ // destroy functions
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_byte_array_destroy(ref godot_packed_byte_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_int32_array_destroy(ref godot_packed_int32_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_int64_array_destroy(ref godot_packed_int64_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_float32_array_destroy(ref godot_packed_float32_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_float64_array_destroy(ref godot_packed_float64_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_string_array_destroy(ref godot_packed_string_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_vector2_array_destroy(ref godot_packed_vector2_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_vector3_array_destroy(ref godot_packed_vector3_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_packed_color_array_destroy(ref godot_packed_color_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_variant_destroy(ref godot_variant p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_string_destroy(ref godot_string p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_string_name_destroy(ref godot_string_name p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_node_path_destroy(ref godot_node_path p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_signal_destroy(ref godot_signal p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_callable_destroy(ref godot_callable p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_array_destroy(ref godot_array p_self);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_dictionary_destroy(ref godot_dictionary p_self);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
new file mode 100644
index 0000000000..70df79c1de
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Runtime.CompilerServices;
+
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ internal static unsafe partial class NativeFuncs
+ {
+ public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src)
+ {
+ godot_string_name ret;
+ godotsharp_string_name_new_copy(&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)
+ {
+ godot_node_path ret;
+ godotsharp_node_path_new_copy(&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_copy(godot_array* src)
+ {
+ godot_array ret;
+ godotsharp_array_new_copy(&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_copy(godot_dictionary* src)
+ {
+ godot_dictionary ret;
+ godotsharp_dictionary_new_copy(&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);
+ 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);
+ return ret;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
new file mode 100644
index 0000000000..2814f9d506
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Godot.NativeInterop
+{
+ internal ref struct VariantSpanDisposer
+ {
+ private readonly Span<godot_variant> _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<godot_variant> variantSpan)
+ {
+ _variantSpan = variantSpan;
+ }
+
+ public void Dispose()
+ {
+ for (int i = 0; i < _variantSpan.Length; i++)
+ _variantSpan[i].Dispose();
+ }
+ }
+
+ internal static class VariantSpanExtensions
+ {
+ // 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<godot_variant> Cleared(this Span<godot_variant> 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
new file mode 100644
index 0000000000..67f9e23893
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -0,0 +1,335 @@
+using System;
+using System.Runtime.CompilerServices;
+
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ internal static class VariantUtils
+ {
+ public static godot_variant CreateFromRID(RID from)
+ => new() {_type = Variant.Type.Rid, _data = {_m_rid = from}};
+
+ public static godot_variant CreateFromBool(bool from)
+ => new() {_type = Variant.Type.Bool, _data = {_bool = from}};
+
+ public static godot_variant CreateFromInt(long from)
+ => new() {_type = Variant.Type.Int, _data = {_int = from}};
+
+ public static godot_variant CreateFromInt(ulong from)
+ => new() {_type = Variant.Type.Int, _data = {_int = (long)from}};
+
+ public static godot_variant CreateFromFloat(double from)
+ => new() {_type = Variant.Type.Float, _data = {_float = from}};
+
+ public static godot_variant CreateFromVector2(Vector2 from)
+ => new() {_type = Variant.Type.Vector2, _data = {_m_vector2 = from}};
+
+ public static godot_variant CreateFromVector2i(Vector2i from)
+ => new() {_type = Variant.Type.Vector2i, _data = {_m_vector2i = from}};
+
+ public static godot_variant CreateFromVector3(Vector3 from)
+ => new() {_type = Variant.Type.Vector3, _data = {_m_vector3 = from}};
+
+ public static godot_variant CreateFromVector3i(Vector3i from)
+ => new() {_type = Variant.Type.Vector3i, _data = {_m_vector3i = from}};
+
+ public static godot_variant CreateFromRect2(Rect2 from)
+ => new() {_type = Variant.Type.Rect2, _data = {_m_rect2 = from}};
+
+ public static godot_variant CreateFromRect2i(Rect2i from)
+ => new() {_type = Variant.Type.Rect2i, _data = {_m_rect2i = from}};
+
+ public static godot_variant CreateFromQuaternion(Quaternion from)
+ => new() {_type = Variant.Type.Quaternion, _data = {_m_quaternion = from}};
+
+ public static godot_variant CreateFromColor(Color from)
+ => new() {_type = Variant.Type.Color, _data = {_m_color = from}};
+
+ public static godot_variant CreateFromPlane(Plane from)
+ => new() {_type = Variant.Type.Plane, _data = {_m_plane = from}};
+
+ public static unsafe godot_variant CreateFromTransform2D(Transform2D from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_transform2d(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromVector4(Vector4 from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_vector4(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromVector4i(Vector4i from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_vector4i(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromBasis(Basis from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_basis(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromTransform3D(Transform3D from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_transform3d(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromProjection(Projection from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_projection(&ret, &from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromAABB(AABB from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_aabb(&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}};
+
+ // Explicit name to make it very clear
+ public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from)
+ => new() {_type = Variant.Type.Signal, _data = {_m_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}};
+
+ public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_byte_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedInt32Array(godot_packed_int32_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_int32_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedInt64Array(godot_packed_int64_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_int64_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedFloat32Array(godot_packed_float32_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_float32_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedFloat64Array(godot_packed_float64_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_float64_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedStringArray(godot_packed_string_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_string_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedVector2Array(godot_packed_vector2_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_vector2_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedVector3Array(godot_packed_vector3_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_vector3_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromPackedColorArray(godot_packed_color_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_packed_color_array(&ret, from);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromArray(godot_array* from)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_array(&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)
+ {
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_dictionary(&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)
+ {
+ godot_variant ret;
+ godot_string_name src = arg1;
+ NativeFuncs.godotsharp_variant_new_string_name(&ret, &src);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromNodePath(ref godot_node_path arg1)
+ {
+ godot_variant ret;
+ godot_node_path src = arg1;
+ NativeFuncs.godotsharp_variant_new_node_path(&ret, &src);
+ return ret;
+ }
+
+ public static unsafe godot_variant CreateFromGodotObject(IntPtr from)
+ {
+ if (from == IntPtr.Zero)
+ return new godot_variant();
+ godot_variant ret;
+ NativeFuncs.godotsharp_variant_new_object(&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 : NativeFuncs.godotsharp_variant_as_bool(p_var);
+
+ public static unsafe char ConvertToChar(godot_variant* p_var)
+ => (char)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._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 : 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 : 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 : 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 unsafe byte ConvertToUInt8(godot_variant* p_var)
+ => (byte)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 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 Basis ConvertToBasis(godot_variant* p_var)
+ => (*p_var)._type == Variant.Type.Basis ? *(*p_var)._data._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 : 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 : 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 AABB ConvertToAABB(godot_variant* p_var)
+ => (*p_var)._type == Variant.Type.Aabb ? *(*p_var)._data._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 : 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 : 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 unsafe RID ConvertToRID(godot_variant* p_var)
+ => (*p_var)._type == Variant.Type.Rid ? (*p_var)._data._m_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) :
+ 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) :
+ 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) :
+ 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) :
+ 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 9ae01016cb..90e51e8a1a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -39,22 +40,9 @@ namespace Godot
/// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
/// </code>
/// </example>
- public sealed partial class NodePath : IDisposable
+ public sealed class NodePath : IDisposable
{
- private bool _disposed = false;
-
- private IntPtr ptr;
-
- internal static IntPtr GetPtr(NodePath instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null.");
-
- if (instance._disposed)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
+ internal godot_node_path NativeValue;
~NodePath()
{
@@ -70,29 +58,27 @@ namespace Godot
GC.SuppressFinalize(this);
}
- private void Dispose(bool disposing)
+ public void Dispose(bool disposing)
{
- if (_disposed)
- return;
-
- if (ptr != IntPtr.Zero)
- {
- godot_icall_NodePath_Dtor(ptr);
- ptr = IntPtr.Zero;
- }
-
- _disposed = true;
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.Dispose();
}
- internal NodePath(IntPtr ptr)
+ private NodePath(godot_node_path nativeValueToOwn)
{
- this.ptr = ptr;
+ NativeValue = nativeValueToOwn;
}
+ // Explicit name to make it very clear
+ internal static NodePath CreateTakingOwnershipOfDisposableValue(godot_node_path nativeValueToOwn)
+ => new NodePath(nativeValueToOwn);
+
/// <summary>
/// Constructs an empty <see cref="NodePath"/>.
/// </summary>
- public NodePath() : this(string.Empty) { }
+ public NodePath()
+ {
+ }
/// <summary>
/// Constructs a <see cref="NodePath"/> from a string <paramref name="path"/>,
@@ -125,7 +111,8 @@ namespace Godot
/// <param name="path">A string that represents a path in a scene tree.</param>
public NodePath(string path)
{
- ptr = godot_icall_NodePath_Ctor(path);
+ if (!string.IsNullOrEmpty(path))
+ NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path);
}
/// <summary>
@@ -144,9 +131,16 @@ namespace Godot
/// Converts this <see cref="NodePath"/> to a string.
/// </summary>
/// <returns>A string representation of this <see cref="NodePath"/>.</returns>
- public override string ToString()
+ public override unsafe string ToString()
{
- return godot_icall_NodePath_operator_String(GetPtr(this));
+ if (IsEmpty)
+ return string.Empty;
+
+ godot_string dest;
+ godot_node_path src = NativeValue;
+ NativeFuncs.godotsharp_node_path_as_string(&dest, &src);
+ using (dest)
+ return Marshaling.mono_string_from_godot(&dest);
}
/// <summary>
@@ -166,7 +160,9 @@ namespace Godot
/// <returns>The <see cref="NodePath"/> as a pure property path.</returns>
public NodePath GetAsPropertyPath()
{
- return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this)));
+ godot_node_path propertyPath = default;
+ godot_icall_NodePath_get_as_property_path(ref NativeValue, ref propertyPath);
+ return CreateTakingOwnershipOfDisposableValue(propertyPath);
}
/// <summary>
@@ -181,7 +177,7 @@ namespace Godot
/// <returns>The names concatenated with <c>/</c>.</returns>
public string GetConcatenatedNames()
{
- return godot_icall_NodePath_get_concatenated_names(GetPtr(this));
+ return godot_icall_NodePath_get_concatenated_names(ref NativeValue);
}
/// <summary>
@@ -195,9 +191,9 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The subnames concatenated with <c>:</c>.</returns>
- public string GetConcatenatedSubnames()
+ public string GetConcatenatedSubNames()
{
- return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this));
+ return godot_icall_NodePath_get_concatenated_subnames(ref NativeValue);
}
/// <summary>
@@ -215,28 +211,28 @@ namespace Godot
/// <returns>The name at the given index <paramref name="idx"/>.</returns>
public string GetName(int idx)
{
- return godot_icall_NodePath_get_name(GetPtr(this), idx);
+ return godot_icall_NodePath_get_name(ref NativeValue, idx);
}
/// <summary>
/// Gets the number of node names which make up the path.
- /// Subnames (see <see cref="GetSubnameCount"/>) are not included.
+ /// Subnames (see <see cref="GetSubNameCount"/>) are not included.
/// For example, <c>"Path2D/PathFollow2D/Sprite2D"</c> has 3 names.
/// </summary>
/// <returns>The number of node names which make up the path.</returns>
public int GetNameCount()
{
- return godot_icall_NodePath_get_name_count(GetPtr(this));
+ return godot_icall_NodePath_get_name_count(ref NativeValue);
}
/// <summary>
- /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubnameCount"/>).
+ /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubNameCount"/>).
/// </summary>
/// <param name="idx">The subname index.</param>
/// <returns>The subname at the given index <paramref name="idx"/>.</returns>
- public string GetSubname(int idx)
+ public string GetSubName(int idx)
{
- return godot_icall_NodePath_get_subname(GetPtr(this), idx);
+ return godot_icall_NodePath_get_subname(ref NativeValue, idx);
}
/// <summary>
@@ -245,9 +241,9 @@ namespace Godot
/// For example, <c>"Path2D/PathFollow2D/Sprite2D:texture:load_path"</c> has 2 subnames.
/// </summary>
/// <returns>The number of subnames in the path.</returns>
- public int GetSubnameCount()
+ public int GetSubNameCount()
{
- return godot_icall_NodePath_get_subname_count(GetPtr(this));
+ return godot_icall_NodePath_get_subname_count(ref NativeValue);
}
/// <summary>
@@ -259,52 +255,37 @@ namespace Godot
/// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
public bool IsAbsolute()
{
- return godot_icall_NodePath_is_absolute(GetPtr(this));
+ return godot_icall_NodePath_is_absolute(ref NativeValue);
}
/// <summary>
/// Returns <see langword="true"/> if the node path is empty.
/// </summary>
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
- public bool IsEmpty()
- {
- return godot_icall_NodePath_is_empty(GetPtr(this));
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_NodePath_Ctor(string path);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void godot_icall_NodePath_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_operator_String(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
+ public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_concatenated_names(IntPtr ptr);
+ private static extern void godot_icall_NodePath_get_as_property_path(ref godot_node_path ptr, ref godot_node_path dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
+ private static extern string godot_icall_NodePath_get_concatenated_names(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
+ private static extern string godot_icall_NodePath_get_concatenated_subnames(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr);
+ private static extern string godot_icall_NodePath_get_name(ref godot_node_path ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
+ private static extern int godot_icall_NodePath_get_name_count(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr);
+ private static extern string godot_icall_NodePath_get_subname(ref godot_node_path ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_NodePath_is_absolute(IntPtr ptr);
+ private static extern int godot_icall_NodePath_get_subname_count(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_NodePath_is_empty(IntPtr ptr);
+ private static extern bool godot_icall_NodePath_is_absolute(ref godot_node_path ptr);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 746612477d..80d63581c1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -7,38 +7,44 @@ namespace Godot
{
private bool _disposed = false;
- private static StringName nativeName = "Object";
-
- internal IntPtr ptr;
- internal bool memoryOwn;
+ internal IntPtr NativePtr;
+ internal bool MemoryOwn;
/// <summary>
/// Constructs a new <see cref="Object"/>.
/// </summary>
public Object() : this(false)
{
- if (ptr == IntPtr.Zero)
- ptr = godot_icall_Object_Ctor(this);
+ if (NativePtr == IntPtr.Zero)
+ {
+#if NET
+ unsafe
+ {
+ ptr = NativeCtor();
+ }
+#else
+ NativePtr = _gd__invoke_class_constructor(NativeCtor);
+#endif
+ NativeInterop.InteropUtils.TieManagedToUnmanaged(this, NativePtr);
+ }
+
_InitializeGodotScriptInstanceInternals();
}
internal void _InitializeGodotScriptInstanceInternals()
{
- godot_icall_Object_ConnectEventSignals(ptr);
+ godot_icall_Object_ConnectEventSignals(NativePtr);
}
internal Object(bool memoryOwn)
{
- this.memoryOwn = memoryOwn;
+ this.MemoryOwn = memoryOwn;
}
/// <summary>
/// The pointer to the native instance of this <see cref="Object"/>.
/// </summary>
- public IntPtr NativeInstance
- {
- get { return ptr; }
- }
+ public IntPtr NativeInstance => NativePtr;
internal static IntPtr GetPtr(Object instance)
{
@@ -48,7 +54,7 @@ namespace Godot
if (instance._disposed)
throw new ObjectDisposedException(instance.GetType().FullName);
- return instance.ptr;
+ return instance.NativePtr;
}
~Object()
@@ -73,19 +79,19 @@ namespace Godot
if (_disposed)
return;
- if (ptr != IntPtr.Zero)
+ if (NativePtr != IntPtr.Zero)
{
- if (memoryOwn)
+ if (MemoryOwn)
{
- memoryOwn = false;
- godot_icall_RefCounted_Disposed(this, ptr, !disposing);
+ MemoryOwn = false;
+ godot_icall_RefCounted_Disposed(this, NativePtr, !disposing);
}
else
{
- godot_icall_Object_Disposed(this, ptr);
+ godot_icall_Object_Disposed(this, NativePtr);
}
- ptr = IntPtr.Zero;
+ this.NativePtr = IntPtr.Zero;
}
_disposed = true;
@@ -137,13 +143,49 @@ namespace Godot
/// </summary>
public dynamic DynamicObject => new DynamicGodotObject(this);
- internal static IntPtr __ClassDB_get_method(StringName type, string method)
+ internal static unsafe IntPtr ClassDB_get_method(StringName type, string method)
+ {
+ IntPtr methodBind;
+ fixed (char* methodChars = method)
+ {
+ methodBind = NativeInterop.NativeFuncs
+ .godotsharp_method_bind_get_method(ref type.NativeValue, methodChars);
+ }
+
+ if (methodBind == IntPtr.Zero)
+ throw new NativeMethodBindNotFoundException(type + "." + method);
+
+ return methodBind;
+ }
+
+#if NET
+ internal static unsafe delegate* unmanaged<IntPtr> _gd__ClassDB_get_constructor(StringName type)
+ {
+ // for some reason the '??' operator doesn't support 'delegate*'
+ var nativeConstructor = NativeInterop.NativeFuncs
+ .godotsharp_get_class_constructor(ref type.NativeValue);
+
+ if (nativeConstructor == null)
+ throw new NativeConstructorNotFoundException(type);
+
+ return nativeConstructor;
+ }
+#else
+ internal static IntPtr ClassDB_get_constructor(StringName type)
{
- return godot_icall_Object_ClassDB_get_method(StringName.GetPtr(type), method);
+ // for some reason the '??' operator doesn't support 'delegate*'
+ var nativeConstructor = NativeInterop.NativeFuncs
+ .godotsharp_get_class_constructor(ref type.NativeValue);
+
+ if (nativeConstructor == IntPtr.Zero)
+ throw new NativeConstructorNotFoundException(type);
+
+ return nativeConstructor;
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Object_Ctor(Object obj);
+ internal static IntPtr _gd__invoke_class_constructor(IntPtr ctorFuncPtr)
+ => NativeInterop.NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr);
+#endif
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
@@ -156,9 +198,5 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern string godot_icall_Object_ToString(IntPtr ptr);
-
- // Used by the generated API
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Object_ClassDB_get_method(IntPtr type, string method);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
new file mode 100644
index 0000000000..eb2811c73d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
@@ -0,0 +1,135 @@
+using System;
+
+#nullable enable
+
+namespace Godot
+{
+ public partial class Object
+ {
+ public class NativeMemberNotFoundException : Exception
+ {
+ public NativeMemberNotFoundException()
+ {
+ }
+
+ public NativeMemberNotFoundException(string? message) : base(message)
+ {
+ }
+
+ public NativeMemberNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+
+ public class NativeConstructorNotFoundException : NativeMemberNotFoundException
+ {
+ private readonly string? _nativeClassName;
+
+ // ReSharper disable once InconsistentNaming
+ private const string Arg_NativeConstructorNotFoundException = "Unable to find the native constructor.";
+
+ public NativeConstructorNotFoundException()
+ : base(Arg_NativeConstructorNotFoundException)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? nativeClassName)
+ : this(Arg_NativeConstructorNotFoundException, nativeClassName)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? message, string? nativeClassName)
+ : base(message)
+ {
+ _nativeClassName = nativeClassName;
+ }
+
+ public NativeConstructorNotFoundException(string? message, string? nativeClassName, Exception? innerException)
+ : base(message, innerException)
+ {
+ _nativeClassName = nativeClassName;
+ }
+
+ public override string Message
+ {
+ get
+ {
+ string s = base.Message;
+
+ if (string.IsNullOrEmpty(s))
+ {
+ s = Arg_NativeConstructorNotFoundException;
+ }
+
+ if (!string.IsNullOrEmpty(_nativeClassName))
+ {
+ s += " " + string.Format("(Class '{0}')", _nativeClassName);
+ }
+
+ return s;
+ }
+ }
+ }
+
+ public class NativeMethodBindNotFoundException : NativeMemberNotFoundException
+ {
+ private readonly string? _nativeMethodName;
+
+ // ReSharper disable once InconsistentNaming
+ private const string Arg_NativeMethodBindNotFoundException = "Unable to find the native method bind.";
+
+ public NativeMethodBindNotFoundException()
+ : base(Arg_NativeMethodBindNotFoundException)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? nativeMethodName)
+ : this(Arg_NativeMethodBindNotFoundException, nativeMethodName)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? message, string? nativeMethodName)
+ : base(message)
+ {
+ _nativeMethodName = nativeMethodName;
+ }
+
+ public NativeMethodBindNotFoundException(string? message, string? nativeMethodName, Exception? innerException)
+ : base(message, innerException)
+ {
+ _nativeMethodName = nativeMethodName;
+ }
+
+ public override string Message
+ {
+ get
+ {
+ string s = base.Message;
+
+ if (string.IsNullOrEmpty(s))
+ {
+ s = Arg_NativeMethodBindNotFoundException;
+ }
+
+ if (!string.IsNullOrEmpty(_nativeMethodName))
+ {
+ s += " " + string.Format("(Method '{0}')", _nativeMethodName);
+ }
+
+ return s;
+ }
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
index 1588869ec0..a31fef8360 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
@@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -9,99 +11,32 @@ namespace Godot
/// resource by themselves. They are used by and with the low-level Server
/// classes such as <see cref="RenderingServer"/>.
/// </summary>
- public sealed partial class RID : IDisposable
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RID
{
- private bool _disposed = false;
+ private ulong _id; // Default is 0
- internal IntPtr ptr;
-
- internal static IntPtr GetPtr(RID instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(RID)} is null.");
-
- if (instance._disposed)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
-
- ~RID()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// Disposes of this <see cref="RID"/>.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (_disposed)
- return;
-
- if (ptr != IntPtr.Zero)
- {
- godot_icall_RID_Dtor(ptr);
- ptr = IntPtr.Zero;
- }
-
- _disposed = true;
- }
-
- internal RID(IntPtr ptr)
+ internal RID(ulong id)
{
- this.ptr = ptr;
- }
-
- /// <summary>
- /// The pointer to the native instance of this <see cref="RID"/>.
- /// </summary>
- public IntPtr NativeInstance
- {
- get { return ptr; }
- }
-
- internal RID()
- {
- this.ptr = IntPtr.Zero;
+ _id = id;
}
/// <summary>
/// Constructs a new <see cref="RID"/> for the given <see cref="Object"/> <paramref name="from"/>.
/// </summary>
public RID(Object from)
- {
- this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from));
- }
+ => _id = from is Resource res ? res.GetRid()._id : default;
/// <summary>
/// Returns the ID of the referenced resource.
/// </summary>
/// <returns>The ID of the referenced resource.</returns>
- public int GetId()
- {
- return godot_icall_RID_get_id(GetPtr(this));
- }
+ public ulong Id => _id;
/// <summary>
/// Converts this <see cref="RID"/> to a string.
/// </summary>
/// <returns>A string representation of this RID.</returns>
- public override string ToString() => "[RID]";
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_RID_Ctor(IntPtr from);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_RID_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_RID_get_id(IntPtr ptr);
+ public override string ToString() => $"RID({Id})";
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index 2ba0493002..e485207fb4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -11,34 +12,22 @@ namespace Godot
public SignalAwaiter(Object source, StringName signal, Object target)
{
- godot_icall_SignalAwaiter_connect(Object.GetPtr(source), StringName.GetPtr(signal), Object.GetPtr(target), this);
+ godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue, Object.GetPtr(target), this);
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter);
+ internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal, IntPtr target, SignalAwaiter awaiter);
- public bool IsCompleted
- {
- get
- {
- return _completed;
- }
- }
+ public bool IsCompleted => _completed;
public void OnCompleted(Action action)
{
this._action = action;
}
- public object[] GetResult()
- {
- return _result;
- }
+ public object[] GetResult() => _result;
- public IAwaiter<object[]> GetAwaiter()
- {
- return this;
- }
+ public IAwaiter<object[]> GetAwaiter() => this;
internal void SignalCallback(object[] args)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index a1f058ffe5..058c5447e2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -214,7 +214,7 @@ namespace Godot
/// <returns>The escaped string.</returns>
public static string CEscape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\", "\\\\");
sb.Replace("\a", "\\a");
@@ -239,7 +239,7 @@ namespace Godot
/// <returns>The unescaped string.</returns>
public static string CUnescape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\a", "\a");
sb.Replace("\\b", "\b");
@@ -926,7 +926,7 @@ namespace Godot
/// <returns>The escaped string.</returns>
public static string JSONEscape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\", "\\\\");
sb.Replace("\b", "\\b");
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index b1d504410b..40d282eab4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -10,20 +11,9 @@ namespace Godot
/// Comparing them is much faster than with regular strings, because only the pointers are compared,
/// not the whole strings.
/// </summary>
- public sealed partial class StringName : IDisposable
+ public sealed class StringName : IDisposable
{
- private IntPtr ptr;
-
- internal static IntPtr GetPtr(StringName instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(StringName)} is null.");
-
- if (instance.ptr == IntPtr.Zero)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
+ internal godot_string_name NativeValue;
~StringName()
{
@@ -39,35 +29,36 @@ namespace Godot
GC.SuppressFinalize(this);
}
- private void Dispose(bool disposing)
+ public void Dispose(bool disposing)
{
- if (ptr != IntPtr.Zero)
- {
- godot_icall_StringName_Dtor(ptr);
- ptr = IntPtr.Zero;
- }
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.Dispose();
}
- internal StringName(IntPtr ptr)
+ private StringName(godot_string_name nativeValueToOwn)
{
- this.ptr = ptr;
+ NativeValue = nativeValueToOwn;
}
+ // Explicit name to make it very clear
+ internal static StringName CreateTakingOwnershipOfDisposableValue(godot_string_name nativeValueToOwn)
+ => new StringName(nativeValueToOwn);
+
/// <summary>
/// Constructs an empty <see cref="StringName"/>.
/// </summary>
public StringName()
{
- ptr = IntPtr.Zero;
}
/// <summary>
/// Constructs a <see cref="StringName"/> from the given <paramref name="path"/> string.
/// </summary>
/// <param name="path">String to construct the <see cref="StringName"/> from.</param>
- public StringName(string path)
+ public StringName(string name)
{
- ptr = path == null ? IntPtr.Zero : godot_icall_StringName_Ctor(path);
+ if (!string.IsNullOrEmpty(name))
+ NativeValue = NativeFuncs.godotsharp_string_name_new_from_string(name);
}
/// <summary>
@@ -86,30 +77,22 @@ namespace Godot
/// Converts this <see cref="StringName"/> to a string.
/// </summary>
/// <returns>A string representation of this <see cref="StringName"/>.</returns>
- public override string ToString()
+ public override unsafe string ToString()
{
- return ptr == IntPtr.Zero ? string.Empty : godot_icall_StringName_operator_String(GetPtr(this));
+ if (IsEmpty)
+ return string.Empty;
+
+ godot_string dest;
+ godot_string_name src = NativeValue;
+ NativeFuncs.godotsharp_string_name_as_string(&dest, &src);
+ using (dest)
+ return Marshaling.mono_string_from_godot(&dest);
}
/// <summary>
/// Check whether this <see cref="StringName"/> is empty.
/// </summary>
/// <returns>If the <see cref="StringName"/> is empty.</returns>
- public bool IsEmpty()
- {
- return ptr == IntPtr.Zero || godot_icall_StringName_is_empty(GetPtr(this));
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_StringName_Ctor(string path);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void godot_icall_StringName_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_StringName_operator_String(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_StringName_is_empty(IntPtr ptr);
+ public bool IsEmpty => godot_string_name.IsEmpty(in NativeValue);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 4f55ce47e8..9683d8e812 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -7,11 +7,20 @@
<TargetFramework>netstandard2.1</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <LangVersion>9</LangVersion>
+
+ <!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. -->
+ <NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
+ <!--PackageReference Include="IDisposableAnalyzers" Version="3.4.13" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /-->
+ </ItemGroup>
+ <ItemGroup>
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
@@ -47,14 +56,22 @@
<Compile Include="Core\MarshalUtils.cs" />
<Compile Include="Core\Mathf.cs" />
<Compile Include="Core\MathfEx.cs" />
+ <Compile Include="Core\NativeInterop\InteropUtils.cs" />
+ <Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
+ <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
+ <Compile Include="Core\NativeInterop\VariantUtils.cs" />
<Compile Include="Core\NodePath.cs" />
<Compile Include="Core\Object.base.cs" />
+ <Compile Include="Core\Object.exceptions.cs" />
<Compile Include="Core\Plane.cs" />
<Compile Include="Core\Projection.cs" />
<Compile Include="Core\Quaternion.cs" />
<Compile Include="Core\Rect2.cs" />
<Compile Include="Core\Rect2i.cs" />
<Compile Include="Core\RID.cs" />
+ <Compile Include="Core\NativeInterop\NativeFuncs.cs" />
+ <Compile Include="Core\NativeInterop\InteropStructs.cs" />
+ <Compile Include="Core\NativeInterop\Marshaling.cs" />
<Compile Include="Core\SignalInfo.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings
new file mode 100644
index 0000000000..1add6cc77e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings
@@ -0,0 +1,5 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=core/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean>
+</wpf:ResourceDictionary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index a8c4ba96b5..1082c74448 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -7,6 +7,8 @@
<TargetFramework>netstandard2.1</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings
new file mode 100644
index 0000000000..c7ff6fd3ee
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings
@@ -0,0 +1,4 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean>
+</wpf:ResourceDictionary>
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 7b9dbc87cf..05a8ef20f9 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include "core/object/class_db.h"
#include "core/object/ref_counted.h"
#include "core/string/string_name.h"
@@ -43,12 +41,6 @@
#include "../signal_awaiter_utils.h"
#include "arguments_vector.h"
-Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
- Object *instance = memnew(Object);
- GDMonoInternals::tie_managed_to_unmanaged(p_obj, instance);
- return instance;
-}
-
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
@@ -133,12 +125,6 @@ void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
}
}
-MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method) {
- StringName type = p_type ? *p_type : StringName();
- StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
- return ClassDB::get_method(type, method);
-}
-
MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
if (!p_ptr) {
return nullptr;
@@ -240,11 +226,9 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) {
}
void godot_register_object_icalls() {
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
@@ -253,5 +237,3 @@ void godot_register_object_icalls() {
GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 8a9f30459c..30adea60cc 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include <mono/metadata/exception.h>
#include "core/variant/array.h"
@@ -39,28 +37,17 @@
#include "../mono_gd/gd_mono_marshal.h"
#include "../mono_gd/gd_mono_utils.h"
-Array *godot_icall_Array_Ctor() {
- return memnew(Array);
-}
-
-void godot_icall_Array_Dtor(Array *ptr) {
- memdelete(ptr);
-}
-
-MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
- if (index < 0 || index >= ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
+void godot_icall_Array_Ctor(Array *r_dest) {
+ memnew_placement(r_dest, Array);
}
-MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
+void godot_icall_Array_At(Array *ptr, int32_t index, Variant *r_elem) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return nullptr;
+ *r_elem = Variant();
+ return;
}
- return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
+ *r_elem = ptr->operator[](index);
}
void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
@@ -104,29 +91,27 @@ void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index)
}
}
-Array *godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array) {
- Array *godot_array = memnew(Array);
+void godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array, Array *r_dest) {
+ memnew_placement(r_dest, Array);
unsigned int count = mono_array_length(mono_array);
- godot_array->resize(count);
+ r_dest->resize(count);
for (unsigned int i = 0; i < count; i++) {
MonoObject *item = mono_array_get(mono_array, MonoObject *, i);
- godot_icall_Array_SetAt(godot_array, i, item);
+ godot_icall_Array_SetAt(r_dest, i, item);
}
- return godot_array;
}
-Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) {
- return memnew(Array(ptr->duplicate(deep)));
+void godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep, Array *r_dest) {
+ memnew_placement(r_dest, Array(ptr->duplicate(deep)));
}
-Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
+void godot_icall_Array_Concatenate(Array *left, Array *right, Array *r_dest) {
int count = left->size() + right->size();
- Array *new_array = memnew(Array(left->duplicate(false)));
- new_array->resize(count);
+ memnew_placement(r_dest, Array(left->duplicate(false)));
+ r_dest->resize(count);
for (unsigned int i = 0; i < (unsigned int)right->size(); i++) {
- new_array->operator[](i + left->size()) = right->operator[](i);
+ r_dest->operator[](i + left->size()) = right->operator[](i);
}
- return new_array;
}
int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
@@ -166,41 +151,15 @@ void godot_icall_Array_Shuffle(Array *ptr) {
ptr->shuffle();
}
-void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
- MonoType *elem_type = mono_reflection_type_get_type(refltype);
-
- *type_encoding = mono_type_get_type(elem_type);
- MonoClass *type_class_raw = mono_class_from_mono_type(elem_type);
- *type_class = GDMono::get_singleton()->get_class(type_class_raw);
-}
-
MonoString *godot_icall_Array_ToString(Array *ptr) {
return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
}
-Dictionary *godot_icall_Dictionary_Ctor() {
- return memnew(Dictionary);
-}
-
-void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
- memdelete(ptr);
-}
-
-MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
-#ifdef DEBUG_ENABLED
- CRASH_COND(!exc);
-#endif
- GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
- GDMonoUtils::set_pending_exception((MonoException *)exc);
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ret);
+void godot_icall_Dictionary_Ctor(Dictionary *r_dest) {
+ memnew_placement(r_dest, Dictionary);
}
-MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
+void godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key, Variant *r_value) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == nullptr) {
MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
@@ -209,42 +168,37 @@ MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject
#endif
GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
GDMonoUtils::set_pending_exception((MonoException *)exc);
- return nullptr;
+ *r_value = Variant();
+ return;
}
- return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
+ *r_value = *ret;
}
void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
}
-Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
- return memnew(Array(ptr->keys()));
+void godot_icall_Dictionary_Keys(Dictionary *ptr, Array *r_dest) {
+ memnew_placement(r_dest, Array(ptr->keys()));
}
-Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
- return memnew(Array(ptr->values()));
+void godot_icall_Dictionary_Values(Dictionary *ptr, Array *r_dest) {
+ memnew_placement(r_dest, Array(ptr->values()));
}
int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
return ptr->size();
}
-int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) {
- *keys = godot_icall_Dictionary_Keys(ptr);
- *values = godot_icall_Dictionary_Values(ptr);
- return godot_icall_Dictionary_Count(ptr);
-}
-
-void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) {
- *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index));
- *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index));
+int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array *keys, Array *values) {
+ memnew_placement(keys, Array(ptr->keys()));
+ memnew_placement(values, Array(ptr->values()));
+ return ptr->size();
}
-void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) {
- ManagedType type(value_type_encoding, value_type_class);
- *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index));
- *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type);
+void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, Variant *r_key, Variant *r_value) {
+ memnew_placement(r_key, Variant(ptr->get_key_at_index(index)));
+ memnew_placement(r_value, Variant(ptr->get_value_at_index(index)));
}
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
@@ -271,8 +225,8 @@ MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key)
return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
}
-Dictionary *godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep) {
- return memnew(Dictionary(ptr->duplicate(deep)));
+void godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep, Dictionary *r_dest) {
+ memnew_placement(r_dest, Dictionary(ptr->duplicate(deep)));
}
MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
@@ -292,34 +246,16 @@ MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, Mono
return false;
}
-MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- *value = nullptr;
- return false;
- }
- *value = GDMonoMarshal::variant_to_mono_object(ret);
- return true;
-}
-
-MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, Variant *value) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == nullptr) {
- *value = nullptr;
+ *value = Variant();
return false;
}
- *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
+ *value = *ret;
return true;
}
-void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
- MonoType *value_type = mono_reflection_type_get_type(refltype);
-
- *type_encoding = mono_type_get_type(value_type);
- MonoClass *type_class_raw = mono_class_from_mono_type(value_type);
- *type_class = GDMono::get_singleton()->get_class(type_class_raw);
-}
-
MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
}
@@ -327,9 +263,7 @@ MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
void godot_register_collections_icalls() {
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
@@ -344,20 +278,16 @@ void godot_register_collections_icalls() {
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
@@ -366,9 +296,5 @@ void godot_register_collections_icalls() {
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 8b1c2b729e..b315831819 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include "core/io/marshalls.h"
#include "core/os/os.h"
#include "core/string/ustring.h"
@@ -41,10 +39,9 @@
#include "../mono_gd/gd_mono_marshal.h"
#include "../mono_gd/gd_mono_utils.h"
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
+MonoObject *godot_icall_GD_bytes2var(PackedByteArray *p_bytes, MonoBoolean p_allow_objects) {
Variant ret;
- PackedByteArray varr = GDMonoMarshal::mono_array_to_PackedByteArray(p_bytes);
- Error err = decode_variant(ret, varr.ptr(), varr.size(), nullptr, p_allow_objects);
+ Error err = decode_variant(ret, p_bytes->ptr(), p_bytes->size(), nullptr, p_allow_objects);
if (err != OK) {
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
}
@@ -285,18 +282,17 @@ void godot_icall_GD_pushwarning(MonoString *p_str) {
WARN_PRINT(GDMonoMarshal::mono_string_to_godot(p_str));
}
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
+void godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects, PackedByteArray *r_bytes) {
+ memnew_placement(r_bytes, PackedByteArray);
+
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
- PackedByteArray barr;
int len;
Error err = encode_variant(var, nullptr, len, p_full_objects);
- ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
+ ERR_FAIL_COND_MSG(err != OK, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
- barr.resize(len);
- encode_variant(var, barr.ptrw(), len, p_full_objects);
-
- return GDMonoMarshal::PackedByteArray_to_mono_array(barr);
+ r_bytes->resize(len);
+ encode_variant(var, r_bytes->ptrw(), len, p_full_objects);
}
MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
@@ -344,5 +340,3 @@ void godot_register_gd_icalls() {
// Dispatcher
GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
deleted file mode 100644
index f9ad1a9893..0000000000
--- a/modules/mono/glue/glue_header.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*************************************************************************/
-/* glue_header.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GLUE_HEADER_H
-#define GLUE_HEADER_H
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-void godot_register_collections_icalls();
-void godot_register_gd_icalls();
-void godot_register_string_name_icalls();
-void godot_register_nodepath_icalls();
-void godot_register_callable_icalls();
-void godot_register_object_icalls();
-void godot_register_rid_icalls();
-void godot_register_string_icalls();
-void godot_register_scene_tree_icalls();
-
-/**
- * Registers internal calls that were not generated. This function is called
- * from the generated GodotSharpBindings::register_generated_icalls() function.
- */
-void godot_register_glue_header_icalls() {
- godot_register_collections_icalls();
- godot_register_gd_icalls();
- godot_register_string_name_icalls();
- godot_register_nodepath_icalls();
- godot_register_callable_icalls();
- godot_register_object_icalls();
- godot_register_rid_icalls();
- godot_register_string_icalls();
- godot_register_scene_tree_icalls();
-}
-
-// Used by the generated glue
-
-#include "core/config/engine.h"
-#include "core/object/class_db.h"
-#include "core/object/method_bind.h"
-#include "core/object/ref_counted.h"
-#include "core/string/node_path.h"
-#include "core/string/ustring.h"
-#include "core/typedefs.h"
-#include "core/variant/array.h"
-#include "core/variant/dictionary.h"
-
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
- static ClassDB::ClassInfo *ci = nullptr; \
- if (!ci) { \
- ci = ClassDB::classes.getptr(m_type); \
- } \
- Object *m_instance = ci->creation_func();
-
-#include "arguments_vector.h"
-
-#endif // MONO_GLUE_ENABLED
-
-#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/node_path_glue.cpp
index 16e1509eb0..770ed31260 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/node_path_glue.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* nodepath_glue.cpp */
+/* node_path_glue.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,26 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include "core/string/node_path.h"
#include "core/string/ustring.h"
#include "../mono_gd/gd_mono_marshal.h"
-NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
- return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
-}
-
-void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
-}
-
-MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
- return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
-}
-
MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) {
return (MonoBoolean)p_ptr->is_absolute();
}
@@ -76,18 +61,11 @@ MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) {
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames());
}
-NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr) {
- return memnew(NodePath(p_ptr->get_as_property_path()));
+void godot_icall_NodePath_get_as_property_path(NodePath *p_ptr, NodePath *r_dest) {
+ *r_dest = p_ptr->get_as_property_path();
}
-MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
- return (MonoBoolean)p_ptr->is_empty();
-}
-
-void godot_register_nodepath_icalls() {
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
+void godot_register_node_path_icalls() {
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_names", godot_icall_NodePath_get_concatenated_names);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
@@ -96,7 +74,4 @@ void godot_register_nodepath_icalls() {
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/rid_glue.cpp b/modules/mono/glue/placeholder_glue.cpp
index 3e09564539..edac231bb4 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/modules/mono/glue/placeholder_glue.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* rid_glue.cpp */
+/* placeholder_glue.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,37 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
+#ifndef GLUE_HEADER_H
+#define GLUE_HEADER_H
-#include "core/io/resource.h"
-#include "core/object/class_db.h"
-#include "core/templates/rid.h"
+#include "core/object/object.h"
-#include "../mono_gd/gd_mono_marshal.h"
+#include "../mono_gd/gd_mono_internals.h"
+#include "../mono_gd/gd_mono_utils.h"
-RID *godot_icall_RID_Ctor(Object *p_from) {
- Resource *res_from = Object::cast_to<Resource>(p_from);
-
- if (res_from) {
- return memnew(RID(res_from->get_rid()));
- }
-
- return memnew(RID);
-}
-
-void godot_icall_RID_Dtor(RID *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
+MonoObject *godot_icall_InteropUtils_unmanaged_get_managed(Object *unmanaged) {
+ return GDMonoUtils::unmanaged_get_managed(unmanaged);
}
-uint32_t godot_icall_RID_get_id(RID *p_ptr) {
- return p_ptr->get_id();
+void godot_icall_InteropUtils_tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
+ GDMonoInternals::tie_managed_to_unmanaged(managed, unmanaged);
}
-void godot_register_rid_icalls() {
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor);
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor);
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id);
+void godot_register_placeholder_icalls() {
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_unmanaged_get_managed",
+ godot_icall_InteropUtils_unmanaged_get_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged",
+ godot_icall_InteropUtils_tie_managed_to_unmanaged);
}
-#endif // MONO_GLUE_ENABLED
+#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
new file mode 100644
index 0000000000..a9c47f8880
--- /dev/null
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -0,0 +1,786 @@
+/*************************************************************************/
+/* runtime_interop.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/config/engine.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/string/string_name.h"
+
+#include "../interop_types.h"
+
+#include "modules/mono/managed_callable.h"
+#include "modules/mono/signal_awaiter_utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+#define MAYBE_UNUSED [[maybe_unused]]
+#else
+#define MAYBE_UNUSED
+#endif
+
+#ifdef __GNUC__
+#define GD_PINVOKE_EXPORT MAYBE_UNUSED __attribute__((visibility("default")))
+#elif defined(_WIN32)
+#define GD_PINVOKE_EXPORT MAYBE_UNUSED __declspec(dllexport)
+#else
+#define GD_PINVOKE_EXPORT MAYBE_UNUSED
+#endif
+
+typedef Object *(*godotsharp_class_creation_func)();
+
+GD_PINVOKE_EXPORT MethodBind *godotsharp_method_bind_get_method(const StringName *p_classname, const char16_t *p_methodname) {
+ return ClassDB::get_method(*p_classname, StringName(String::utf16(p_methodname)));
+}
+
+GD_PINVOKE_EXPORT godotsharp_class_creation_func godotsharp_get_class_constructor(const StringName *p_classname) {
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(*p_classname);
+ if (class_info) {
+ return class_info->creation_func;
+ }
+ return nullptr;
+}
+
+GD_PINVOKE_EXPORT Object *godotsharp_invoke_class_constructor(godotsharp_class_creation_func p_creation_func) {
+ return p_creation_func();
+}
+
+GD_PINVOKE_EXPORT Object *godotsharp_engine_get_singleton(const String *p_name) {
+ return Engine::get_singleton()->get_singleton_object(*p_name);
+}
+
+GD_PINVOKE_EXPORT void godotsharp_ref_destroy(Ref<RefCounted> *p_instance) {
+ p_instance->~Ref();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_string_name_new_from_string(StringName *r_dest, const String *p_name) {
+ memnew_placement(r_dest, StringName(*p_name));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_node_path_new_from_string(NodePath *r_dest, const String *p_name) {
+ memnew_placement(r_dest, NodePath(*p_name));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_string_name_as_string(String *r_dest, const StringName *p_name) {
+ memnew_placement(r_dest, String(p_name->operator String()));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_node_path_as_string(String *r_dest, const NodePath *p_np) {
+ memnew_placement(r_dest, String(p_np->operator String()));
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_byte_array_new_mem_copy(const uint8_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedByteArray);
+ PackedByteArray *array = reinterpret_cast<PackedByteArray *>(&ret);
+ array->resize(p_length);
+ uint8_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(uint8_t));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_int32_array_new_mem_copy(const int32_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedInt32Array);
+ PackedInt32Array *array = reinterpret_cast<PackedInt32Array *>(&ret);
+ array->resize(p_length);
+ int32_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(int32_t));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_int64_array_new_mem_copy(const int64_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedInt64Array);
+ PackedInt64Array *array = reinterpret_cast<PackedInt64Array *>(&ret);
+ array->resize(p_length);
+ int64_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(int64_t));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_float32_array_new_mem_copy(const float *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedFloat32Array);
+ PackedFloat32Array *array = reinterpret_cast<PackedFloat32Array *>(&ret);
+ array->resize(p_length);
+ float *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(float));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_float64_array_new_mem_copy(const double *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedFloat64Array);
+ PackedFloat64Array *array = reinterpret_cast<PackedFloat64Array *>(&ret);
+ array->resize(p_length);
+ double *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(double));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_vector2_array_new_mem_copy(const Vector2 *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedVector2Array);
+ PackedVector2Array *array = reinterpret_cast<PackedVector2Array *>(&ret);
+ array->resize(p_length);
+ Vector2 *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Vector2));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_vector3_array_new_mem_copy(const Vector3 *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedVector3Array);
+ PackedVector3Array *array = reinterpret_cast<PackedVector3Array *>(&ret);
+ array->resize(p_length);
+ Vector3 *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Vector3));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_packed_color_array_new_mem_copy(const Color *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedColorArray);
+ PackedColorArray *array = reinterpret_cast<PackedColorArray *>(&ret);
+ array->resize(p_length);
+ Color *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Color));
+ return ret;
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String *p_element) {
+ r_dest->append(*p_element);
+}
+
+GD_PINVOKE_EXPORT void godotsharp_callable_new_with_delegate(void *p_delegate_handle, Callable *r_callable) {
+ // TODO: Use pooling for ManagedCallable instances.
+ CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle));
+ *r_callable = Callable(managed_callable);
+}
+
+GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
+ void **r_delegate_handle, Object **r_object, StringName *r_name) {
+ if (p_callable->is_custom()) {
+ CallableCustom *custom = p_callable->get_custom();
+ CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
+
+ if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
+ ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
+ *r_delegate_handle = managed_callable->get_delegate();
+ *r_object = nullptr;
+ *r_name = StringName();
+ return true;
+ } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
+ SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
+ *r_delegate_handle = nullptr;
+ *r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
+ *r_name = signal_awaiter_callable->get_signal();
+ return true;
+ } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
+ EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
+ *r_delegate_handle = nullptr;
+ *r_object = ObjectDB::get_instance(event_signal_callable->get_object());
+ *r_name = event_signal_callable->get_signal();
+ return true;
+ }
+
+ // Some other CallableCustom. We only support ManagedCallable.
+ *r_delegate_handle = nullptr;
+ *r_object = nullptr;
+ *r_name = StringName();
+ return false;
+ } else {
+ *r_delegate_handle = nullptr;
+ *r_object = ObjectDB::get_instance(p_callable->get_object_id());
+ *r_name = p_callable->get_method();
+ return true;
+ }
+}
+
+// GDNative functions
+
+// gdnative.h
+
+GD_PINVOKE_EXPORT void godotsharp_method_bind_ptrcall(MethodBind *p_method_bind, Object *p_instance, const void **p_args, void *p_ret) {
+ p_method_bind->ptrcall(p_instance, p_args, p_ret);
+}
+
+GD_PINVOKE_EXPORT godot_variant godotsharp_method_bind_call(MethodBind *p_method_bind, Object *p_instance, const godot_variant **p_args, const int p_arg_count, Callable::CallError *p_call_error) {
+ godot_variant ret;
+ memnew_placement(&ret, Variant());
+
+ Variant *ret_val = (Variant *)&ret;
+
+ *ret_val = p_method_bind->call(p_instance, (const Variant **)p_args, p_arg_count, *p_call_error);
+
+ return ret;
+}
+
+// variant.h
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_string_name(godot_variant *r_dest, const StringName *p_s) {
+ memnew_placement(r_dest, Variant(*p_s));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_node_path(godot_variant *r_dest, const NodePath *p_np) {
+ memnew_placement(r_dest, Variant(*p_np));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_object(godot_variant *r_dest, const Object *p_obj) {
+ memnew_placement(r_dest, Variant(p_obj));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_transform2d(godot_variant *r_dest, const Transform2D *p_t2d) {
+ memnew_placement(r_dest, Variant(*p_t2d));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_vector4(godot_variant *r_dest, const Vector4 *p_vec4) {
+ memnew_placement(r_dest, Variant(*p_vec4));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_vector4i(godot_variant *r_dest, const Vector4i *p_vec4i) {
+ memnew_placement(r_dest, Variant(*p_vec4i));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_basis(godot_variant *r_dest, const Basis *p_basis) {
+ memnew_placement(r_dest, Variant(*p_basis));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_transform3d(godot_variant *r_dest, const Transform3D *p_trans) {
+ memnew_placement(r_dest, Variant(*p_trans));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_projection(godot_variant *r_dest, const Projection *p_proj) {
+ memnew_placement(r_dest, Variant(*p_proj));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_aabb(godot_variant *r_dest, const AABB *p_aabb) {
+ memnew_placement(r_dest, Variant(*p_aabb));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_dictionary(godot_variant *r_dest, const Dictionary *p_dict) {
+ memnew_placement(r_dest, Variant(*p_dict));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_array(godot_variant *r_dest, const Array *p_arr) {
+ memnew_placement(r_dest, Variant(*p_arr));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_byte_array(godot_variant *r_dest, const PackedByteArray *p_pba) {
+ memnew_placement(r_dest, Variant(*p_pba));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int32_array(godot_variant *r_dest, const PackedInt32Array *p_pia) {
+ memnew_placement(r_dest, Variant(*p_pia));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int64_array(godot_variant *r_dest, const PackedInt64Array *p_pia) {
+ memnew_placement(r_dest, Variant(*p_pia));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float32_array(godot_variant *r_dest, const PackedFloat32Array *p_pra) {
+ memnew_placement(r_dest, Variant(*p_pra));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float64_array(godot_variant *r_dest, const PackedFloat64Array *p_pra) {
+ memnew_placement(r_dest, Variant(*p_pra));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_string_array(godot_variant *r_dest, const PackedStringArray *p_psa) {
+ memnew_placement(r_dest, Variant(*p_psa));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector2_array(godot_variant *r_dest, const PackedVector2Array *p_pv2a) {
+ memnew_placement(r_dest, Variant(*p_pv2a));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector3_array(godot_variant *r_dest, const PackedVector3Array *p_pv3a) {
+ memnew_placement(r_dest, Variant(*p_pv3a));
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_color_array(godot_variant *r_dest, const PackedColorArray *p_pca) {
+ memnew_placement(r_dest, Variant(*p_pca));
+}
+
+GD_PINVOKE_EXPORT bool godotsharp_variant_as_bool(const Variant *p_self) {
+ return p_self->operator bool();
+}
+
+GD_PINVOKE_EXPORT int64_t godotsharp_variant_as_int(const Variant *p_self) {
+ return p_self->operator int64_t();
+}
+
+GD_PINVOKE_EXPORT double godotsharp_variant_as_float(const Variant *p_self) {
+ return p_self->operator double();
+}
+
+GD_PINVOKE_EXPORT godot_string godotsharp_variant_as_string(const Variant *p_self) {
+ godot_string raw_dest;
+ String *dest = (String *)&raw_dest;
+ memnew_placement(dest, String(p_self->operator String()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector2 godotsharp_variant_as_vector2(const Variant *p_self) {
+ godot_vector2 raw_dest;
+ Vector2 *dest = (Vector2 *)&raw_dest;
+ memnew_placement(dest, Vector2(p_self->operator Vector2()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector2i godotsharp_variant_as_vector2i(const Variant *p_self) {
+ godot_vector2i raw_dest;
+ Vector2i *dest = (Vector2i *)&raw_dest;
+ memnew_placement(dest, Vector2i(p_self->operator Vector2i()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_rect2 godotsharp_variant_as_rect2(const Variant *p_self) {
+ godot_rect2 raw_dest;
+ Rect2 *dest = (Rect2 *)&raw_dest;
+ memnew_placement(dest, Rect2(p_self->operator Rect2()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_rect2i godotsharp_variant_as_rect2i(const Variant *p_self) {
+ godot_rect2i raw_dest;
+ Rect2i *dest = (Rect2i *)&raw_dest;
+ memnew_placement(dest, Rect2i(p_self->operator Rect2i()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector3 godotsharp_variant_as_vector3(const Variant *p_self) {
+ godot_vector3 raw_dest;
+ Vector3 *dest = (Vector3 *)&raw_dest;
+ memnew_placement(dest, Vector3(p_self->operator Vector3()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector3i godotsharp_variant_as_vector3i(const Variant *p_self) {
+ godot_vector3i raw_dest;
+ Vector3i *dest = (Vector3i *)&raw_dest;
+ memnew_placement(dest, Vector3i(p_self->operator Vector3i()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_transform2d godotsharp_variant_as_transform2d(const Variant *p_self) {
+ godot_transform2d raw_dest;
+ Transform2D *dest = (Transform2D *)&raw_dest;
+ memnew_placement(dest, Transform2D(p_self->operator Transform2D()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector4 godotsharp_variant_as_vector4(const Variant *p_self) {
+ godot_vector4 raw_dest;
+ Vector4 *dest = (Vector4 *)&raw_dest;
+ memnew_placement(dest, Vector4(p_self->operator Vector4()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_vector4i godotsharp_variant_as_vector4i(const Variant *p_self) {
+ godot_vector4i raw_dest;
+ Vector4i *dest = (Vector4i *)&raw_dest;
+ memnew_placement(dest, Vector4i(p_self->operator Vector4i()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_plane godotsharp_variant_as_plane(const Variant *p_self) {
+ godot_plane raw_dest;
+ Plane *dest = (Plane *)&raw_dest;
+ memnew_placement(dest, Plane(p_self->operator Plane()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_quaternion godotsharp_variant_as_quaternion(const Variant *p_self) {
+ godot_quaternion raw_dest;
+ Quaternion *dest = (Quaternion *)&raw_dest;
+ memnew_placement(dest, Quaternion(p_self->operator Quaternion()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_aabb godotsharp_variant_as_aabb(const Variant *p_self) {
+ godot_aabb raw_dest;
+ AABB *dest = (AABB *)&raw_dest;
+ memnew_placement(dest, AABB(p_self->operator ::AABB()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_basis godotsharp_variant_as_basis(const Variant *p_self) {
+ godot_basis raw_dest;
+ Basis *dest = (Basis *)&raw_dest;
+ memnew_placement(dest, Basis(p_self->operator Basis()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_transform3d godotsharp_variant_as_transform3d(const Variant *p_self) {
+ godot_transform3d raw_dest;
+ Transform3D *dest = (Transform3D *)&raw_dest;
+ memnew_placement(dest, Transform3D(p_self->operator Transform3D()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_projection godotsharp_variant_as_projection(const Variant *p_self) {
+ godot_projection raw_dest;
+ Projection *dest = (Projection *)&raw_dest;
+ memnew_placement(dest, Projection(p_self->operator Projection()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_color godotsharp_variant_as_color(const Variant *p_self) {
+ godot_color raw_dest;
+ Color *dest = (Color *)&raw_dest;
+ memnew_placement(dest, Color(p_self->operator Color()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_string_name godotsharp_variant_as_string_name(const Variant *p_self) {
+ godot_string_name raw_dest;
+ StringName *dest = (StringName *)&raw_dest;
+ memnew_placement(dest, StringName(p_self->operator StringName()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_node_path godotsharp_variant_as_node_path(const Variant *p_self) {
+ godot_node_path raw_dest;
+ NodePath *dest = (NodePath *)&raw_dest;
+ memnew_placement(dest, NodePath(p_self->operator NodePath()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_rid godotsharp_variant_as_rid(const Variant *p_self) {
+ godot_rid raw_dest;
+ RID *dest = (RID *)&raw_dest;
+ memnew_placement(dest, RID(p_self->operator ::RID()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_callable godotsharp_variant_as_callable(const Variant *p_self) {
+ godot_callable raw_dest;
+ Callable *dest = (Callable *)&raw_dest;
+ memnew_placement(dest, Callable(p_self->operator Callable()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_signal godotsharp_variant_as_signal(const Variant *p_self) {
+ godot_signal raw_dest;
+ Signal *dest = (Signal *)&raw_dest;
+ memnew_placement(dest, Signal(p_self->operator Signal()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_dictionary godotsharp_variant_as_dictionary(const Variant *p_self) {
+ godot_dictionary raw_dest;
+ Dictionary *dest = (Dictionary *)&raw_dest;
+ memnew_placement(dest, Dictionary(p_self->operator Dictionary()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_array godotsharp_variant_as_array(const Variant *p_self) {
+ godot_array raw_dest;
+ Array *dest = (Array *)&raw_dest;
+ memnew_placement(dest, Array(p_self->operator Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_byte_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedByteArray *dest = (PackedByteArray *)&raw_dest;
+ memnew_placement(dest, PackedByteArray(p_self->operator PackedByteArray()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_int32_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedInt32Array *dest = (PackedInt32Array *)&raw_dest;
+ memnew_placement(dest, PackedInt32Array(p_self->operator PackedInt32Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_int64_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedInt64Array *dest = (PackedInt64Array *)&raw_dest;
+ memnew_placement(dest, PackedInt64Array(p_self->operator PackedInt64Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_float32_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedFloat32Array *dest = (PackedFloat32Array *)&raw_dest;
+ memnew_placement(dest, PackedFloat32Array(p_self->operator PackedFloat32Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_float64_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedFloat64Array *dest = (PackedFloat64Array *)&raw_dest;
+ memnew_placement(dest, PackedFloat64Array(p_self->operator PackedFloat64Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_string_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedStringArray *dest = (PackedStringArray *)&raw_dest;
+ memnew_placement(dest, PackedStringArray(p_self->operator PackedStringArray()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_vector2_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedVector2Array *dest = (PackedVector2Array *)&raw_dest;
+ memnew_placement(dest, PackedVector2Array(p_self->operator PackedVector2Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_vector3_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedVector3Array *dest = (PackedVector3Array *)&raw_dest;
+ memnew_placement(dest, PackedVector3Array(p_self->operator PackedVector3Array()));
+ return raw_dest;
+}
+
+GD_PINVOKE_EXPORT godot_packed_array godotsharp_variant_as_packed_color_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedColorArray *dest = (PackedColorArray *)&raw_dest;
+ memnew_placement(dest, PackedColorArray(p_self->operator PackedColorArray()));
+ return raw_dest;
+}
+
+// string.h
+
+GD_PINVOKE_EXPORT void godotsharp_string_new_with_utf16_chars(String *r_dest, const char16_t *p_contents) {
+ memnew_placement(r_dest, String());
+ r_dest->parse_utf16(p_contents);
+}
+
+// string_name.h
+
+GD_PINVOKE_EXPORT void godotsharp_string_name_new_copy(StringName *r_dest, const StringName *p_src) {
+ memnew_placement(r_dest, StringName(*p_src));
+}
+
+// node_path.h
+
+GD_PINVOKE_EXPORT void godotsharp_node_path_new_copy(NodePath *r_dest, const NodePath *p_src) {
+ memnew_placement(r_dest, NodePath(*p_src));
+}
+
+// array.h
+
+GD_PINVOKE_EXPORT void godotsharp_array_new_copy(Array *r_dest, const Array *p_src) {
+ memnew_placement(r_dest, Array(*p_src));
+}
+
+// dictionary.h
+
+GD_PINVOKE_EXPORT void godotsharp_dictionary_new_copy(Dictionary *r_dest, const Dictionary *p_src) {
+ memnew_placement(r_dest, Dictionary(*p_src));
+}
+
+// destroy functions
+
+GD_PINVOKE_EXPORT void godotsharp_packed_byte_array_destroy(PackedByteArray *p_self) {
+ p_self->~PackedByteArray();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_int32_array_destroy(PackedInt32Array *p_self) {
+ p_self->~PackedInt32Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_int64_array_destroy(PackedInt64Array *p_self) {
+ p_self->~PackedInt64Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_float32_array_destroy(PackedFloat32Array *p_self) {
+ p_self->~PackedFloat32Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_float64_array_destroy(PackedFloat64Array *p_self) {
+ p_self->~PackedFloat64Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_string_array_destroy(PackedStringArray *p_self) {
+ p_self->~PackedStringArray();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_vector2_array_destroy(PackedVector2Array *p_self) {
+ p_self->~PackedVector2Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_vector3_array_destroy(PackedVector3Array *p_self) {
+ p_self->~PackedVector3Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_packed_color_array_destroy(PackedColorArray *p_self) {
+ p_self->~PackedColorArray();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_variant_destroy(Variant *p_self) {
+ p_self->~Variant();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_string_destroy(String *p_self) {
+ p_self->~String();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_string_name_destroy(StringName *p_self) {
+ p_self->~StringName();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_node_path_destroy(NodePath *p_self) {
+ p_self->~NodePath();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_signal_destroy(Signal *p_self) {
+ p_self->~Signal();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_callable_destroy(Callable *p_self) {
+ p_self->~Callable();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_array_destroy(Array *p_self) {
+ p_self->~Array();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_dictionary_destroy(Dictionary *p_self) {
+ p_self->~Dictionary();
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+// We need this to prevent the functions from being stripped.
+void *godotsharp_pinvoke_funcs[101] = {
+ (void *)godotsharp_method_bind_get_method,
+ (void *)godotsharp_get_class_constructor,
+ (void *)godotsharp_invoke_class_constructor,
+ (void *)godotsharp_engine_get_singleton,
+ (void *)godotsharp_ref_destroy,
+ (void *)godotsharp_string_name_new_from_string,
+ (void *)godotsharp_node_path_new_from_string,
+ (void *)godotsharp_string_name_as_string,
+ (void *)godotsharp_node_path_as_string,
+ (void *)godotsharp_packed_byte_array_new_mem_copy,
+ (void *)godotsharp_packed_int32_array_new_mem_copy,
+ (void *)godotsharp_packed_int64_array_new_mem_copy,
+ (void *)godotsharp_packed_float32_array_new_mem_copy,
+ (void *)godotsharp_packed_float64_array_new_mem_copy,
+ (void *)godotsharp_packed_vector2_array_new_mem_copy,
+ (void *)godotsharp_packed_vector3_array_new_mem_copy,
+ (void *)godotsharp_packed_color_array_new_mem_copy,
+ (void *)godotsharp_packed_string_array_add,
+ (void *)godotsharp_callable_new_with_delegate,
+ (void *)godotsharp_callable_get_data_for_marshalling,
+ (void *)godotsharp_method_bind_ptrcall,
+ (void *)godotsharp_method_bind_call,
+ (void *)godotsharp_variant_new_string_name,
+ (void *)godotsharp_variant_new_node_path,
+ (void *)godotsharp_variant_new_object,
+ (void *)godotsharp_variant_new_transform2d,
+ (void *)godotsharp_variant_new_vector4,
+ (void *)godotsharp_variant_new_vector4i,
+ (void *)godotsharp_variant_new_basis,
+ (void *)godotsharp_variant_new_transform3d,
+ (void *)godotsharp_variant_new_projection,
+ (void *)godotsharp_variant_new_aabb,
+ (void *)godotsharp_variant_new_dictionary,
+ (void *)godotsharp_variant_new_array,
+ (void *)godotsharp_variant_new_packed_byte_array,
+ (void *)godotsharp_variant_new_packed_int32_array,
+ (void *)godotsharp_variant_new_packed_int64_array,
+ (void *)godotsharp_variant_new_packed_float32_array,
+ (void *)godotsharp_variant_new_packed_float64_array,
+ (void *)godotsharp_variant_new_packed_string_array,
+ (void *)godotsharp_variant_new_packed_vector2_array,
+ (void *)godotsharp_variant_new_packed_vector3_array,
+ (void *)godotsharp_variant_new_packed_color_array,
+ (void *)godotsharp_variant_as_bool,
+ (void *)godotsharp_variant_as_int,
+ (void *)godotsharp_variant_as_float,
+ (void *)godotsharp_variant_as_string,
+ (void *)godotsharp_variant_as_vector2,
+ (void *)godotsharp_variant_as_vector2i,
+ (void *)godotsharp_variant_as_rect2,
+ (void *)godotsharp_variant_as_rect2i,
+ (void *)godotsharp_variant_as_vector3,
+ (void *)godotsharp_variant_as_vector3i,
+ (void *)godotsharp_variant_as_transform2d,
+ (void *)godotsharp_variant_as_vector4,
+ (void *)godotsharp_variant_as_vector4i,
+ (void *)godotsharp_variant_as_plane,
+ (void *)godotsharp_variant_as_quaternion,
+ (void *)godotsharp_variant_as_aabb,
+ (void *)godotsharp_variant_as_basis,
+ (void *)godotsharp_variant_as_transform3d,
+ (void *)godotsharp_variant_as_projection,
+ (void *)godotsharp_variant_as_color,
+ (void *)godotsharp_variant_as_string_name,
+ (void *)godotsharp_variant_as_node_path,
+ (void *)godotsharp_variant_as_rid,
+ (void *)godotsharp_variant_as_callable,
+ (void *)godotsharp_variant_as_signal,
+ (void *)godotsharp_variant_as_dictionary,
+ (void *)godotsharp_variant_as_array,
+ (void *)godotsharp_variant_as_packed_byte_array,
+ (void *)godotsharp_variant_as_packed_int32_array,
+ (void *)godotsharp_variant_as_packed_int64_array,
+ (void *)godotsharp_variant_as_packed_float32_array,
+ (void *)godotsharp_variant_as_packed_float64_array,
+ (void *)godotsharp_variant_as_packed_string_array,
+ (void *)godotsharp_variant_as_packed_vector2_array,
+ (void *)godotsharp_variant_as_packed_vector3_array,
+ (void *)godotsharp_variant_as_packed_color_array,
+ (void *)godotsharp_string_new_with_utf16_chars,
+ (void *)godotsharp_string_name_new_copy,
+ (void *)godotsharp_node_path_new_copy,
+ (void *)godotsharp_array_new_copy,
+ (void *)godotsharp_dictionary_new_copy,
+ (void *)godotsharp_packed_byte_array_destroy,
+ (void *)godotsharp_packed_int32_array_destroy,
+ (void *)godotsharp_packed_int64_array_destroy,
+ (void *)godotsharp_packed_float32_array_destroy,
+ (void *)godotsharp_packed_float64_array_destroy,
+ (void *)godotsharp_packed_string_array_destroy,
+ (void *)godotsharp_packed_vector2_array_destroy,
+ (void *)godotsharp_packed_vector3_array_destroy,
+ (void *)godotsharp_packed_color_array_destroy,
+ (void *)godotsharp_variant_destroy,
+ (void *)godotsharp_string_destroy,
+ (void *)godotsharp_string_name_destroy,
+ (void *)godotsharp_node_path_destroy,
+ (void *)godotsharp_signal_destroy,
+ (void *)godotsharp_callable_destroy,
+ (void *)godotsharp_array_destroy,
+ (void *)godotsharp_dictionary_destroy
+};
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
index c60e7c4869..55a46ad368 100644
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ b/modules/mono/glue/scene_tree_glue.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include "core/object/class_db.h"
#include "core/string/string_name.h"
#include "core/variant/array.h"
@@ -40,9 +38,10 @@
#include "../mono_gd/gd_mono_marshal.h"
#include "../mono_gd/gd_mono_utils.h"
-Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype) {
+void godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype, Array *r_dest) {
+ memnew_placement(r_dest, Array);
+
List<Node *> nodes;
- Array ret;
// Retrieve all the nodes in the group
ptr->get_nodes_in_group(*group, &nodes);
@@ -58,7 +57,7 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
StringName native_class_name = GDMonoUtils::get_native_godot_class_name(klass);
for (int i = 0; i < nodes.size(); ++i) {
if (ClassDB::is_parent_class(nodes[i]->get_class(), native_class_name)) {
- ret.push_back(nodes[i]);
+ r_dest->push_back(nodes[i]);
}
}
} else {
@@ -69,18 +68,14 @@ Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringNa
if (si != nullptr) {
MonoObject *obj = si->get_mono_object();
if (obj != nullptr && mono_object_get_class(obj) == mono_class) {
- ret.push_back(nodes[i]);
+ r_dest->push_back(nodes[i]);
}
}
}
}
}
-
- return memnew(Array(ret));
}
void godot_register_scene_tree_icalls() {
GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
index fc6b13ceb3..fe1c0b5f8c 100644
--- a/modules/mono/glue/string_glue.cpp
+++ b/modules/mono/glue/string_glue.cpp
@@ -28,8 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
-
#include "core/string/ustring.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
@@ -81,5 +79,3 @@ void godot_register_string_icalls() {
GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path);
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
deleted file mode 100644
index 46d15316ba..0000000000
--- a/modules/mono/glue/string_name_glue.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* string_name_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/string/string_name.h"
-#include "core/string/ustring.h"
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-StringName *godot_icall_StringName_Ctor(MonoString *p_path) {
- return memnew(StringName(GDMonoMarshal::mono_string_to_godot(p_path)));
-}
-
-void godot_icall_StringName_Dtor(StringName *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
-}
-
-MonoString *godot_icall_StringName_operator_String(StringName *p_np) {
- return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
-}
-
-MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
- return (MonoBoolean)(*p_ptr == StringName());
-}
-
-void godot_register_string_name_icalls() {
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index e5f1abe8d7..a637e0be9b 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -34,8 +34,8 @@
#define BINDINGS_NAMESPACE "Godot"
#define BINDINGS_NAMESPACE_COLLECTIONS BINDINGS_NAMESPACE ".Collections"
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
-#define BINDINGS_PTR_FIELD "ptr"
-#define BINDINGS_NATIVE_NAME_FIELD "nativeName"
+#define BINDINGS_PTR_FIELD "NativePtr"
+#define BINDINGS_NATIVE_NAME_FIELD "NativeName"
#define API_SOLUTION_NAME "GodotSharp"
#define CORE_API_ASSEMBLY_NAME "GodotSharp"
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
diff --git a/modules/mono/interop_types.h b/modules/mono/interop_types.h
new file mode 100644
index 0000000000..6942a91559
--- /dev/null
+++ b/modules/mono/interop_types.h
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* interop_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef INTEROP_TYPES_H
+#define INTEROP_TYPES_H
+
+#include "core/math/math_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// This is taken from the old GDNative, which was removed.
+
+#define GODOT_VARIANT_SIZE (sizeof(real_t) * 4 + sizeof(int64_t))
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VARIANT_SIZE];
+} godot_variant;
+
+#define GODOT_ARRAY_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_ARRAY_SIZE];
+} godot_array;
+
+#define GODOT_DICTIONARY_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_DICTIONARY_SIZE];
+} godot_dictionary;
+
+#define GODOT_STRING_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_STRING_SIZE];
+} godot_string;
+
+#define GODOT_STRING_NAME_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_STRING_NAME_SIZE];
+} godot_string_name;
+
+#define GODOT_PACKED_ARRAY_SIZE (2 * sizeof(void *))
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PACKED_ARRAY_SIZE];
+} godot_packed_array;
+
+#define GODOT_VECTOR2_SIZE (sizeof(real_t) * 2)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR2_SIZE];
+} godot_vector2;
+
+#define GODOT_VECTOR2I_SIZE (sizeof(int32_t) * 2)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR2I_SIZE];
+} godot_vector2i;
+
+#define GODOT_RECT2_SIZE (sizeof(real_t) * 4)
+
+typedef struct godot_rect2 {
+ uint8_t _dont_touch_that[GODOT_RECT2_SIZE];
+} godot_rect2;
+
+#define GODOT_RECT2I_SIZE (sizeof(int32_t) * 4)
+
+typedef struct godot_rect2i {
+ uint8_t _dont_touch_that[GODOT_RECT2I_SIZE];
+} godot_rect2i;
+
+#define GODOT_VECTOR3_SIZE (sizeof(real_t) * 3)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR3_SIZE];
+} godot_vector3;
+
+#define GODOT_VECTOR3I_SIZE (sizeof(int32_t) * 3)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR3I_SIZE];
+} godot_vector3i;
+
+#define GODOT_TRANSFORM2D_SIZE (sizeof(real_t) * 6)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_TRANSFORM2D_SIZE];
+} godot_transform2d;
+
+#define GODOT_VECTOR4_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR4_SIZE];
+} godot_vector4;
+
+#define GODOT_VECTOR4I_SIZE (sizeof(int32_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR4I_SIZE];
+} godot_vector4i;
+
+#define GODOT_PLANE_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PLANE_SIZE];
+} godot_plane;
+
+#define GODOT_QUATERNION_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE];
+} godot_quaternion;
+
+#define GODOT_AABB_SIZE (sizeof(real_t) * 6)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_AABB_SIZE];
+} godot_aabb;
+
+#define GODOT_BASIS_SIZE (sizeof(real_t) * 9)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_BASIS_SIZE];
+} godot_basis;
+
+#define GODOT_TRANSFORM3D_SIZE (sizeof(real_t) * 12)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE];
+} godot_transform3d;
+
+#define GODOT_PROJECTION_SIZE (sizeof(real_t) * 4 * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PROJECTION_SIZE];
+} godot_projection;
+
+// Colors should always use 32-bit floats, so don't use real_t here.
+#define GODOT_COLOR_SIZE (sizeof(float) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_COLOR_SIZE];
+} godot_color;
+
+#define GODOT_NODE_PATH_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_NODE_PATH_SIZE];
+} godot_node_path;
+
+#define GODOT_RID_SIZE sizeof(uint64_t)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_RID_SIZE];
+} godot_rid;
+
+// Alignment hardcoded in `core/variant/callable.h`.
+#define GODOT_CALLABLE_SIZE (16)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_CALLABLE_SIZE];
+} godot_callable;
+
+// Alignment hardcoded in `core/variant/callable.h`.
+#define GODOT_SIGNAL_SIZE (16)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_SIGNAL_SIZE];
+} godot_signal;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INTEROP_TYPES_H
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index c159bb9eea..72b353d8c1 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -31,6 +31,7 @@
#include "managed_callable.h"
#include "csharp_script.h"
+#include "mono_gd/gd_mono_cache.h"
#include "mono_gd/gd_mono_marshal.h"
#include "mono_gd/gd_mono_utils.h"
@@ -44,18 +45,20 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus
const ManagedCallable *a = static_cast<const ManagedCallable *>(p_a);
const ManagedCallable *b = static_cast<const ManagedCallable *>(p_b);
- MonoDelegate *delegate_a = (MonoDelegate *)a->delegate_handle.get_target();
- MonoDelegate *delegate_b = (MonoDelegate *)b->delegate_handle.get_target();
-
- if (!delegate_a || !delegate_b) {
- if (!delegate_a && !delegate_b) {
+ if (!a->delegate_handle || !b->delegate_handle) {
+ if (!a->delegate_handle && !b->delegate_handle) {
return true;
}
return false;
}
// Call Delegate's 'Equals'
- return GDMonoUtils::mono_delegate_equal(delegate_a, delegate_b);
+ MonoException *exc = nullptr;
+ MonoBoolean res = CACHED_METHOD_THUNK(DelegateUtils, DelegateEquals)
+ .invoke(a->delegate_handle,
+ b->delegate_handle, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -66,8 +69,7 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust
}
uint32_t ManagedCallable::hash() const {
- uint32_t hash = delegate_invoke->get_name().hash();
- return hash_murmur3_one_64(delegate_handle.handle, hash);
+ return hash_murmur3_one_64((uint64_t)delegate_handle);
}
String ManagedCallable::get_as_text() const {
@@ -91,41 +93,34 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
-#ifdef GD_MONO_HOT_RELOAD
- // Lost during hot-reload
- ERR_FAIL_NULL(delegate_invoke);
- ERR_FAIL_COND(delegate_handle.is_released());
-#endif
-
- ERR_FAIL_COND(delegate_invoke->get_parameters_count() < p_argcount);
-
- MonoObject *delegate = delegate_handle.get_target();
-
MonoException *exc = nullptr;
- MonoObject *ret = delegate_invoke->invoke(delegate, p_arguments, &exc);
+ CACHED_METHOD_THUNK(DelegateUtils, InvokeWithVariantArgs)
+ .invoke(delegate_handle, p_arguments,
+ p_argcount, &r_return_value, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
} else {
- r_return_value = GDMonoMarshal::mono_object_to_variant(ret);
r_call_error.error = Callable::CallError::CALL_OK;
}
}
-void ManagedCallable::set_delegate(MonoDelegate *p_delegate) {
- delegate_handle = MonoGCHandleData::new_strong_handle((MonoObject *)p_delegate);
- MonoMethod *delegate_invoke_raw = mono_get_delegate_invoke(mono_object_get_class((MonoObject *)p_delegate));
- const StringName &delegate_invoke_name = CSharpLanguage::get_singleton()->get_string_names().delegate_invoke_method_name;
- delegate_invoke = memnew(GDMonoMethod(delegate_invoke_name, delegate_invoke_raw)); // TODO: Use pooling for this GDMonoMethod instances
-}
+void ManagedCallable::release_delegate_handle() {
+ if (delegate_handle) {
+ MonoException *exc = nullptr;
+ CACHED_METHOD_THUNK(DelegateUtils, FreeGCHandle).invoke(delegate_handle, &exc);
-ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_delegate == nullptr);
-#endif
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ }
- set_delegate(p_delegate);
+ delegate_handle = nullptr;
+ }
+}
+// Why you do this clang-format...
+/* clang-format off */
+ManagedCallable::ManagedCallable(void *p_delegate_handle) : delegate_handle(p_delegate_handle) {
#ifdef GD_MONO_HOT_RELOAD
{
MutexLock lock(instances_mutex);
@@ -133,6 +128,7 @@ ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
}
#endif
}
+/* clang-format on */
ManagedCallable::~ManagedCallable() {
#ifdef GD_MONO_HOT_RELOAD
@@ -143,5 +139,5 @@ ManagedCallable::~ManagedCallable() {
}
#endif
- delegate_handle.release();
+ release_delegate_handle();
}
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 11bee6cf60..56c11e7e45 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -42,8 +42,7 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
- MonoGCHandleData delegate_handle;
- GDMonoMethod *delegate_invoke = nullptr;
+ void *delegate_handle = nullptr;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
@@ -60,9 +59,7 @@ public:
ObjectID get_object() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- _FORCE_INLINE_ MonoDelegate *get_delegate() { return (MonoDelegate *)delegate_handle.get_target(); }
-
- void set_delegate(MonoDelegate *p_delegate);
+ _FORCE_INLINE_ void *get_delegate() const { return delegate_handle; }
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -70,7 +67,9 @@ public:
static constexpr CompareEqualFunc compare_equal_func_ptr = &ManagedCallable::compare_equal;
static constexpr CompareEqualFunc compare_less_func_ptr = &ManagedCallable::compare_less;
- ManagedCallable(MonoDelegate *p_delegate);
+ void release_delegate_handle();
+
+ ManagedCallable(void *p_delegate_handle);
~ManagedCallable();
};
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index d3d3bb2bef..eeaec30d73 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -408,10 +408,6 @@ void GDMono::initialize() {
}
void GDMono::initialize_load_assemblies() {
-#ifndef MONO_GLUE_ENABLED
- CRASH_NOW_MSG("Mono: This binary was built with 'mono_glue=no'; cannot load assemblies.");
-#endif
-
// Load assemblies. The API and tools assemblies are required,
// the application is aborted if these assemblies cannot be loaded.
@@ -446,59 +442,34 @@ bool GDMono::_are_api_assemblies_out_of_sync() {
return out_of_sync;
}
-namespace GodotSharpBindings {
-#ifdef MONO_GLUE_ENABLED
-
-uint64_t get_core_api_hash();
-#ifdef TOOLS_ENABLED
-uint64_t get_editor_api_hash();
-#endif
-uint32_t get_bindings_version();
-uint32_t get_cs_glue_version();
-
-void register_generated_icalls();
-
-#else
-
-uint64_t get_core_api_hash() {
- GD_UNREACHABLE();
-}
-#ifdef TOOLS_ENABLED
-uint64_t get_editor_api_hash() {
- GD_UNREACHABLE();
-}
-#endif
-uint32_t get_bindings_version() {
- GD_UNREACHABLE();
-}
-
-uint32_t get_cs_glue_version() {
- GD_UNREACHABLE();
-}
-
-void register_generated_icalls() {
- /* Fine, just do nothing */
-}
-
-#endif // MONO_GLUE_ENABLED
-} // namespace GodotSharpBindings
+void godot_register_collections_icalls();
+void godot_register_gd_icalls();
+void godot_register_node_path_icalls();
+void godot_register_object_icalls();
+void godot_register_rid_icalls();
+void godot_register_string_icalls();
+void godot_register_scene_tree_icalls();
+void godot_register_placeholder_icalls();
void GDMono::_register_internal_calls() {
- GodotSharpBindings::register_generated_icalls();
+ // Registers internal calls that were not generated.
+ godot_register_collections_icalls();
+ godot_register_gd_icalls();
+ godot_register_node_path_icalls();
+ godot_register_object_icalls();
+ godot_register_string_icalls();
+ godot_register_scene_tree_icalls();
+ godot_register_placeholder_icalls();
}
void GDMono::_init_godot_api_hashes() {
-#if defined(MONO_GLUE_ENABLED) && defined(DEBUG_METHODS_ENABLED)
- if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
- ERR_PRINT("Mono: Core API hash mismatch.");
- }
+#ifdef DEBUG_METHODS_ENABLED
+ get_api_core_hash();
#ifdef TOOLS_ENABLED
- if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) {
- ERR_PRINT("Mono: Editor API hash mismatch.");
- }
+ get_api_editor_hash();
#endif // TOOLS_ENABLED
-#endif // MONO_GLUE_ENABLED && DEBUG_METHODS_ENABLED
+#endif // DEBUG_METHODS_ENABLED
}
void GDMono::_init_exception_policy() {
@@ -601,16 +572,6 @@ ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMo
if (api_hash_field) {
api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr));
}
-
- GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version");
- if (binds_ver_field) {
- api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(nullptr));
- }
-
- GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version");
- if (cs_glue_ver_field) {
- api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr));
- }
}
return api_assembly_version;
@@ -698,12 +659,8 @@ static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool
return false;
}
- r_out_of_sync = GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("core", "bindings_version") ||
- GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("core", "cs_glue_version") ||
- GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("editor", "bindings_version") ||
- GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("editor", "cs_glue_version") ||
- GodotSharpBindings::get_core_api_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
- GodotSharpBindings::get_editor_api_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
+ r_out_of_sync = GDMono::get_singleton()->get_api_core_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
+ GDMono::get_singleton()->get_api_editor_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
return true;
}
@@ -719,14 +676,9 @@ static void create_cached_api_hash_for(const String &p_api_assemblies_dir) {
cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path));
cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path));
- cfg->set_value("core", "bindings_version", GodotSharpBindings::get_bindings_version());
- cfg->set_value("core", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
- cfg->set_value("editor", "bindings_version", GodotSharpBindings::get_bindings_version());
- cfg->set_value("editor", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
-
// This assumes the prebuilt api assemblies we copied to the project are not out of sync
- cfg->set_value("core", "api_hash", GodotSharpBindings::get_core_api_hash());
- cfg->set_value("editor", "api_hash", GodotSharpBindings::get_editor_api_hash());
+ cfg->set_value("core", "api_hash", GDMono::get_singleton()->get_api_core_hash());
+ cfg->set_value("editor", "api_hash", GDMono::get_singleton()->get_api_editor_hash());
Error err = cfg->save(cached_api_hash_path);
ERR_FAIL_COND(err != OK);
@@ -764,7 +716,7 @@ String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const
bool api_assemblies_out_of_sync = false;
if (p_core_api_out_of_sync && p_editor_api_out_of_sync) {
- api_assemblies_out_of_sync = p_core_api_out_of_sync || p_editor_api_out_of_sync;
+ api_assemblies_out_of_sync = *p_core_api_out_of_sync || *p_editor_api_out_of_sync;
} else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
// Determine if they're out of sync
if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) {
@@ -824,14 +776,16 @@ bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, c
bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &r_loaded_api_assembly.assembly, p_refonly);
#endif
+#ifdef DEBUG_METHODS_ENABLED
if (success) {
ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE);
- r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
- GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
+ r_loaded_api_assembly.out_of_sync = get_api_core_hash() != api_assembly_ver.godot_api_hash;
} else {
r_loaded_api_assembly.out_of_sync = false;
}
+#else
+ r_loaded_api_assembly.out_of_sync = false;
+#endif
return success;
}
@@ -854,14 +808,16 @@ bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly,
bool success = FileAccess::exists(assembly_path) &&
load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
+#ifdef DEBUG_METHODS_ENABLED
if (success) {
ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR);
- r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
- GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
+ r_loaded_api_assembly.out_of_sync = get_api_editor_hash() != api_assembly_ver.godot_api_hash;
} else {
r_loaded_api_assembly.out_of_sync = false;
}
+#else
+ r_loaded_api_assembly.out_of_sync = false;
+#endif
return success;
}
@@ -1091,13 +1047,13 @@ Error GDMono::_unload_scripts_domain() {
Error GDMono::reload_scripts_domain() {
ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
+ CSharpLanguage::get_singleton()->_on_scripts_domain_about_to_unload();
+
if (scripts_domain) {
Error domain_unload_err = _unload_scripts_domain();
ERR_FAIL_COND_V_MSG(domain_unload_err != OK, domain_unload_err, "Mono: Failed to unload scripts domain.");
}
- CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
-
Error domain_load_err = _load_scripts_domain();
ERR_FAIL_COND_V_MSG(domain_load_err != OK, domain_load_err, "Mono: Failed to load scripts domain.");
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 51fd0f8483..bc871fe750 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -49,23 +49,15 @@ enum Type {
struct Version {
uint64_t godot_api_hash = 0;
- uint32_t bindings_version = 0;
- uint32_t cs_glue_version = 0;
bool operator==(const Version &p_other) const {
- return godot_api_hash == p_other.godot_api_hash &&
- bindings_version == p_other.bindings_version &&
- cs_glue_version == p_other.cs_glue_version;
+ return godot_api_hash == p_other.godot_api_hash;
}
Version() {}
- Version(uint64_t p_godot_api_hash,
- uint32_t p_bindings_version,
- uint32_t p_cs_glue_version) :
- godot_api_hash(p_godot_api_hash),
- bindings_version(p_bindings_version),
- cs_glue_version(p_cs_glue_version) {
+ Version(uint64_t p_godot_api_hash) :
+ godot_api_hash(p_godot_api_hash) {
}
static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type);
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 69d8c7edc9..08660e3701 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -48,8 +48,6 @@ CachedData cached_data;
}
#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val)
-#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_ns##_##m_class, m_val)
-#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.rawclass_##m_class, m_val)
#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val)
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val)
#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val)
@@ -68,23 +66,7 @@ void CachedData::clear_corlib_cache() {
corlib_cache_updated = false;
class_MonoObject = nullptr;
- class_bool = nullptr;
- class_int8_t = nullptr;
- class_int16_t = nullptr;
- class_int32_t = nullptr;
- class_int64_t = nullptr;
- class_uint8_t = nullptr;
- class_uint16_t = nullptr;
- class_uint32_t = nullptr;
- class_uint64_t = nullptr;
- class_float = nullptr;
- class_double = nullptr;
class_String = nullptr;
- class_IntPtr = nullptr;
-
- class_System_Collections_IEnumerable = nullptr;
- class_System_Collections_ICollection = nullptr;
- class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
class_System_Diagnostics_StackTrace = nullptr;
@@ -99,38 +81,12 @@ void CachedData::clear_corlib_cache() {
void CachedData::clear_godot_api_cache() {
godot_api_cache_updated = false;
- rawclass_Dictionary = nullptr;
-
- class_Vector2 = nullptr;
- class_Vector2i = nullptr;
- class_Rect2 = nullptr;
- class_Rect2i = nullptr;
- class_Transform2D = nullptr;
- class_Vector3 = nullptr;
- class_Vector3i = nullptr;
- class_Vector4 = nullptr;
- class_Vector4i = nullptr;
- class_Basis = nullptr;
- class_Quaternion = nullptr;
- class_Transform3D = nullptr;
- class_Projection = nullptr;
- class_AABB = nullptr;
- class_Color = nullptr;
- class_Plane = nullptr;
- class_StringName = nullptr;
- class_NodePath = nullptr;
- class_RID = nullptr;
class_GodotObject = nullptr;
class_GodotResource = nullptr;
class_Node = nullptr;
class_Control = nullptr;
- class_Node3D = nullptr;
- class_WeakRef = nullptr;
class_Callable = nullptr;
class_SignalInfo = nullptr;
- class_Array = nullptr;
- class_Dictionary = nullptr;
- class_MarshalUtils = nullptr;
class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
@@ -157,68 +113,39 @@ void CachedData::clear_godot_api_cache() {
field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
field_GodotObject_ptr = nullptr;
- field_StringName_ptr = nullptr;
- field_NodePath_ptr = nullptr;
- field_Image_ptr = nullptr;
- field_RID_ptr = nullptr;
methodthunk_GodotObject_Dispose.nullify();
- methodthunk_Array_GetPtr.nullify();
- methodthunk_Dictionary_GetPtr.nullify();
methodthunk_SignalAwaiter_SignalCallback.nullify();
methodthunk_GodotTaskScheduler_Activate.nullify();
methodthunk_Delegate_Equals.nullify();
+ methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle.nullify();
+ methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle.nullify();
methodthunk_DelegateUtils_TrySerializeDelegate.nullify();
methodthunk_DelegateUtils_TryDeserializeDelegate.nullify();
+ methodthunk_DelegateUtils_InvokeWithVariantArgs.nullify();
+ methodthunk_DelegateUtils_DelegateEquals.nullify();
+ methodthunk_DelegateUtils_FreeGCHandle.nullify();
- // Start of MarshalUtils methods
-
- methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
- methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify();
- methodthunk_MarshalUtils_TypeIsSystemGenericList.nullify();
- methodthunk_MarshalUtils_TypeIsSystemGenericDictionary.nullify();
- methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
- methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
- methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
- methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
-
- methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
-
- methodthunk_MarshalUtils_ArrayGetElementType.nullify();
- methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
+ methodthunk_Marshaling_managed_to_variant_type.nullify();
+ methodthunk_Marshaling_try_get_array_element_type.nullify();
+ methodthunk_Marshaling_variant_to_mono_object_of_type.nullify();
+ methodthunk_Marshaling_variant_to_mono_object.nullify();
+ methodthunk_Marshaling_mono_object_to_variant_out.nullify();
- methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
- methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
+ methodthunk_Marshaling_SetFieldValue.nullify();
- // End of MarshalUtils methods
+ methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
task_scheduler_handle = Ref<MonoGCHandleRef>();
}
#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
-#define GODOT_API_NS_CLASS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class))
void update_corlib_cache() {
CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
- CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
- CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
- CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
- CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
- CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
- CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
- CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
- CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
- CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
- CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
- CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
- CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
-
- CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
- CACHE_CLASS_AND_CHECK(System_Collections_ICollection, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "ICollection"));
- CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
#ifdef DEBUG_ENABLED
CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
@@ -235,36 +162,12 @@ void update_corlib_cache() {
}
void update_godot_api_cache() {
- CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
- CACHE_CLASS_AND_CHECK(Vector2i, GODOT_API_CLASS(Vector2i));
- CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
- CACHE_CLASS_AND_CHECK(Rect2i, GODOT_API_CLASS(Rect2i));
- CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
- CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
- CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i));
- CACHE_CLASS_AND_CHECK(Vector4, GODOT_API_CLASS(Vector4));
- CACHE_CLASS_AND_CHECK(Vector4i, GODOT_API_CLASS(Vector4i));
- CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
- CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion));
- CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D));
- CACHE_CLASS_AND_CHECK(Projection, GODOT_API_CLASS(Projection));
- CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
- CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
- CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
- CACHE_CLASS_AND_CHECK(StringName, GODOT_API_CLASS(StringName));
- CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
- CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
- CACHE_CLASS_AND_CHECK(Node3D, GODOT_API_CLASS(Node3D));
- CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable));
CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo));
- CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
- CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
- CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
#ifdef DEBUG_ENABLED
@@ -291,40 +194,41 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes"));
CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(StringName, ptr, CACHED_CLASS(StringName)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0));
- CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegateWithGCHandle", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegateWithGCHandle", 2));
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2));
CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, InvokeWithVariantArgs, GODOT_API_CLASS(DelegateUtils)->get_method("InvokeWithVariantArgs", 4));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, DelegateEquals, GODOT_API_CLASS(DelegateUtils)->get_method("DelegateEquals", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, FreeGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("FreeGCHandle", 1));
+
+ GDMonoClass *gd_mono_marshal_class = GDMono::get_singleton()->get_core_api_assembly()->get_class(
+ "Godot.NativeInterop", "Marshaling");
+
+ ERR_FAIL_COND_MSG(gd_mono_marshal_class == nullptr,
+ "Mono Cache: Class `Godot.NativeInterop.Marshaling` not found.");
+
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, managed_to_variant_type,
+ gd_mono_marshal_class->get_method("managed_to_variant_type", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, try_get_array_element_type,
+ gd_mono_marshal_class->get_method("try_get_array_element_type", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object_of_type,
+ gd_mono_marshal_class->get_method("variant_to_mono_object_of_type", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object,
+ gd_mono_marshal_class->get_method("variant_to_mono_object", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, mono_object_to_variant_out,
+ gd_mono_marshal_class->get_method("mono_object_to_variant_out", 3));
+
+ CACHE_METHOD_THUNK_AND_CHECK(Marshaling, SetFieldValue,
+ gd_mono_marshal_class->get_method("SetFieldValue", 3));
- // Start of MarshalUtils methods
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericList, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericList", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericDictionary", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2));
-
- // End of MarshalUtils methods
-
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));
#endif
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index e9cc26899e..0db32b5885 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -42,23 +42,7 @@ struct CachedData {
// Let's use the no-namespace format for these too
GDMonoClass *class_MonoObject = nullptr; // object
- GDMonoClass *class_bool = nullptr; // bool
- GDMonoClass *class_int8_t = nullptr; // sbyte
- GDMonoClass *class_int16_t = nullptr; // short
- GDMonoClass *class_int32_t = nullptr; // int
- GDMonoClass *class_int64_t = nullptr; // long
- GDMonoClass *class_uint8_t = nullptr; // byte
- GDMonoClass *class_uint16_t = nullptr; // ushort
- GDMonoClass *class_uint32_t = nullptr; // uint
- GDMonoClass *class_uint64_t = nullptr; // ulong
- GDMonoClass *class_float = nullptr; // float
- GDMonoClass *class_double = nullptr; // double
GDMonoClass *class_String = nullptr; // string
- GDMonoClass *class_IntPtr = nullptr; // System.IntPtr
-
- GDMonoClass *class_System_Collections_IEnumerable = nullptr;
- GDMonoClass *class_System_Collections_ICollection = nullptr;
- GDMonoClass *class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
@@ -68,40 +52,14 @@ struct CachedData {
#endif
GDMonoClass *class_KeyNotFoundException = nullptr;
-
- MonoClass *rawclass_Dictionary = nullptr;
// -----------------------------------------------
- GDMonoClass *class_Vector2 = nullptr;
- GDMonoClass *class_Vector2i = nullptr;
- GDMonoClass *class_Rect2 = nullptr;
- GDMonoClass *class_Rect2i = nullptr;
- GDMonoClass *class_Transform2D = nullptr;
- GDMonoClass *class_Vector3 = nullptr;
- GDMonoClass *class_Vector3i = nullptr;
- GDMonoClass *class_Vector4 = nullptr;
- GDMonoClass *class_Vector4i = nullptr;
- GDMonoClass *class_Basis = nullptr;
- GDMonoClass *class_Quaternion = nullptr;
- GDMonoClass *class_Transform3D = nullptr;
- GDMonoClass *class_Projection = nullptr;
- GDMonoClass *class_AABB = nullptr;
- GDMonoClass *class_Color = nullptr;
- GDMonoClass *class_Plane = nullptr;
- GDMonoClass *class_StringName = nullptr;
- GDMonoClass *class_NodePath = nullptr;
- GDMonoClass *class_RID = nullptr;
GDMonoClass *class_GodotObject = nullptr;
GDMonoClass *class_GodotResource = nullptr;
GDMonoClass *class_Node = nullptr;
GDMonoClass *class_Control = nullptr;
- GDMonoClass *class_Node3D = nullptr;
- GDMonoClass *class_WeakRef = nullptr;
GDMonoClass *class_Callable = nullptr;
GDMonoClass *class_SignalInfo = nullptr;
- GDMonoClass *class_Array = nullptr;
- GDMonoClass *class_Dictionary = nullptr;
- GDMonoClass *class_MarshalUtils = nullptr;
GDMonoClass *class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
@@ -127,43 +85,34 @@ struct CachedData {
GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
+
GDMonoField *field_GodotObject_ptr = nullptr;
- GDMonoField *field_StringName_ptr = nullptr;
- GDMonoField *field_NodePath_ptr = nullptr;
- GDMonoField *field_Image_ptr = nullptr;
- GDMonoField *field_RID_ptr = nullptr;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
- GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
- GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr;
GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate;
GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals;
+ GDMonoMethodThunkR<MonoBoolean, void *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle;
+ GDMonoMethodThunkR<MonoBoolean, MonoObject *, void **> methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle;
+
GDMonoMethodThunkR<MonoBoolean, MonoDelegate *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegate;
GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoDelegate **> methodthunk_DelegateUtils_TryDeserializeDelegate;
- // Start of MarshalUtils methods
-
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericList;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
-
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
+ GDMonoMethodThunk<void *, const Variant **, uint32_t, const Variant *> methodthunk_DelegateUtils_InvokeWithVariantArgs;
+ GDMonoMethodThunkR<MonoBoolean, void *, void *> methodthunk_DelegateUtils_DelegateEquals;
+ GDMonoMethodThunk<void *> methodthunk_DelegateUtils_FreeGCHandle;
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
+ GDMonoMethodThunkR<int32_t, MonoReflectionType *, MonoBoolean *> methodthunk_Marshaling_managed_to_variant_type;
+ GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_Marshaling_try_get_array_element_type;
+ GDMonoMethodThunkR<MonoObject *, const Variant *, MonoReflectionType *> methodthunk_Marshaling_variant_to_mono_object_of_type;
+ GDMonoMethodThunkR<MonoObject *, const Variant *> methodthunk_Marshaling_variant_to_mono_object;
+ GDMonoMethodThunk<MonoObject *, MonoBoolean, Variant *> methodthunk_Marshaling_mono_object_to_variant_out;
- GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
- GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
+ GDMonoMethodThunk<MonoReflectionField *, MonoObject *, const Variant *> methodthunk_Marshaling_SetFieldValue;
- // End of MarshalUtils methods
+ GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
Ref<MonoGCHandleRef> task_scheduler_handle;
@@ -184,10 +133,6 @@ extern CachedData cached_data;
void update_corlib_cache();
void update_godot_api_cache();
-inline void clear_corlib_cache() {
- cached_data.clear_corlib_cache();
-}
-
inline void clear_godot_api_cache() {
cached_data.clear_godot_api_cache();
}
@@ -195,7 +140,6 @@ inline void clear_godot_api_cache() {
#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr())
-#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoCache::cached_data.rawclass_##m_class)
#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field)
#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method)
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method)
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 51c5aa3542..24b46d2ce8 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -462,18 +462,11 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
return delegates_list;
}
- // If the class is generic we must use the generic type definition.
- MonoClass *klass = mono_class;
- if (mono_type_get_type(get_mono_type()) == MONO_TYPE_GENERICINST) {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), get_mono_type());
- GDMonoUtils::Marshal::get_generic_type_definition(reftype, &reftype);
- MonoType *type = mono_reflection_type_get_type(reftype);
- klass = mono_class_from_mono_type(type);
- }
+ // NOTE: Temporarily reverted d28be4d5808947606b8189ae1b2900b8fd2925cf, while we move code to C#
void *iter = nullptr;
MonoClass *raw_class = nullptr;
- while ((raw_class = mono_class_get_nested_types(klass, &iter)) != nullptr) {
+ while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) {
if (mono_class_is_delegate(raw_class)) {
StringName name = String::utf8(mono_class_get_name(raw_class));
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index cb025fc67a..6beeca79c3 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -46,421 +46,14 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
}
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
- switch (type.type_encoding) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_CHAR: {
- int16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I1: {
- int8_t val = p_value.operator signed char();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I2: {
- int16_t val = p_value.operator signed short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I4: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I8: {
- int64_t val = p_value.operator int64_t();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U1: {
- uint8_t val = p_value.operator unsigned char();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U2: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U4: {
- uint32_t val = p_value.operator unsigned int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U8: {
- uint64_t val = p_value.operator uint64_t();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_R4: {
- float val = p_value.operator float();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_R8: {
- double val = p_value.operator double();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = type.type_class;
+ MonoReflectionField *reflfield = mono_field_get_object(mono_domain_get(), owner->get_mono_ptr(), mono_field);
- if (tclass == CACHED_CLASS(Vector2)) {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
+ MonoException *exc = nullptr;
+ CACHED_METHOD_THUNK(Marshaling, SetFieldValue)
+ .invoke(reflfield, p_object, &p_value, &exc);
- if (tclass == CACHED_CLASS(Vector2i)) {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Rect2)) {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Rect2i)) {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Transform2D)) {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector3)) {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector3i)) {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector4)) {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector4i)) {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Basis)) {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Quaternion)) {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Transform3D)) {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Projection)) {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(AABB)) {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Color)) {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Plane)) {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
-
- if (tclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
-
- if (mono_class_is_enum(tclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I1: {
- int8_t val = p_value.operator signed char();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I2: {
- int16_t val = p_value.operator signed short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I4: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I8: {
- int64_t val = p_value.operator int64_t();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_value.operator unsigned char();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_value.operator unsigned int();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_value.operator uint64_t();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- default: {
- ERR_FAIL_MSG("Attempted to convert Variant to a managed enum value of unmarshallable base type.");
- }
- }
-
- break;
- }
-
- ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'.");
- } break;
- case MONO_TYPE_STRING: {
- if (p_value.get_type() == Variant::NIL) {
- // Otherwise, Variant -> String would return the string "Null"
- MonoString *mono_string = nullptr;
- mono_field_set_value(p_object, mono_field, mono_string);
- } else {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- }
- } break;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_CLASS: {
- MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_OBJECT: {
- // Variant
- switch (p_value.get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::INT: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_value.operator double();
- mono_field_set_value(p_object, mono_field, &val);
-#else
- float val = p_value.operator float();
- mono_field_set_value(p_object, mono_field, &val);
-#endif
- } break;
- case Variant::STRING: {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- } break;
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR4: {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR4I: {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::QUATERNION: {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::TRANSFORM3D: {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::PROJECTION: {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::STRING_NAME: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::NODE_PATH: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::RID: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::OBJECT: {
- MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::DICTIONARY: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::ARRAY: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- default:
- break;
- }
- } break;
- default: {
- ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + ".");
- } break;
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
}
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index a860442764..ef6a008a25 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,1282 +37,104 @@
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) {
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return Variant::BOOL;
-
- case MONO_TYPE_I1:
- return Variant::INT;
- case MONO_TYPE_I2:
- return Variant::INT;
- case MONO_TYPE_I4:
- return Variant::INT;
- case MONO_TYPE_I8:
- return Variant::INT;
-
- case MONO_TYPE_U1:
- return Variant::INT;
- case MONO_TYPE_U2:
- return Variant::INT;
- case MONO_TYPE_U4:
- return Variant::INT;
- case MONO_TYPE_U8:
- return Variant::INT;
-
- case MONO_TYPE_R4:
- return Variant::FLOAT;
- case MONO_TYPE_R8:
- return Variant::FLOAT;
-
- case MONO_TYPE_STRING: {
- return Variant::STRING;
- } break;
-
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
- if (vtclass == CACHED_CLASS(Vector2)) {
- return Variant::VECTOR2;
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- return Variant::VECTOR2I;
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- return Variant::RECT2;
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- return Variant::RECT2I;
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- return Variant::TRANSFORM2D;
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- return Variant::VECTOR3;
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- return Variant::VECTOR3I;
- }
- if (vtclass == CACHED_CLASS(Vector4)) {
- return Variant::VECTOR4;
- }
-
- if (vtclass == CACHED_CLASS(Vector4i)) {
- return Variant::VECTOR4I;
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- return Variant::BASIS;
- }
-
- if (vtclass == CACHED_CLASS(Quaternion)) {
- return Variant::QUATERNION;
- }
-
- if (vtclass == CACHED_CLASS(Transform3D)) {
- return Variant::TRANSFORM3D;
- }
- if (vtclass == CACHED_CLASS(Projection)) {
- return Variant::PROJECTION;
- }
- if (vtclass == CACHED_CLASS(AABB)) {
- return Variant::AABB;
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- return Variant::COLOR;
- }
-
- if (vtclass == CACHED_CLASS(Plane)) {
- return Variant::PLANE;
- }
-
- if (vtclass == CACHED_CLASS(Callable)) {
- return Variant::CALLABLE;
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- return Variant::SIGNAL;
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- return Variant::INT;
- }
- } break;
-
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoClass *elem_class = mono_class_get_element_class(p_type.type_class->get_mono_ptr());
-
- if (elem_class == CACHED_CLASS_RAW(MonoObject)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(uint8_t)) {
- return Variant::PACKED_BYTE_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(int32_t)) {
- return Variant::PACKED_INT32_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(int64_t)) {
- return Variant::PACKED_INT64_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(float)) {
- return Variant::PACKED_FLOAT32_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(double)) {
- return Variant::PACKED_FLOAT64_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(String)) {
- return Variant::PACKED_STRING_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Vector2)) {
- return Variant::PACKED_VECTOR2_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Vector3)) {
- return Variant::PACKED_VECTOR3_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Color)) {
- return Variant::PACKED_COLOR_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(StringName)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(NodePath)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(RID)) {
- return Variant::ARRAY;
- }
-
- if (mono_class_is_enum(elem_class)) {
- return Variant::ARRAY;
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(elem_class);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return Variant::ARRAY;
- }
- } break;
-
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
+// TODO: Those are just temporary until the code that needs them is moved to C#
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return Variant::OBJECT;
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- return Variant::STRING_NAME;
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- return Variant::NODE_PATH;
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- return Variant::RID;
- }
-
- if (CACHED_CLASS(Dictionary) == type_class) {
- return Variant::DICTIONARY;
- }
-
- if (CACHED_CLASS(Array) == type_class) {
- return Variant::ARRAY;
- }
-
- // IDictionary
- if (p_type.type_class == CACHED_CLASS(System_Collections_IDictionary)) {
- return Variant::DICTIONARY;
- }
-
- // ICollection or IEnumerable
- if (p_type.type_class == CACHED_CLASS(System_Collections_ICollection) ||
- p_type.type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
- return Variant::ARRAY;
- }
- } break;
-
- case MONO_TYPE_OBJECT: {
- if (r_nil_is_variant) {
- *r_nil_is_variant = true;
- }
- return Variant::NIL;
- } break;
-
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return Variant::DICTIONARY;
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return Variant::ARRAY;
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- return Variant::DICTIONARY;
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- return Variant::ARRAY;
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- return Variant::DICTIONARY;
- }
+Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) {
+ if (p_type.type_encoding == MONO_TYPE_VOID) {
+ return Variant::NIL;
+ }
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- return Variant::ARRAY;
- }
+ MonoReflectionType *refltype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
+ MonoBoolean nil_is_variant = false;
- // GodotObject
- GDMonoClass *type_class = p_type.type_class;
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return Variant::OBJECT;
- }
- } break;
+ MonoException *exc = nullptr;
+ int32_t ret = CACHED_METHOD_THUNK(Marshaling, managed_to_variant_type)
+ .invoke(refltype, &nil_is_variant, &exc);
- default: {
- } break;
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ return Variant::NIL;
}
if (r_nil_is_variant) {
- *r_nil_is_variant = false;
+ *r_nil_is_variant = (bool)nil_is_variant;
}
- // Unknown
- return Variant::NIL;
+ return (Variant::Type)ret;
}
bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) {
- switch (p_array_type.type_encoding) {
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoClass *elem_class = mono_class_get_element_class(p_array_type.type_class->get_mono_ptr());
- r_elem_type = ManagedType::from_class(elem_class);
- return true;
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
-
- if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype) ||
- GDMonoUtils::Marshal::type_is_system_generic_list(array_reftype) ||
- GDMonoUtils::Marshal::type_is_generic_icollection(array_reftype) ||
- GDMonoUtils::Marshal::type_is_generic_ienumerable(array_reftype)) {
- MonoReflectionType *elem_reftype;
-
- GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype);
-
- r_elem_type = ManagedType::from_reftype(elem_reftype);
- return true;
- }
- } break;
- default: {
- } break;
- }
-
- return false;
-}
-
-MonoString *variant_to_mono_string(const Variant &p_var) {
- if (p_var.get_type() == Variant::NIL) {
- return nullptr; // Otherwise, Variant -> String would return the string "Null"
- }
- return mono_string_from_godot(p_var.operator String());
-}
-
-MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) {
- MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) {
- return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass);
- }
+ MonoReflectionType *array_refltype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
+ MonoReflectionType *elem_refltype = nullptr;
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + GDMonoClass::get_full_name(array_type->eklass) + "'.");
-}
-
-MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) {
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
- }
-
- if (CACHED_CLASS(StringName) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator StringName());
- }
-
- if (CACHED_CLASS(NodePath) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator NodePath());
- }
-
- if (CACHED_CLASS(RID) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator ::RID());
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
- }
+ MonoException *exc = nullptr;
+ MonoBoolean ret = CACHED_METHOD_THUNK(Marshaling, try_get_array_element_type)
+ .invoke(array_refltype, &elem_refltype, &exc);
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == p_type_class ||
- CACHED_CLASS(System_Collections_ICollection) == p_type_class ||
- CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ return Variant::NIL;
}
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + p_type_class->get_full_name() + "'.");
+ r_elem_type = ManagedType::from_reftype(elem_refltype);
+ return ret;
}
-MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype);
- }
+MonoObject *variant_to_mono_object_of_type(const Variant &p_var, const ManagedType &p_type) {
+ MonoReflectionType *refltype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype);
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class);
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class);
- }
+ MonoException *exc = nullptr;
+ MonoObject *ret = CACHED_METHOD_THUNK(Marshaling, variant_to_mono_object_of_type)
+ .invoke(&p_var, refltype, &exc);
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ return nullptr;
}
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + p_type_class->get_full_name() + "'.");
+ return ret;
}
MonoObject *variant_to_mono_object(const Variant &p_var) {
- // Variant
- switch (p_var.get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_var.operator bool();
- return BOX_BOOLEAN(val);
- }
- case Variant::INT: {
- int64_t val = p_var.operator int64_t();
- return BOX_INT64(val);
- }
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_var.operator double();
- return BOX_DOUBLE(val);
-#else
- float val = p_var.operator float();
- return BOX_FLOAT(val);
-#endif
- }
- case Variant::STRING:
- return (MonoObject *)mono_string_from_godot(p_var.operator String());
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
- case Variant::VECTOR4: {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_var.operator ::Vector4());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4), &from);
- }
- case Variant::VECTOR4I: {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_var.operator ::Vector4i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4i), &from);
- }
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
- case Variant::QUATERNION: {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from);
- }
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
- case Variant::TRANSFORM3D: {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from);
- }
- case Variant::PROJECTION: {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_var.operator ::Projection());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Projection), &from);
- }
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
- case Variant::STRING_NAME:
- return GDMonoUtils::create_managed_from(p_var.operator StringName());
- case Variant::NODE_PATH:
- return GDMonoUtils::create_managed_from(p_var.operator NodePath());
- case Variant::RID:
- return GDMonoUtils::create_managed_from(p_var.operator ::RID());
- case Variant::OBJECT:
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
- case Variant::DICTIONARY:
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
- case Variant::ARRAY:
- return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
- case Variant::PACKED_BYTE_ARRAY:
- return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
- case Variant::PACKED_INT32_ARRAY:
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
- case Variant::PACKED_INT64_ARRAY:
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
- case Variant::PACKED_FLOAT32_ARRAY:
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
- case Variant::PACKED_FLOAT64_ARRAY:
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
- case Variant::PACKED_STRING_ARRAY:
- return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
- case Variant::PACKED_VECTOR2_ARRAY:
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
- case Variant::PACKED_VECTOR3_ARRAY:
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
- case Variant::PACKED_COLOR_ARRAY:
- return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
- default:
- return nullptr;
- }
-}
-
-size_t variant_get_managed_unboxed_size(const ManagedType &p_type) {
- // This method prints no errors for unsupported types. It's called on all methods, not only
- // those that end up being invoked with Variant parameters.
-
- // For MonoObject* we return 0, as it doesn't need to be stored.
- constexpr size_t zero_for_mono_object = 0;
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return sizeof(MonoBoolean);
- case MONO_TYPE_CHAR:
- return sizeof(uint16_t);
- case MONO_TYPE_I1:
- return sizeof(int8_t);
- case MONO_TYPE_I2:
- return sizeof(int16_t);
- case MONO_TYPE_I4:
- return sizeof(int32_t);
- case MONO_TYPE_I8:
- return sizeof(int64_t);
- case MONO_TYPE_U1:
- return sizeof(uint8_t);
- case MONO_TYPE_U2:
- return sizeof(uint16_t);
- case MONO_TYPE_U4:
- return sizeof(uint32_t);
- case MONO_TYPE_U8:
- return sizeof(uint64_t);
- case MONO_TYPE_R4:
- return sizeof(float);
- case MONO_TYPE_R8:
- return sizeof(double);
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- return sizeof(M_##m_struct); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
- RETURN_CHECK_FOR_STRUCT(Callable);
- RETURN_CHECK_FOR_STRUCT(SignalInfo);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN:
- return sizeof(MonoBoolean);
- case MONO_TYPE_CHAR:
- return sizeof(uint16_t);
- case MONO_TYPE_I1:
- return sizeof(int8_t);
- case MONO_TYPE_I2:
- return sizeof(int16_t);
- case MONO_TYPE_I4:
- return sizeof(int32_t);
- case MONO_TYPE_I8:
- return sizeof(int64_t);
- case MONO_TYPE_U1:
- return sizeof(uint8_t);
- case MONO_TYPE_U2:
- return sizeof(uint16_t);
- case MONO_TYPE_U4:
- return sizeof(uint32_t);
- case MONO_TYPE_U8:
- return sizeof(uint64_t);
- default: {
- // Enum with unsupported base type. We return nullptr MonoObject* on error.
- return zero_for_mono_object;
- }
- }
- }
-
- // Enum with unsupported value type. We return nullptr MonoObject* on error.
- } break;
- case MONO_TYPE_STRING:
- return zero_for_mono_object;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_GENERICINST:
- return zero_for_mono_object;
- case MONO_TYPE_OBJECT:
- return zero_for_mono_object;
- }
-
- // Unsupported type encoding. We return nullptr MonoObject* on error.
- return zero_for_mono_object;
-}
-
-void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
-#define RETURN_TYPE_VAL(m_type, m_val) \
- *reinterpret_cast<m_type *>(r_buffer) = m_val; \
- r_offset += sizeof(m_type); \
- return r_buffer;
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool());
- case MONO_TYPE_CHAR:
- RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
- case MONO_TYPE_I1:
- RETURN_TYPE_VAL(int8_t, p_var.operator signed char());
- case MONO_TYPE_I2:
- RETURN_TYPE_VAL(int16_t, p_var.operator signed short());
- case MONO_TYPE_I4:
- RETURN_TYPE_VAL(int32_t, p_var.operator signed int());
- case MONO_TYPE_I8:
- RETURN_TYPE_VAL(int64_t, p_var.operator int64_t());
- case MONO_TYPE_U1:
- RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char());
- case MONO_TYPE_U2:
- RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
- case MONO_TYPE_U4:
- RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int());
- case MONO_TYPE_U8:
- RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t());
- case MONO_TYPE_R4:
- RETURN_TYPE_VAL(float, p_var.operator float());
- case MONO_TYPE_R8:
- RETURN_TYPE_VAL(double, p_var.operator double());
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
- RETURN_TYPE_VAL(M_##m_struct, from); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- RETURN_TYPE_VAL(M_Callable, from);
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- RETURN_TYPE_VAL(M_SignalInfo, from);
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- RETURN_TYPE_VAL(MonoBoolean, val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- RETURN_TYPE_VAL(uint16_t, val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- RETURN_TYPE_VAL(int8_t, val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- RETURN_TYPE_VAL(int16_t, val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- RETURN_TYPE_VAL(int32_t, val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- RETURN_TYPE_VAL(int64_t, val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- RETURN_TYPE_VAL(uint8_t, val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- RETURN_TYPE_VAL(uint16_t, val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- RETURN_TYPE_VAL(uint32_t, val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- RETURN_TYPE_VAL(uint64_t, val);
- }
- default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'.");
- }
- }
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'.");
- } break;
-#undef RETURN_TYPE_VAL
- case MONO_TYPE_STRING:
- return variant_to_mono_string(p_var);
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- return variant_to_mono_array(p_var, p_type.type_class);
- case MONO_TYPE_CLASS:
- return variant_to_mono_object_of_class(p_var, p_type.type_class);
- case MONO_TYPE_GENERICINST:
- return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
- case MONO_TYPE_OBJECT:
- return variant_to_mono_object(p_var);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + ".");
-}
-
-MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- return BOX_BOOLEAN(val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_UINT16(val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- return BOX_INT8(val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- return BOX_INT16(val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- return BOX_INT32(val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- return BOX_INT64(val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- return BOX_UINT8(val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_UINT16(val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- return BOX_UINT32(val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- return BOX_UINT64(val);
- }
- case MONO_TYPE_R4: {
- float val = p_var.operator float();
- return BOX_FLOAT(val);
- }
- case MONO_TYPE_R8: {
- double val = p_var.operator double();
- return BOX_DOUBLE(val);
- }
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- return BOX_ENUM(enum_baseclass, val);
- }
- default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(enum_baseclass) + "'.");
- }
- }
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'.");
- } break;
- case MONO_TYPE_STRING:
- return (MonoObject *)variant_to_mono_string(p_var);
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class);
- case MONO_TYPE_CLASS:
- return variant_to_mono_object_of_class(p_var, p_type.type_class);
- case MONO_TYPE_GENERICINST:
- return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
- case MONO_TYPE_OBJECT:
- return variant_to_mono_object(p_var);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + ".");
-}
-
-Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
- ERR_FAIL_COND_V(!p_type.type_class, Variant());
-
-#ifdef DEBUG_ENABLED
- CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known.");
-#endif
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return (bool)unbox<MonoBoolean>(p_obj);
- case MONO_TYPE_CHAR:
- return unbox<uint16_t>(p_obj);
- case MONO_TYPE_I1:
- return unbox<int8_t>(p_obj);
- case MONO_TYPE_I2:
- return unbox<int16_t>(p_obj);
- case MONO_TYPE_I4:
- return unbox<int32_t>(p_obj);
- case MONO_TYPE_I8:
- return unbox<int64_t>(p_obj);
- case MONO_TYPE_U1:
- return unbox<uint8_t>(p_obj);
- case MONO_TYPE_U2:
- return unbox<uint16_t>(p_obj);
- case MONO_TYPE_U4:
- return unbox<uint32_t>(p_obj);
- case MONO_TYPE_U8:
- return unbox<uint64_t>(p_obj);
- case MONO_TYPE_R4:
- return unbox<float>(p_obj);
- case MONO_TYPE_R8:
- return unbox<double>(p_obj);
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
- if (vtclass == CACHED_CLASS(Vector2)) {
- return MARSHALLED_IN(Vector2, unbox_addr<GDMonoMarshal::M_Vector2>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- return MARSHALLED_IN(Vector2i, unbox_addr<GDMonoMarshal::M_Vector2i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- return MARSHALLED_IN(Rect2, unbox_addr<GDMonoMarshal::M_Rect2>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- return MARSHALLED_IN(Rect2i, unbox_addr<GDMonoMarshal::M_Rect2i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- return MARSHALLED_IN(Transform2D, unbox_addr<GDMonoMarshal::M_Transform2D>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- return MARSHALLED_IN(Vector3, unbox_addr<GDMonoMarshal::M_Vector3>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- return MARSHALLED_IN(Vector3i, unbox_addr<GDMonoMarshal::M_Vector3i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Quaternion)) {
- return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Transform3D)) {
- return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(AABB)) {
- return MARSHALLED_IN(AABB, unbox_addr<GDMonoMarshal::M_AABB>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- return MARSHALLED_IN(Color, unbox_addr<GDMonoMarshal::M_Color>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Plane)) {
- return MARSHALLED_IN(Plane, unbox_addr<GDMonoMarshal::M_Plane>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Callable)) {
- return managed_to_callable(unbox<GDMonoMarshal::M_Callable>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- return managed_to_signal_info(unbox<GDMonoMarshal::M_SignalInfo>(p_obj));
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- return unbox<int32_t>(p_obj);
- }
- } break;
- case MONO_TYPE_STRING: {
- if (p_obj == nullptr) {
- return Variant(); // NIL
- }
- return mono_string_to_godot_not_null((MonoString *)p_obj);
- } break;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return mono_array_to_PackedByteArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return mono_array_to_PackedInt32Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return mono_array_to_PackedInt64Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return mono_array_to_PackedFloat32Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return mono_array_to_PackedFloat64Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return mono_array_to_PackedStringArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return mono_array_to_PackedVector2Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return mono_array_to_PackedVector3Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return mono_array_to_PackedColorArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (p_fail_with_err) {
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
- } else {
- return Variant();
- }
- } break;
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- if (ptr != nullptr) {
- RefCounted *rc = Object::cast_to<RefCounted>(ptr);
- return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
- }
- return Variant();
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- StringName *ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- // Godot.Collections.Dictionary
- if (CACHED_CLASS(Dictionary) == type_class) {
- MonoException *exc = nullptr;
- Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return ptr ? Variant(*ptr) : Variant();
- }
-
- // Godot.Collections.Array
- if (CACHED_CLASS(Array) == type_class) {
- MonoException *exc = nullptr;
- Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return ptr ? Variant(*ptr) : Variant();
- }
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- MonoException *exc = nullptr;
- MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return *unbox<Dictionary *>(ret);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- MonoException *exc = nullptr;
- MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return *unbox<Array *>(ret);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return system_generic_dict_to_Dictionary(p_obj, p_type.type_class, key_reftype, value_reftype);
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return system_generic_list_to_Array_variant(p_obj, p_type.type_class, elem_reftype);
- }
+ MonoException *exc = nullptr;
+ MonoObject *ret = CACHED_METHOD_THUNK(Marshaling, variant_to_mono_object)
+ .invoke(&p_var, &exc);
- // GodotObject
- GDMonoClass *type_class = p_type.type_class;
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- if (ptr != nullptr) {
- RefCounted *rc = Object::cast_to<RefCounted>(ptr);
- return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
- }
- return Variant();
- }
- } break;
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ return nullptr;
}
- if (p_fail_with_err) {
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" + p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
- } else {
- return Variant();
- }
+ return ret;
}
-Variant mono_object_to_variant(MonoObject *p_obj) {
+static Variant mono_object_to_variant_impl(MonoObject *p_obj, bool p_fail_with_err) {
if (!p_obj) {
return Variant();
}
- ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
+ MonoBoolean fail_with_error = p_fail_with_err;
- return mono_object_to_variant_impl(p_obj, type);
-}
+ Variant ret;
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
- if (!p_obj) {
+ MonoException *exc = nullptr;
+ CACHED_METHOD_THUNK(Marshaling, mono_object_to_variant_out)
+ .invoke(p_obj, fail_with_error, &ret, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
return Variant();
}
- return mono_object_to_variant_impl(p_obj, p_type);
+ return ret;
}
-Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type) {
- if (!p_obj) {
- return Variant();
- }
+Variant mono_object_to_variant(MonoObject *p_obj) {
+ return mono_object_to_variant_impl(p_obj, /* fail_with_err: */ true);
+}
- return mono_object_to_variant_impl(p_obj, p_type, /* fail_with_err: */ false);
+Variant mono_object_to_variant_no_err(MonoObject *p_obj) {
+ return mono_object_to_variant_impl(p_obj, /* fail_with_err: */ false);
}
String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
@@ -1320,8 +142,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
return String("null");
}
- ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
- Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
+ Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj);
if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true
// Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
@@ -1341,90 +162,6 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
}
}
-MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
- ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
- GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(ctor == nullptr);
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
- MonoObject *godot_dict = GDMonoUtils::create_managed_from(p_dict, godot_dict_class);
-
- void *ctor_args[1] = { godot_dict };
-
- MonoException *exc = nullptr;
- ctor->invoke_raw(mono_object, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
- String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
- ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
- GDMonoMethod *godot_dict_ctor = godot_dict_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(godot_dict_ctor == nullptr);
-
- MonoObject *godot_dict = mono_object_new(mono_domain_get(), godot_dict_class->get_mono_ptr());
- ERR_FAIL_NULL_V(godot_dict, Dictionary());
-
- void *ctor_args[1] = { p_obj };
-
- MonoException *exc = nullptr;
- godot_dict_ctor->invoke_raw(godot_dict, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- exc = nullptr;
- MonoObject *ret = godot_dict_class->get_method("GetPtr")->invoke(godot_dict, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return *unbox<Dictionary *>(ret);
-}
-
-MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
- MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype);
-
- String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)";
- GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(ctor == nullptr);
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(p_elem_reftype);
- MonoObject *godot_array = GDMonoUtils::create_managed_from(p_array, godot_array_class);
-
- void *ctor_args[1] = { godot_array };
-
- MonoException *exc = nullptr;
- ctor->invoke_raw(mono_object, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) {
- GDMonoMethod *to_array = p_class->get_method("ToArray", 0);
- CRASH_COND(to_array == nullptr);
-
- MonoException *exc = nullptr;
- MonoObject *array = to_array->invoke_raw(p_obj, nullptr, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- ERR_FAIL_NULL_V(array, Variant());
-
- ManagedType type = ManagedType::from_class(mono_object_get_class(array));
-
- bool result_is_array = type.type_encoding != MONO_TYPE_SZARRAY && type.type_encoding != MONO_TYPE_ARRAY;
- ERR_FAIL_COND_V(result_is_array, Variant());
-
- return mono_object_to_variant(array, type);
-}
-
MonoArray *Array_to_mono_array(const Array &p_array) {
int length = p_array.size();
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length);
@@ -1437,18 +174,6 @@ MonoArray *Array_to_mono_array(const Array &p_array) {
return ret;
}
-MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) {
- int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length);
-
- for (int i = 0; i < length; i++) {
- MonoObject *boxed = variant_to_mono_object(p_array[i]);
- mono_array_setref(ret, i, boxed);
- }
-
- return ret;
-}
-
Array mono_array_to_Array(MonoArray *p_array) {
Array ret;
if (!p_array) {
@@ -1465,141 +190,6 @@ Array mono_array_to_Array(MonoArray *p_array) {
return ret;
}
-MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array) {
- const int32_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), length);
-
- int32_t *dst = mono_array_addr(ret, int32_t, 0);
- memcpy(dst, src, length * sizeof(int32_t));
-
- return ret;
-}
-
-PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array) {
- PackedInt32Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- int32_t *dst = ret.ptrw();
-
- const int32_t *src = mono_array_addr(p_array, int32_t, 0);
- memcpy(dst, src, length * sizeof(int32_t));
-
- return ret;
-}
-
-MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array) {
- const int64_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int64_t), length);
-
- int64_t *dst = mono_array_addr(ret, int64_t, 0);
- memcpy(dst, src, length * sizeof(int64_t));
-
- return ret;
-}
-
-PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array) {
- PackedInt64Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- int64_t *dst = ret.ptrw();
-
- const int64_t *src = mono_array_addr(p_array, int64_t, 0);
- memcpy(dst, src, length * sizeof(int64_t));
-
- return ret;
-}
-
-MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array) {
- const uint8_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), length);
-
- uint8_t *dst = mono_array_addr(ret, uint8_t, 0);
- memcpy(dst, src, length * sizeof(uint8_t));
-
- return ret;
-}
-
-PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array) {
- PackedByteArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- uint8_t *dst = ret.ptrw();
-
- const uint8_t *src = mono_array_addr(p_array, uint8_t, 0);
- memcpy(dst, src, length * sizeof(uint8_t));
-
- return ret;
-}
-
-MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array) {
- const float *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(float), length);
-
- float *dst = mono_array_addr(ret, float, 0);
- memcpy(dst, src, length * sizeof(float));
-
- return ret;
-}
-
-PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array) {
- PackedFloat32Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- float *dst = ret.ptrw();
-
- const float *src = mono_array_addr(p_array, float, 0);
- memcpy(dst, src, length * sizeof(float));
-
- return ret;
-}
-
-MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array) {
- const double *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(double), length);
-
- double *dst = mono_array_addr(ret, double, 0);
- memcpy(dst, src, length * sizeof(double));
-
- return ret;
-}
-
-PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array) {
- PackedFloat64Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- double *dst = ret.ptrw();
-
- const double *src = mono_array_addr(p_array, double, 0);
- memcpy(dst, src, length * sizeof(double));
-
- return ret;
-}
-
MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) {
const String *r = p_array.ptr();
int length = p_array.size();
@@ -1613,212 +203,4 @@ MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) {
return ret;
}
-
-PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array) {
- PackedStringArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- String *w = ret.ptrw();
-
- for (int i = 0; i < length; i++) {
- MonoString *elem = mono_array_get(p_array, MonoString *, i);
- w[i] = mono_string_to_godot(elem);
- }
-
- return ret;
-}
-
-MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array) {
- const Color *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), length);
-
- if constexpr (InteropLayout::MATCHES_Color) {
- Color *dst = mono_array_addr(ret, Color, 0);
- memcpy(dst, src, length * sizeof(Color));
- } else {
- for (int i = 0; i < length; i++) {
- M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
- *raw = MARSHALLED_OUT(Color, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array) {
- PackedColorArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Color *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Color) {
- const Color *src = mono_array_addr(p_array, Color, 0);
- memcpy(dst, src, length * sizeof(Color));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
- }
- }
-
- return ret;
-}
-
-MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array) {
- const Vector2 *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), length);
-
- if constexpr (InteropLayout::MATCHES_Vector2) {
- Vector2 *dst = mono_array_addr(ret, Vector2, 0);
- memcpy(dst, src, length * sizeof(Vector2));
- } else {
- for (int i = 0; i < length; i++) {
- M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
- *raw = MARSHALLED_OUT(Vector2, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array) {
- PackedVector2Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Vector2 *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Vector2) {
- const Vector2 *src = mono_array_addr(p_array, Vector2, 0);
- memcpy(dst, src, length * sizeof(Vector2));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
- }
- }
-
- return ret;
-}
-
-MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array) {
- const Vector3 *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), length);
-
- if constexpr (InteropLayout::MATCHES_Vector3) {
- Vector3 *dst = mono_array_addr(ret, Vector3, 0);
- memcpy(dst, src, length * sizeof(Vector3));
- } else {
- for (int i = 0; i < length; i++) {
- M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
- *raw = MARSHALLED_OUT(Vector3, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array) {
- PackedVector3Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Vector3 *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Vector3) {
- const Vector3 *src = mono_array_addr(p_array, Vector3, 0);
- memcpy(dst, src, length * sizeof(Vector3));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
- }
- }
-
- return ret;
-}
-
-Callable managed_to_callable(const M_Callable &p_managed_callable) {
- if (p_managed_callable.delegate) {
- // TODO: Use pooling for ManagedCallable instances.
- CallableCustom *managed_callable = memnew(ManagedCallable(p_managed_callable.delegate));
- return Callable(managed_callable);
- } else {
- Object *target = p_managed_callable.target
- ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target))
- : nullptr;
- StringName *method_ptr = p_managed_callable.method_string_name
- ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name))
- : nullptr;
- StringName method = method_ptr ? *method_ptr : StringName();
- return Callable(target, method);
- }
-}
-
-M_Callable callable_to_managed(const Callable &p_callable) {
- if (p_callable.is_custom()) {
- CallableCustom *custom = p_callable.get_custom();
- CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
-
- if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
- ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
- return {
- nullptr, nullptr,
- managed_callable->get_delegate()
- };
- } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
- SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
- return {
- GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(signal_awaiter_callable->get_object())),
- GDMonoUtils::create_managed_from(signal_awaiter_callable->get_signal()),
- nullptr
- };
- } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
- EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
- return {
- GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(event_signal_callable->get_object())),
- GDMonoUtils::create_managed_from(event_signal_callable->get_signal()),
- nullptr
- };
- }
-
- // Some other CallableCustom. We only support ManagedCallable.
- return { nullptr, nullptr, nullptr };
- } else {
- MonoObject *target_managed = GDMonoUtils::unmanaged_get_managed(p_callable.get_object());
- MonoObject *method_string_name_managed = GDMonoUtils::create_managed_from(p_callable.get_method());
- return { target_managed, method_string_name_managed, nullptr };
- }
-}
-
-Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) {
- Object *owner = p_managed_signal.owner
- ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner))
- : nullptr;
- StringName *name_ptr = p_managed_signal.name_string_name
- ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name))
- : nullptr;
- StringName name = name_ptr ? *name_ptr : StringName();
- return Signal(owner, name);
-}
-
-M_SignalInfo signal_info_to_managed(const Signal &p_signal) {
- Object *owner = p_signal.get_object();
- MonoObject *owner_managed = GDMonoUtils::unmanaged_get_managed(owner);
- MonoObject *name_string_name_managed = GDMonoUtils::create_managed_from(p_signal.get_name());
- return { owner_managed, name_string_name_managed };
-}
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 51f11ab18a..16683de51a 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,6 @@
#include "core/variant/variant.h"
-#include "../managed_callable.h"
#include "gd_mono.h"
#include "gd_mono_utils.h"
@@ -44,25 +43,6 @@ T unbox(MonoObject *p_obj) {
return *(T *)mono_object_unbox(p_obj);
}
-template <typename T>
-T *unbox_addr(MonoObject *p_obj) {
- return (T *)mono_object_unbox(p_obj);
-}
-
-#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
-#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
-#define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)
-#define BOX_INT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int32_t), &x)
-#define BOX_INT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int16_t), &x)
-#define BOX_INT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int8_t), &x)
-#define BOX_UINT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint64_t), &x)
-#define BOX_UINT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint32_t), &x)
-#define BOX_UINT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint16_t), &x)
-#define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x)
-#define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x)
-#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
-#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-
Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr);
bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type);
@@ -90,516 +70,37 @@ _FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
// Variant
-size_t variant_get_managed_unboxed_size(const ManagedType &p_type);
-void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset);
-MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type);
+MonoObject *variant_to_mono_object_of_type(const Variant &p_var, const ManagedType &p_type);
MonoObject *variant_to_mono_object(const Variant &p_var);
-MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class);
-MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class);
-MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class);
-MonoString *variant_to_mono_string(const Variant &p_var);
// These overloads were added to avoid passing a `const Variant *` to the `const Variant &`
// parameter. That would result in the `Variant(bool)` copy constructor being called as
// pointers are implicitly converted to bool. Implicit conversions are f-ing evil.
-_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
- return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
- return variant_to_mono_object(*p_var, p_type);
+_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_type(const Variant *p_var, const ManagedType &p_type) {
+ return variant_to_mono_object_of_type(*p_var, p_type);
}
_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) {
return variant_to_mono_object(*p_var);
}
-_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_array(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_object_of_class(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_object_of_genericinst(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) {
- return variant_to_mono_string(*p_var);
-}
Variant mono_object_to_variant(MonoObject *p_obj);
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
-Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type);
+Variant mono_object_to_variant_no_err(MonoObject *p_obj);
/// Tries to convert the MonoObject* to Variant and then convert the Variant to String.
/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
-// System.Collections.Generic
-
-MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-
-MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
-Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
-
// Array
MonoArray *Array_to_mono_array(const Array &p_array);
-MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class);
Array mono_array_to_Array(MonoArray *p_array);
-// PackedInt32Array
-
-MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array);
-PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array);
-
-// PackedInt64Array
-
-MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array);
-PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array);
-
-// PackedByteArray
-
-MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array);
-PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array);
-
-// PackedFloat32Array
-
-MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array);
-PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array);
-
-// PackedFloat64Array
-
-MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array);
-PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array);
-
// PackedStringArray
MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array);
-PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array);
-
-// PackedColorArray
-
-MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array);
-PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array);
-
-// PackedVector2Array
-
-MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array);
-PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array);
-
-// PackedVector3Array
-
-MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array);
-PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
-
-#pragma pack(push, 1)
-
-struct M_Callable {
- MonoObject *target = nullptr;
- MonoObject *method_string_name = nullptr;
- MonoDelegate *delegate = nullptr;
-};
-
-struct M_SignalInfo {
- MonoObject *owner = nullptr;
- MonoObject *name_string_name = nullptr;
-};
-
-#pragma pack(pop)
-
-// Callable
-Callable managed_to_callable(const M_Callable &p_managed_callable);
-M_Callable callable_to_managed(const Callable &p_callable);
-
-// SignalInfo
-Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal);
-M_SignalInfo signal_info_to_managed(const Signal &p_signal);
-
-// Structures
-
-namespace InteropLayout {
-
-enum {
- MATCHES_int = (sizeof(int32_t) == sizeof(uint32_t)),
-
- MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
-
- MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
-
-#ifdef REAL_T_IS_DOUBLE
- MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)),
-#else
- MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)),
-#endif
-
- MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) &&
- offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector2, y) == (sizeof(real_t) * 1)),
-
- MATCHES_Vector2i = (MATCHES_int && (sizeof(Vector2i) == (sizeof(int32_t) * 2)) &&
- offsetof(Vector2i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector2i, y) == (sizeof(int32_t) * 1)),
-
- MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
- offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
- offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
-
- MATCHES_Rect2i = (MATCHES_Vector2i && (sizeof(Rect2i) == (sizeof(Vector2i) * 2)) &&
- offsetof(Rect2i, position) == (sizeof(Vector2i) * 0) &&
- offsetof(Rect2i, size) == (sizeof(Vector2i) * 1)),
-
- MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
-
- MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
- offsetof(Vector3, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
- offsetof(Vector3, z) == (sizeof(real_t) * 2)),
-
- MATCHES_Vector4 = (MATCHES_real_t && (sizeof(Vector4) == (sizeof(real_t) * 4)) &&
- offsetof(Vector4, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector4, y) == (sizeof(real_t) * 1) &&
- offsetof(Vector4, z) == (sizeof(real_t) * 2) &&
- offsetof(Vector4, w) == (sizeof(real_t) * 3)),
-
- MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4)) &&
- offsetof(Vector4i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector4i, y) == (sizeof(int32_t) * 1) &&
- offsetof(Vector4i, z) == (sizeof(int32_t) * 2) &&
- offsetof(Vector4i, w) == (sizeof(int32_t) * 3)),
-
- MATCHES_Vector3i = (MATCHES_int && (sizeof(Vector3i) == (sizeof(int32_t) * 3)) &&
- offsetof(Vector3i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector3i, y) == (sizeof(int32_t) * 1) &&
- offsetof(Vector3i, z) == (sizeof(int32_t) * 2)),
-
- MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
-
- MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) &&
- offsetof(Quaternion, x) == (sizeof(real_t) * 0) &&
- offsetof(Quaternion, y) == (sizeof(real_t) * 1) &&
- offsetof(Quaternion, z) == (sizeof(real_t) * 2) &&
- offsetof(Quaternion, w) == (sizeof(real_t) * 3)),
-
- MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) &&
- offsetof(Transform3D, basis) == 0 &&
- offsetof(Transform3D, origin) == sizeof(Basis)),
-
- MATCHES_Projection = (MATCHES_Vector4 && (sizeof(Projection) == (sizeof(Vector4) * 4))),
-
- MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
- offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
- offsetof(AABB, size) == (sizeof(Vector3) * 1)),
-
- MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) &&
- offsetof(Color, r) == (sizeof(float) * 0) &&
- offsetof(Color, g) == (sizeof(float) * 1) &&
- offsetof(Color, b) == (sizeof(float) * 2) &&
- offsetof(Color, a) == (sizeof(float) * 3)),
-
- MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) &&
- offsetof(Plane, normal) == 0 &&
- offsetof(Plane, d) == sizeof(Vector3))
-};
-
-// In the future we may force this if we want to ref return these structs
-#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
-/* clang-format off */
-static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && MATCHES_Vector4 &&
- MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_Projection && MATCHES_AABB && MATCHES_Color &&
- MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i && MATCHES_Vector4i);
-/* clang-format on */
-#endif
-} // namespace InteropLayout
-
-#pragma pack(push, 1)
-
-struct M_Vector2 {
- real_t x, y;
-
- static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) {
- return Vector2(p_from.x, p_from.y);
- }
-
- static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) {
- M_Vector2 ret = { p_from.x, p_from.y };
- return ret;
- }
-};
-
-struct M_Vector2i {
- int32_t x, y;
-
- static _FORCE_INLINE_ Vector2i convert_to(const M_Vector2i &p_from) {
- return Vector2i(p_from.x, p_from.y);
- }
-
- static _FORCE_INLINE_ M_Vector2i convert_from(const Vector2i &p_from) {
- M_Vector2i ret = { p_from.x, p_from.y };
- return ret;
- }
-};
-
-struct M_Rect2 {
- M_Vector2 position;
- M_Vector2 size;
-
- static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) {
- return Rect2(M_Vector2::convert_to(p_from.position),
- M_Vector2::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) {
- M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Rect2i {
- M_Vector2i position;
- M_Vector2i size;
-
- static _FORCE_INLINE_ Rect2i convert_to(const M_Rect2i &p_from) {
- return Rect2i(M_Vector2i::convert_to(p_from.position),
- M_Vector2i::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_Rect2i convert_from(const Rect2i &p_from) {
- M_Rect2i ret = { M_Vector2i::convert_from(p_from.position), M_Vector2i::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Transform2D {
- M_Vector2 elements[3];
-
- static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) {
- return Transform2D(p_from.elements[0].x, p_from.elements[0].y,
- p_from.elements[1].x, p_from.elements[1].y,
- p_from.elements[2].x, p_from.elements[2].y);
- }
-
- static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
- M_Transform2D ret = {
- M_Vector2::convert_from(p_from.columns[0]),
- M_Vector2::convert_from(p_from.columns[1]),
- M_Vector2::convert_from(p_from.columns[2])
- };
- return ret;
- }
-};
-
-struct M_Vector3 {
- real_t x, y, z;
-
- static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) {
- return Vector3(p_from.x, p_from.y, p_from.z);
- }
-
- static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) {
- M_Vector3 ret = { p_from.x, p_from.y, p_from.z };
- return ret;
- }
-};
-
-struct M_Vector3i {
- int32_t x, y, z;
-
- static _FORCE_INLINE_ Vector3i convert_to(const M_Vector3i &p_from) {
- return Vector3i(p_from.x, p_from.y, p_from.z);
- }
-
- static _FORCE_INLINE_ M_Vector3i convert_from(const Vector3i &p_from) {
- M_Vector3i ret = { p_from.x, p_from.y, p_from.z };
- return ret;
- }
-};
-
-struct M_Vector4 {
- real_t x, y, z, w;
-
- static _FORCE_INLINE_ Vector4 convert_to(const M_Vector4 &p_from) {
- return Vector4(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Vector4 convert_from(const Vector4 &p_from) {
- M_Vector4 ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Vector4i {
- int32_t x, y, z, w;
-
- static _FORCE_INLINE_ Vector4i convert_to(const M_Vector4i &p_from) {
- return Vector4i(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Vector4i convert_from(const Vector4i &p_from) {
- M_Vector4i ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Basis {
- M_Vector3 elements[3];
-
- static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) {
- return Basis(M_Vector3::convert_to(p_from.elements[0]),
- M_Vector3::convert_to(p_from.elements[1]),
- M_Vector3::convert_to(p_from.elements[2]));
- }
-
- static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
- M_Basis ret = {
- M_Vector3::convert_from(p_from.rows[0]),
- M_Vector3::convert_from(p_from.rows[1]),
- M_Vector3::convert_from(p_from.rows[2])
- };
- return ret;
- }
-};
-
-struct M_Quaternion {
- real_t x, y, z, w;
-
- static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) {
- return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) {
- M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Transform3D {
- M_Basis basis;
- M_Vector3 origin;
-
- static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) {
- return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
- }
-
- static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) {
- M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
- return ret;
- }
-};
-
-struct M_Projection {
- M_Vector4 vec1;
- M_Vector4 vec2;
- M_Vector4 vec3;
- M_Vector4 vec4;
-
- static _FORCE_INLINE_ Projection convert_to(const M_Projection &p_from) {
- return Projection(M_Vector4::convert_to(p_from.vec1), M_Vector4::convert_to(p_from.vec2), M_Vector4::convert_to(p_from.vec3), M_Vector4::convert_to(p_from.vec4));
- }
-
- static _FORCE_INLINE_ M_Projection convert_from(const Projection &p_from) {
- M_Projection ret = { M_Vector4::convert_from(p_from.matrix[0]), M_Vector4::convert_from(p_from.matrix[1]), M_Vector4::convert_from(p_from.matrix[2]), M_Vector4::convert_from(p_from.matrix[3]) };
- return ret;
- }
-};
-
-struct M_AABB {
- M_Vector3 position;
- M_Vector3 size;
-
- static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) {
- return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) {
- M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Color {
- float r, g, b, a;
-
- static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) {
- return Color(p_from.r, p_from.g, p_from.b, p_from.a);
- }
-
- static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) {
- M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a };
- return ret;
- }
-};
-
-struct M_Plane {
- M_Vector3 normal;
- real_t d;
-
- static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) {
- return Plane(M_Vector3::convert_to(p_from.normal), p_from.d);
- }
-
- static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) {
- M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d };
- return ret;
- }
-};
-
-#pragma pack(pop)
-
-#define DECL_TYPE_MARSHAL_TEMPLATES(m_type) \
- template <int> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from); \
- \
- template <> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) { \
- return M_##m_type::convert_to(*p_from); \
- } \
- \
- template <> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) { \
- return *reinterpret_cast<const m_type *>(p_from); \
- } \
- \
- _FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) { \
- return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
- } \
- \
- template <int> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from); \
- \
- template <> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \
- return M_##m_type::convert_from(p_from); \
- } \
- \
- template <> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \
- return *reinterpret_cast<const M_##m_type *>(&p_from); \
- } \
- \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) { \
- return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
- }
-
-DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector2i)
-DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
-DECL_TYPE_MARSHAL_TEMPLATES(Rect2i)
-DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector3i)
-DECL_TYPE_MARSHAL_TEMPLATES(Basis)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector4)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector4i)
-DECL_TYPE_MARSHAL_TEMPLATES(Quaternion)
-DECL_TYPE_MARSHAL_TEMPLATES(Transform3D)
-DECL_TYPE_MARSHAL_TEMPLATES(Projection)
-DECL_TYPE_MARSHAL_TEMPLATES(AABB)
-DECL_TYPE_MARSHAL_TEMPLATES(Color)
-DECL_TYPE_MARSHAL_TEMPLATES(Plane)
-#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
-#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
} // namespace GDMonoMarshal
#endif // GD_MONO_MARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 6734b44783..04f6005338 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -75,10 +75,6 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
// clear the cache
method_info_fetched = false;
method_info = MethodInfo();
-
- for (int i = 0; i < params_count; i++) {
- params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]);
- }
}
GDMonoClass *GDMonoMethod::get_enclosing_class() const {
@@ -111,15 +107,14 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
MonoObject *ret;
if (params_count > 0) {
- void **params = (void **)alloca(params_count * sizeof(void *));
- uint8_t *buffer = (uint8_t *)alloca(params_buffer_size);
- unsigned int offset = 0;
+ MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
for (int i = 0; i < params_count; i++) {
- params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset);
+ MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object_of_type(p_params[i], param_types[i]);
+ mono_array_setref(params, i, boxed_param);
}
- ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc);
+ ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
} else {
ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index be11ef5bfe..5398f34103 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -39,7 +39,6 @@ class GDMonoMethod : public IMonoClassMember {
StringName name;
uint16_t params_count;
- unsigned int params_buffer_size = 0;
ManagedType return_type;
Vector<ManagedType> param_types;
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index c9775ae9cb..7cbf5be151 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -65,8 +65,6 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own
type.type_class = GDMono::get_singleton()->get_class(param_type_class);
}
- param_buffer_size = GDMonoMarshal::variant_get_managed_unboxed_size(type);
-
attrs_fetched = false;
attributes = nullptr;
}
@@ -150,19 +148,16 @@ bool GDMonoProperty::has_setter() {
}
void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) {
- uint8_t *buffer = (uint8_t *)alloca(param_buffer_size);
- unsigned int offset = 0;
-
- void *params[1] = {
- GDMonoMarshal::variant_to_managed_unboxed(p_value, type, buffer, offset)
- };
+ MonoMethod *set_method = mono_property_get_set_method(mono_property);
+ ERR_FAIL_COND(set_method == nullptr);
-#ifdef DEBUG_ENABLED
- CRASH_COND(offset != param_buffer_size);
-#endif
+ // Temporary solution, while moving code to C#
+ MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
+ MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object_of_type(p_value, type);
+ mono_array_setref(params, 0, boxed_param);
MonoException *exc = nullptr;
- GDMonoUtils::property_set_value(mono_property, p_object, params, &exc);
+ GDMonoUtils::runtime_invoke_array(set_method, p_object, params, &exc);
if (exc) {
if (r_exc) {
*r_exc = exc;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 6fc681aeb5..885ea8f011 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -45,8 +45,6 @@ class GDMonoProperty : public IMonoClassMember {
bool attrs_fetched;
MonoCustomAttrInfo *attributes = nullptr;
- unsigned int param_buffer_size;
-
public:
virtual GDMonoClass *get_enclosing_class() const final { return owner; }
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 1983d6ebe2..e240381112 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -170,13 +170,6 @@ void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoExcep
ctor->invoke_raw(p_this_obj, nullptr, r_exc);
}
-bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b) {
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(Delegate, Equals).invoke((MonoObject *)p_a, (MonoObject *)p_b, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
GDMonoClass *get_object_class(MonoObject *p_object) {
return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
}
@@ -239,102 +232,6 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
return mono_object;
}
-MonoObject *create_managed_from(const StringName &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(StringName));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(StringName));
-
- CACHED_FIELD(StringName, ptr)->set_value_raw(mono_object, memnew(StringName(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const NodePath &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath));
-
- CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const RID &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID));
-
- CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Search constructor that takes a pointer as parameter
- MonoMethod *m;
- void *iter = nullptr;
- while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
- if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
- MonoMethodSignature *sig = mono_method_signature(m);
- void *front = nullptr;
- if (mono_signature_get_param_count(sig) == 1 &&
- mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
- break;
- }
- }
- }
-
- CRASH_COND(m == nullptr);
-
- Array *new_array = memnew(Array(p_from));
- void *args[1] = { &new_array };
-
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Search constructor that takes a pointer as parameter
- MonoMethod *m;
- void *iter = nullptr;
- while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
- if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
- MonoMethodSignature *sig = mono_method_signature(m);
- void *front = nullptr;
- if (mono_signature_get_param_count(sig) == 1 &&
- mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
- break;
- }
- }
- }
-
- CRASH_COND(m == nullptr);
-
- Dictionary *new_dict = memnew(Dictionary(p_from));
- void *args[1] = { &new_dict };
-
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
MonoDomain *create_domain(const String &p_friendly_name) {
print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
@@ -487,6 +384,13 @@ MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, M
return ret;
}
+MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
+ GD_MONO_BEGIN_RUNTIME_INVOKE;
+ MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
+ GD_MONO_END_RUNTIME_INVOKE;
+ return ret;
+}
+
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
@@ -558,62 +462,6 @@ namespace Marshal {
{ return m_ret; }
#endif
-bool type_is_generic_array(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_system_generic_list(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericList).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_ienumerable(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIEnumerable).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_icollection(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericICollection).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
NO_GLUE_RET(false);
MonoException *exc = nullptr;
@@ -622,39 +470,6 @@ bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
return (bool)res;
}
-void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
- NO_GLUE_RET(nullptr);
- MonoException *exc = nullptr;
- MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
-}
-
-GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- NO_GLUE_RET(nullptr);
- MonoException *exc = nullptr;
- MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
-}
} // namespace Marshal
ScopeThreadAttach::ScopeThreadAttach() {
@@ -671,7 +486,6 @@ ScopeThreadAttach::~ScopeThreadAttach() {
StringName get_native_godot_class_name(GDMonoClass *p_class) {
MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr);
- StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj));
- return ptr ? *ptr : StringName();
+ return (StringName)GDMonoMarshal::mono_object_to_variant(native_name_obj);
}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 300cacfa4b..ee1be979e7 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,23 +53,7 @@
namespace GDMonoUtils {
namespace Marshal {
-
-bool type_is_generic_array(MonoReflectionType *p_reftype);
-bool type_is_generic_dictionary(MonoReflectionType *p_reftype);
-bool type_is_system_generic_list(MonoReflectionType *p_reftype);
-bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
-bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
-bool type_is_generic_icollection(MonoReflectionType *p_reftype);
-bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
bool type_has_flags_attribute(MonoReflectionType *p_reftype);
-
-void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
-
-void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
-void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
-
-GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
-GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
} // namespace Marshal
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
@@ -97,20 +81,12 @@ void free_gchandle(uint32_t p_gchandle);
void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr);
-bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b);
-
GDMonoClass *get_object_class(MonoObject *p_object);
GDMonoClass *type_get_proxy_class(const StringName &p_type);
GDMonoClass *get_class_native_base(GDMonoClass *p_class);
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
-MonoObject *create_managed_from(const StringName &p_from);
-MonoObject *create_managed_from(const NodePath &p_from);
-MonoObject *create_managed_from(const RID &p_from);
-MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
-MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
-
MonoDomain *create_domain(const String &p_friendly_name);
String get_type_desc(MonoType *p_type);
@@ -141,6 +117,7 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
}
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
+MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 437c4ca54a..f26459554c 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -92,6 +92,10 @@ ObjectID SignalAwaiterCallable::get_object() const {
return target_id;
}
+StringName SignalAwaiterCallable::get_signal() const {
+ return signal;
+}
+
void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 532aa3e327..4f4986baf3 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -38,7 +38,12 @@
Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter);
-class SignalAwaiterCallable : public CallableCustom {
+class BaseSignalCallable : public CallableCustom {
+public:
+ virtual StringName get_signal() const = 0;
+};
+
+class SignalAwaiterCallable : public BaseSignalCallable {
ObjectID target_id;
MonoGCHandleData awaiter_handle;
StringName signal;
@@ -59,7 +64,7 @@ public:
ObjectID get_object() const override;
- _FORCE_INLINE_ StringName get_signal() const { return signal; }
+ StringName get_signal() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
@@ -67,7 +72,7 @@ public:
~SignalAwaiterCallable();
};
-class EventSignalCallable : public CallableCustom {
+class EventSignalCallable : public BaseSignalCallable {
Object *owner = nullptr;
const CSharpScript::EventSignal *event_signal;
@@ -87,7 +92,7 @@ public:
ObjectID get_object() const override;
- StringName get_signal() const;
+ StringName get_signal() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 975f2d8332..b0f94310b8 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -65,7 +65,7 @@ int sfind(const String &p_text, int p_from) {
break;
case 1: {
char32_t c = src[read_pos];
- found = src[read_pos] == 's' || (c >= '0' && c <= '4');
+ found = src[read_pos] == 's' || (c >= '0' && c <= '5');
break;
}
default:
@@ -86,32 +86,13 @@ int sfind(const String &p_text, int p_from) {
}
} // namespace
-String sformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
+String sformat(const String &p_text, const String &p1, const String &p2,
+ const String &p3, const String &p4, const String &p5, const String &p6) {
if (p_text.length() < 2) {
return p_text;
}
- Array args;
-
- if (p1.get_type() != Variant::NIL) {
- args.push_back(p1);
-
- if (p2.get_type() != Variant::NIL) {
- args.push_back(p2);
-
- if (p3.get_type() != Variant::NIL) {
- args.push_back(p3);
-
- if (p4.get_type() != Variant::NIL) {
- args.push_back(p4);
-
- if (p5.get_type() != Variant::NIL) {
- args.push_back(p5);
- }
- }
- }
- }
- }
+ String args[6] = { p1, p2, p3, p4, p5, p6 };
String new_string;
@@ -125,7 +106,7 @@ String sformat(const String &p_text, const Variant &p1, const Variant &p2, const
int req_index = (c == 's' ? findex++ : c - '0');
new_string += p_text.substr(search_from, result - search_from);
- new_string += args[req_index].operator String();
+ new_string += args[req_index];
search_from = result + 2;
}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index fa4c5e89f4..b00dd9dde8 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -36,7 +36,8 @@
#include <stdarg.h>
-String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+String sformat(const String &p_text, const String &p1 = String(), const String &p2 = String(),
+ const String &p3 = String(), const String &p4 = String(), const String &p5 = String(), const String &p6 = String());
#ifdef TOOLS_ENABLED
bool is_csharp_keyword(const String &p_name);