C#: Move marshaling logic and generated glue to C#

We will be progressively moving most code to C#.
The plan is to only use Mono's embedding APIs to set things at launch.
This will make it much easier to later support CoreCLR too which
doesn't have rich embedding APIs.

Additionally the code in C# is more maintainable and makes it easier
to implement new features, e.g.: runtime codegen which we could use to
avoid using reflection for marshaling everytime a field, property or
method is accessed.

SOME NOTES ON INTEROP

We make the same assumptions as GDNative about the size of the Godot
structures we use. We take it a bit further by also assuming the layout
of fields in some cases, which is riskier but let's us squeeze out some
performance by avoiding unnecessary managed to native calls.

Code that deals with native structs is less safe than before as there's
no RAII and copy constructors in C#. It's like using the GDNative C API
directly. One has to take special care to free values they own.
Perhaps we could use roslyn analyzers to check this, but I don't know
any that uses attributes to determine what's owned or borrowed.

As to why we maily use pointers for native structs instead of ref/out:
- AFAIK (and confirmed with a benchmark) ref/out are pinned
  during P/Invoke calls and that has a cost.
- Native struct fields can't be ref/out in the first place.
- A `using` local can't be passed as ref/out, only `in`. Calling a
  method or property on an `in` value makes a silent copy, so we want
  to avoid `in`.

REGARDING THE BUILD SYSTEM

There's no longer a `mono_glue=yes/no` SCons options. We no longer
need to build with `mono_glue=no`, generate the glue and then build
again with `mono_glue=yes`. We build only once and generate the glue
(which is in C# now).
However, SCons no longer builds the C# projects for us. Instead one
must run `build_assemblies.py`, e.g.:
```sh
%godot_src_root%/modules/mono/build_scripts/build_assemblies.py \
        --godot-output-dir=%godot_src_root%/bin \
        --godot-target=release_debug`
```
We could turn this into a custom build target, but I don't know how
to do that with SCons (it's possible with Meson).

OTHER NOTES

Most of the moved code doesn't follow the C# naming convention and
still has the word Mono in the names despite no longer dealing with
Mono's embedding APIs. This is just temporary while transitioning,
to make it easier to understand what was moved where.
This commit is contained in:
Ignacio Roldán Etcheverry 2021-05-03 15:21:06 +02:00
parent 4f640762f7
commit 483071716e
67 changed files with 5178 additions and 5325 deletions

View file

@ -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")
@ -60,3 +29,5 @@ if env["platform"] in ["osx", "iphone"]:
if env["tools"]:
env_mono.add_source_files(env.modules_sources, "editor/*.cpp")
env_mono.Prepend(CPPPATH=["#modules/gdnative/include/"])

View file

@ -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

View file

@ -0,0 +1,301 @@
#!/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, godot_target, 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 godot_target == "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("--godot-target", choices=["debug", "release_debug", "release"], type=str, required=True)
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_target, args.godot_platform)
sys.exit(exit_code)
if __name__ == "__main__":
main()

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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")

View file

@ -2,7 +2,7 @@ supported_platforms = ["windows", "osx", "linuxbsd", "server", "android", "haiku
def can_build(env, platform):
return True
return env["module_gdnative_enabled"]
def configure(env):
@ -36,7 +36,6 @@ def configure(env):
)
)
envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static))
envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True))
envvars.Add(BoolVariable("build_cil", "Build C# solutions", True))
envvars.Add(
BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True)

View file

@ -54,6 +54,7 @@
#include "editor/editor_internal_calls.h"
#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"
@ -105,6 +106,9 @@ Error CSharpLanguage::execute_file(const String &p_path) {
return OK;
}
extern void *godotsharp_pinvoke_funcs[95];
[[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")) {
@ -115,20 +119,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();
@ -844,13 +846,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);
@ -1169,10 +1171,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);
@ -1181,7 +1184,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");
}
@ -1309,7 +1312,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();
@ -1322,8 +1325,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
@ -1657,7 +1659,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
GDMonoProperty *property = top->get_property(p_name);
if (property) {
property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type()));
property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object_of_type(p_value, property->get_type()));
return true;
}
@ -1794,7 +1796,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);

View file

@ -393,7 +393,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;

File diff suppressed because it is too large Load diff

View file

@ -218,6 +218,11 @@ class BindingsGenerator {
bool is_singleton = false;
bool is_ref_counted = false;
/**
* Determines whether the
*/
bool c_type_is_disposable_struct = false;
/**
* Used only by Object-derived types.
* Determines if this type is not abstract (incomplete).
@ -232,32 +237,35 @@ 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,
@ -281,7 +289,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;
@ -320,6 +329,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.
@ -328,7 +338,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;
@ -338,16 +350,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;
@ -402,8 +404,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];
}
@ -437,65 +439,26 @@ 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;
bool is_vararg;
TypeReference return_type;
List<TypeReference> argument_types;
_FORCE_INLINE_ int get_arguments_count() const { return argument_types.size(); }
InternalCall() {}
InternalCall(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 = false;
}
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()) {
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;
}
@ -510,7 +473,6 @@ class BindingsGenerator {
OrderedHashMap<StringName, TypeInterface> obj_types;
Map<StringName, TypeInterface> placeholder_types;
Map<StringName, TypeInterface> builtin_types;
Map<StringName, TypeInterface> enum_types;
@ -518,13 +480,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.
Map<const MethodInterface *, const InternalCall *> method_icalls_map;
List<const InternalCall *> generated_icall_funcs;
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
Map<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
@ -536,6 +494,8 @@ class BindingsGenerator {
StringName type_Object = StaticCString::create("Object");
StringName type_RefCounted = StaticCString::create("RefCounted");
StringName type_RID = StaticCString::create("RID");
StringName type_Callable = StaticCString::create("Callable");
StringName type_Signal = StaticCString::create("Signal");
StringName type_String = StaticCString::create("String");
StringName type_StringName = StaticCString::create("StringName");
StringName type_NodePath = StaticCString::create("NodePath");
@ -601,17 +561,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) {
@ -622,10 +571,9 @@ 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";
@ -634,15 +582,27 @@ class BindingsGenerator {
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";
}
return p_type->name;
}
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
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);
StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
@ -661,11 +621,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;
@ -676,15 +636,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() {

View file

@ -43,7 +43,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/osx_utils.h"

View file

@ -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>

View file

@ -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
{
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
{
ArraySafeHandle safeHandle;
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 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 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 extern static IntPtr godot_icall_Array_Ctor();
internal static extern void godot_icall_Array_Ctor(out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array);
internal static extern void godot_icall_Array_Ctor_MonoArray(System.Array array, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
internal static extern void godot_icall_Array_At(ref godot_array ptr, int index, out godot_variant elem);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
internal static extern void godot_icall_Array_SetAt(ref godot_array ptr, int index, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
internal static extern int godot_icall_Array_Count(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
internal static extern int godot_icall_Array_Add(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Array_Count(IntPtr ptr);
internal static extern void godot_icall_Array_Clear(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
internal static extern void godot_icall_Array_Concatenate(ref godot_array left, ref godot_array right, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Clear(IntPtr ptr);
internal static extern bool godot_icall_Array_Contains(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right);
internal static extern void godot_icall_Array_CopyTo(ref godot_array ptr, System.Array array, int arrayIndex);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
internal static extern void godot_icall_Array_Duplicate(ref godot_array ptr, bool deep, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
internal static extern int godot_icall_Array_IndexOf(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep);
internal static extern void godot_icall_Array_Insert(ref godot_array ptr, int index, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
internal static extern bool godot_icall_Array_Remove(ref godot_array ptr, object item);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
internal static extern void godot_icall_Array_RemoveAt(ref godot_array ptr, int index);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
internal static extern Error godot_icall_Array_Resize(ref godot_array ptr, int newSize);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
internal static extern Error godot_icall_Array_Shuffle(ref godot_array ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static Error godot_icall_Array_Shuffle(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_Array_ToString(IntPtr ptr);
internal static extern string godot_icall_Array_ToString(ref godot_array 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,27 @@ 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
{
Array objectArray;
private readonly Array _underlyingArray;
internal static int elemTypeEncoding;
internal static IntPtr 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
static Array()
{
Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
}
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 +360,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 +374,8 @@ namespace Godot.Collections
{
throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
}
objectArray = new Array(array);
_underlyingArray = new Array(array);
}
/// <summary>
@ -395,23 +384,12 @@ namespace Godot.Collections
/// <param name="array">The untyped array to construct from.</param>
public Array(Array array)
{
objectArray = array;
_underlyingArray = array;
}
internal Array(IntPtr handle)
{
objectArray = new Array(handle);
}
internal Array(ArraySafeHandle handle)
{
objectArray = new Array(handle);
}
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 +397,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 +407,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 +417,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 +425,7 @@ namespace Godot.Collections
/// </summary>
public void Shuffle()
{
objectArray.Shuffle();
_underlyingArray.Shuffle();
}
/// <summary>
@ -458,7 +436,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 +447,16 @@ namespace Godot.Collections
/// <value>The value at the given 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 +467,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 +480,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 +489,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 +499,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 +511,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 +519,7 @@ namespace Godot.Collections
/// </summary>
public void Clear()
{
objectArray.Clear();
_underlyingArray.Clear();
}
/// <summary>
@ -546,7 +529,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 +546,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 +566,7 @@ namespace Godot.Collections
/// <returns>A 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 +577,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();
}
}

View file

@ -727,7 +727,7 @@ namespace Godot
/// (in the YXZ convention: when *composing*, first Y, then X, and Z last),
/// given in the vector format as (X angle, Y angle, Z angle).
///
/// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which
/// Consider using the <see cref="Basis(Godot.Quaternion)"/> constructor instead, which
/// uses a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles.
/// </summary>
/// <param name="eulerYXZ">The Euler angles to create the basis from.</param>

View file

@ -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;

View file

@ -2,48 +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
{
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 :
public sealed class Dictionary :
IDictionary,
IDisposable
{
DictionarySafeHandle safeHandle;
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>
@ -60,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>
@ -83,16 +59,14 @@ namespace Godot.Collections
/// </summary>
public void Dispose()
{
if (disposed)
return;
Dispose(true);
GC.SuppressFinalize(this);
}
if (safeHandle != null)
{
safeHandle.Dispose();
safeHandle = null;
}
disposed = true;
public void Dispose(bool disposing)
{
// Always dispose `NativeValue` even if disposing is true
NativeValue.Dispose();
}
/// <summary>
@ -102,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
@ -114,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);
}
}
@ -126,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);
}
@ -149,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>
@ -159,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"/>.
@ -183,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
@ -196,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
@ -260,7 +248,7 @@ namespace Godot.Collections
private void UpdateEntry()
{
dirty = false;
godot_icall_Dictionary_KeyValuePairAt(dictionary.GetPtr(), index, out object key, out object value);
godot_icall_Dictionary_KeyValuePairAt(ref dictionary.NativeValue, index, out object key, out object value);
entry = new DictionaryEntry(key, value);
}
@ -288,73 +276,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 extern static IntPtr godot_icall_Dictionary_Ctor();
internal static extern void godot_icall_Dictionary_Ctor(out godot_dictionary dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
internal static extern void godot_icall_Dictionary_GetValue(ref godot_dictionary ptr, object key, out godot_variant value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
internal static extern void godot_icall_Dictionary_SetValue(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass);
internal static extern void godot_icall_Dictionary_Keys(ref godot_dictionary ptr, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
internal static extern void godot_icall_Dictionary_Values(ref godot_dictionary ptr, out godot_array dest);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Dictionary_Keys(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 extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
internal static extern void godot_icall_Dictionary_KeyValuePairAt(ref godot_dictionary ptr, int index, out object key, out object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
internal static extern void godot_icall_Dictionary_Add(ref godot_dictionary ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values);
internal static extern int godot_icall_Dictionary_Count(ref godot_dictionary ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value);
internal static extern void godot_icall_Dictionary_Clear(ref godot_dictionary ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static 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 extern static 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 extern static 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 extern static 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 extern static 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 extern static 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 extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr);
internal static extern string godot_icall_Dictionary_ToString(ref godot_dictionary 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
@ -363,25 +348,30 @@ 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;
// 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);
static Dictionary()
{
Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass);
}
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 +381,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 +397,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 +410,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 +420,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 +431,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 +450,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,14 +463,15 @@ 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(GetPtr(), index, out object key, out object value);
Dictionary.godot_icall_Dictionary_KeyValuePairAt(ref _underlyingDict.NativeValue, index, out object key, out object value);
return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
}
@ -500,7 +483,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 +493,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 +502,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 +513,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 +535,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 +549,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 +585,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 +602,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();
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using Godot.Collections;
using Godot.NativeInterop;
namespace Godot
{
@ -8,10 +9,12 @@ namespace Godot
{
public Array<T> GetNodesInGroup<T>(StringName group) where T : class
{
return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(Object.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 extern static 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);
}
}

View file

@ -6,6 +6,7 @@ using real_t = System.Single;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
// TODO: Add comments describing what this class does. It is not obvious.
@ -13,9 +14,10 @@ namespace Godot
{
public static partial class GD
{
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);
}
public static object Convert(object what, Variant.Type type)
@ -180,12 +182,17 @@ namespace Godot
public static bool TypeExists(StringName type)
{
return godot_icall_GD_type_exists(StringName.GetPtr(type));
return godot_icall_GD_type_exists(ref type.NativeValue);
}
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);
}
}
public static string Var2Str(object var)
@ -199,73 +206,73 @@ namespace Godot
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static 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 extern static object godot_icall_GD_convert(object what, Variant.Type type);
internal static extern object godot_icall_GD_convert(object what, Variant.Type type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_GD_hash(object var);
internal static extern int godot_icall_GD_hash(object var);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static Object godot_icall_GD_instance_from_id(ulong instanceId);
internal static extern Object godot_icall_GD_instance_from_id(ulong instanceId);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_print(object[] what);
internal static extern void godot_icall_GD_print(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_printerr(object[] what);
internal static extern void godot_icall_GD_printerr(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_printraw(object[] what);
internal static extern void godot_icall_GD_printraw(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_prints(object[] what);
internal static extern void godot_icall_GD_prints(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_printt(object[] what);
internal static extern void godot_icall_GD_printt(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static float godot_icall_GD_randf();
internal static extern float godot_icall_GD_randf();
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static uint godot_icall_GD_randi();
internal static extern uint godot_icall_GD_randi();
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_randomize();
internal static extern void godot_icall_GD_randomize();
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static double godot_icall_GD_randf_range(double from, double to);
internal static extern double godot_icall_GD_randf_range(double from, double to);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_GD_randi_range(int from, int to);
internal static extern int godot_icall_GD_randi_range(int from, int to);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
internal static extern uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_seed(ulong seed);
internal static extern void godot_icall_GD_seed(ulong seed);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_str(object[] what);
internal static extern string godot_icall_GD_str(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_GD_str2var(string str);
internal static extern object godot_icall_GD_str2var(string str);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static 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 extern static 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 extern static string godot_icall_GD_var2str(object var);
internal static extern string godot_icall_GD_var2str(object var);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_pusherror(string type);
internal static extern void godot_icall_GD_pusherror(string type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_pushwarning(string type);
internal static extern void godot_icall_GD_pushwarning(string type);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern Variant.Type godot_icall_TypeToVariantType(Type type);

View file

@ -1,62 +0,0 @@
using System;
using System.Collections.Generic;
namespace Godot
{
static class MarshalUtils
{
/// <summary>
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
/// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
/// </exception>
static bool TypeIsGenericArray(Type type) =>
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
/// <summary>
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
/// is <see cref="Godot.Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
/// </summary>
/// <exception cref="System.InvalidOperationException">
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
/// </exception>
static bool TypeIsGenericDictionary(Type type) =>
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
static bool TypeIsSystemGenericList(Type type) =>
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>);
static bool TypeIsSystemGenericDictionary(Type type) =>
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.Dictionary<,>);
static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>);
static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
static void ArrayGetElementType(Type arrayType, out Type elementType)
{
elementType = arrayType.GetGenericArguments()[0];
}
static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
{
var genericArgs = dictionaryType.GetGenericArguments();
keyType = genericArgs[0];
valueType = genericArgs[1];
}
static Type MakeGenericArrayType(Type elemType)
{
return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
}
static Type MakeGenericDictionaryType(Type keyType, Type valueType)
{
return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
}
}
}

View file

@ -0,0 +1,428 @@
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;
Godot.Variant.Type expected;
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
internal struct godot_variant : IDisposable
{
[FieldOffset(0)] public Godot.Variant.Type _type;
// There's padding here
[FieldOffset(8)] internal godot_variant_data _data;
[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)] 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;
}
}
}

View file

@ -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));
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
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_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_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 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 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);
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -0,0 +1,305 @@
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 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 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 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 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);
}
}

View file

@ -1,24 +1,12 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
{
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()
{
@ -31,112 +19,105 @@ 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;
}
public NodePath() : this(string.Empty) {}
// Explicit name to make it very clear
internal static NodePath CreateTakingOwnershipOfDisposableValue(godot_node_path nativeValueToOwn)
=> new NodePath(nativeValueToOwn);
public NodePath()
{
}
public NodePath(string path)
{
ptr = godot_icall_NodePath_Ctor(path);
if (!string.IsNullOrEmpty(path))
NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path);
}
public static implicit operator NodePath(string from) => new NodePath(from);
public static implicit operator string(NodePath from) => from.ToString();
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);
}
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);
}
public string GetConcatenatedSubnames()
public string GetConcatenatedSubNames()
{
return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this));
return godot_icall_NodePath_get_concatenated_subnames(ref NativeValue);
}
public string GetName(int idx)
{
return godot_icall_NodePath_get_name(GetPtr(this), idx);
return godot_icall_NodePath_get_name(ref NativeValue, idx);
}
public int GetNameCount()
{
return godot_icall_NodePath_get_name_count(GetPtr(this));
return godot_icall_NodePath_get_name_count(ref NativeValue);
}
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);
}
public int GetSubnameCount()
public int GetSubNameCount()
{
return godot_icall_NodePath_get_subname_count(GetPtr(this));
return godot_icall_NodePath_get_subname_count(ref NativeValue);
}
public bool IsAbsolute()
{
return godot_icall_NodePath_is_absolute(GetPtr(this));
return godot_icall_NodePath_is_absolute(ref NativeValue);
}
public bool IsEmpty()
{
return godot_icall_NodePath_is_empty(GetPtr(this));
}
public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr godot_icall_NodePath_Ctor(string path);
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 void godot_icall_NodePath_Dtor(IntPtr ptr);
private static extern string godot_icall_NodePath_get_concatenated_subnames(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string godot_icall_NodePath_operator_String(IntPtr ptr);
private static extern string godot_icall_NodePath_get_name(ref godot_node_path ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
private static extern int godot_icall_NodePath_get_name_count(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
private static extern string godot_icall_NodePath_get_subname(ref godot_node_path ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
private static extern int godot_icall_NodePath_get_subname_count(ref godot_node_path ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool godot_icall_NodePath_is_absolute(IntPtr 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);
}
}

View file

@ -5,44 +5,50 @@ namespace Godot
{
public partial class Object : IDisposable
{
private bool disposed = false;
private bool _disposed = false;
private static StringName nativeName = "Object";
internal IntPtr ptr;
internal bool memoryOwn;
internal IntPtr NativePtr;
internal bool MemoryOwn;
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;
}
public IntPtr NativeInstance
{
get { return ptr; }
}
public IntPtr NativeInstance => NativePtr;
internal static IntPtr GetPtr(Object instance)
{
if (instance == null)
return IntPtr.Zero;
if (instance.disposed)
if (instance._disposed)
throw new ObjectDisposedException(instance.GetType().FullName);
return instance.ptr;
return instance.NativePtr;
}
~Object()
@ -58,25 +64,25 @@ namespace Godot
protected virtual void Dispose(bool disposing)
{
if (disposed)
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);
}
this.ptr = IntPtr.Zero;
this.NativePtr = IntPtr.Zero;
}
disposed = true;
_disposed = true;
}
public override string ToString()
@ -117,13 +123,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)
{
return godot_icall_Object_ClassDB_get_method(StringName.GetPtr(type), 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;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr godot_icall_Object_Ctor(Object obj);
#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)
{
// 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;
}
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);
@ -136,9 +178,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);
}
}

View file

@ -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;
}
}
}
}
}

View file

@ -1,84 +1,25 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Godot.NativeInterop;
namespace Godot
{
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)
internal RID(ulong id)
{
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);
}
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)
{
this.ptr = ptr;
}
public IntPtr NativeInstance
{
get { return ptr; }
}
internal RID()
{
this.ptr = IntPtr.Zero;
_id = id;
}
public RID(Object from)
{
this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from));
}
=> _id = from is Resource res ? res.GetRid()._id : default;
public int GetId()
{
return godot_icall_RID_get_id(RID.GetPtr(this));
}
public ulong Id => _id;
public override string ToString() => "[RID]";
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_RID_Ctor(IntPtr from);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_RID_Dtor(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_RID_get_id(IntPtr ptr);
public override string ToString() => $"RID({Id})";
}
}

View file

@ -1,53 +1,42 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
{
public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
{
private bool completed;
private object[] result;
private Action action;
private bool _completed;
private object[] _result;
private Action _action;
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 extern static 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;
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)
{
completed = true;
result = args;
_completed = true;
_result = args;
if (action != null)
if (_action != null)
{
action();
_action();
}
}
}

View file

@ -192,7 +192,7 @@ namespace Godot
/// </summary>
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");
@ -215,7 +215,7 @@ namespace Godot
/// </summary>
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");
@ -732,7 +732,7 @@ namespace Godot
/// </summary>
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");

View file

@ -1,22 +1,12 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
{
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()
{
@ -29,54 +19,47 @@ 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);
public StringName()
{
ptr = IntPtr.Zero;
}
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);
}
public static implicit operator StringName(string from) => new StringName(from);
public static implicit operator string(StringName from) => from.ToString();
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);
}
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);
}
}

View file

@ -7,10 +7,19 @@
<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" />
@ -44,16 +53,23 @@
<Compile Include="Core\Interfaces\IAwaitable.cs" />
<Compile Include="Core\Interfaces\IAwaiter.cs" />
<Compile Include="Core\Interfaces\ISerializationListener.cs" />
<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\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" />

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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

View file

@ -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_Ctor(Array *r_dest) {
memnew_placement(r_dest, Array);
}
void godot_icall_Array_Dtor(Array *ptr) {
memdelete(ptr);
}
MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
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));
}
MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
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), 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,27 +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_Ctor(Dictionary *r_dest) {
memnew_placement(r_dest, Dictionary);
}
void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
memdelete(ptr);
}
MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
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());
@ -195,35 +168,22 @@ MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
#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);
}
MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
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, 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) {
@ -231,16 +191,14 @@ int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
}
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);
memnew_placement(*keys, Array(ptr->keys()));
memnew_placement(*values, Array(ptr->values()));
return ptr->size();
}
void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) {
Array *keys = godot_icall_Dictionary_Keys(ptr);
Array *values = godot_icall_Dictionary_Values(ptr);
*key = GDMonoMarshal::variant_to_mono_object(keys->get(index));
*value = GDMonoMarshal::variant_to_mono_object(values->get(index));
*key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index));
*value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index));
}
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
@ -267,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) {
@ -288,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) {
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);
*value = ret;
return true;
}
MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == nullptr) {
*value = nullptr;
return false;
}
*value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
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());
}
@ -323,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);
@ -340,13 +278,10 @@ 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);
@ -361,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

View file

@ -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.");
}
@ -260,18 +257,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) {
@ -317,5 +313,3 @@ void godot_register_gd_icalls() {
// Dispatcher
GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
}
#endif // MONO_GLUE_ENABLED

View file

@ -1,84 +0,0 @@
/*************************************************************************/
/* glue_header.h */
/*************************************************************************/
/* 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. */
/*************************************************************************/
#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_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_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

View file

@ -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();
}
@ -72,18 +57,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_subnames", godot_icall_NodePath_get_concatenated_subnames);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
@ -91,7 +69,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

View file

@ -1,5 +1,5 @@
/*************************************************************************/
/* rid_glue.cpp */
/* placeholder_glue.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -28,37 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef MONO_GLUE_ENABLED
#include "core/object/object.h"
#include "core/io/resource.h"
#include "core/object/class_db.h"
#include "core/templates/rid.h"
#include "../mono_gd/gd_mono_internals.h"
#include "../mono_gd/gd_mono_utils.h"
#include "../mono_gd/gd_mono_marshal.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);
MonoObject *godot_icall_InteropUtils_unmanaged_get_managed(Object *unmanaged) {
return GDMonoUtils::unmanaged_get_managed(unmanaged);
}
void godot_icall_RID_Dtor(RID *p_ptr) {
ERR_FAIL_NULL(p_ptr);
memdelete(p_ptr);
void godot_icall_InteropUtils_tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
GDMonoInternals::tie_managed_to_unmanaged(managed, unmanaged);
}
uint32_t godot_icall_RID_get_id(RID *p_ptr) {
return p_ptr->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);
}
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);
}
#endif // MONO_GLUE_ENABLED

View file

@ -0,0 +1,649 @@
/*************************************************************************/
/* 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 <gdnative/gdnative.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_byte_array godotsharp_packed_byte_array_new_mem_copy(const uint8_t *p_src, int32_t p_length) {
godot_packed_byte_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_int32_array godotsharp_packed_int32_array_new_mem_copy(const int32_t *p_src, int32_t p_length) {
godot_packed_int32_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_int64_array godotsharp_packed_int64_array_new_mem_copy(const int64_t *p_src, int32_t p_length) {
godot_packed_int64_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_float32_array godotsharp_packed_float32_array_new_mem_copy(const float *p_src, int32_t p_length) {
godot_packed_float32_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_float64_array godotsharp_packed_float64_array_new_mem_copy(const double *p_src, int32_t p_length) {
godot_packed_float64_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_vector2_array godotsharp_packed_vector2_array_new_mem_copy(const Vector2 *p_src, int32_t p_length) {
godot_packed_vector2_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_vector3_array godotsharp_packed_vector3_array_new_mem_copy(const Vector3 *p_src, int32_t p_length) {
godot_packed_vector3_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_color_array godotsharp_packed_color_array_new_mem_copy(const Color *p_src, int32_t p_length) {
godot_packed_color_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(godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret) {
godot_method_bind_ptrcall(p_method_bind, p_instance, p_args, p_ret);
}
GD_PINVOKE_EXPORT godot_variant godotsharp_method_bind_call(godot_method_bind *p_method_bind, godot_object *p_instance, const godot_variant **p_args, const int p_arg_count, godot_variant_call_error *p_call_error) {
return godot_method_bind_call(p_method_bind, p_instance, p_args, p_arg_count, p_call_error);
}
// variant.h
GD_PINVOKE_EXPORT void godotsharp_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s) {
godot_variant_new_string_name(r_dest, p_s);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np) {
godot_variant_new_node_path(r_dest, p_np);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) {
godot_variant_new_object(r_dest, p_obj);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d) {
godot_variant_new_transform2d(r_dest, p_t2d);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis) {
godot_variant_new_basis(r_dest, p_basis);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) {
godot_variant_new_transform3d(r_dest, p_trans);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) {
godot_variant_new_aabb(r_dest, p_aabb);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_dictionary(godot_variant *r_dest, const godot_dictionary *p_dict) {
godot_variant_new_dictionary(r_dest, p_dict);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_array(godot_variant *r_dest, const godot_array *p_arr) {
godot_variant_new_array(r_dest, p_arr);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_byte_array(godot_variant *r_dest, const godot_packed_byte_array *p_pba) {
godot_variant_new_packed_byte_array(r_dest, p_pba);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int32_array(godot_variant *r_dest, const godot_packed_int32_array *p_pia) {
godot_variant_new_packed_int32_array(r_dest, p_pia);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_int64_array(godot_variant *r_dest, const godot_packed_int64_array *p_pia) {
godot_variant_new_packed_int64_array(r_dest, p_pia);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float32_array(godot_variant *r_dest, const godot_packed_float32_array *p_pra) {
godot_variant_new_packed_float32_array(r_dest, p_pra);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_float64_array(godot_variant *r_dest, const godot_packed_float64_array *p_pra) {
godot_variant_new_packed_float64_array(r_dest, p_pra);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_string_array(godot_variant *r_dest, const godot_packed_string_array *p_psa) {
godot_variant_new_packed_string_array(r_dest, p_psa);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector2_array(godot_variant *r_dest, const godot_packed_vector2_array *p_pv2a) {
godot_variant_new_packed_vector2_array(r_dest, p_pv2a);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_vector3_array(godot_variant *r_dest, const godot_packed_vector3_array *p_pv3a) {
godot_variant_new_packed_vector3_array(r_dest, p_pv3a);
}
GD_PINVOKE_EXPORT void godotsharp_variant_new_packed_color_array(godot_variant *r_dest, const godot_packed_color_array *p_pca) {
godot_variant_new_packed_color_array(r_dest, p_pca);
}
GD_PINVOKE_EXPORT godot_bool godotsharp_variant_as_bool(const godot_variant *p_self) {
return godot_variant_as_bool(p_self);
}
GD_PINVOKE_EXPORT godot_int godotsharp_variant_as_int(const godot_variant *p_self) {
return godot_variant_as_int(p_self);
}
GD_PINVOKE_EXPORT godot_float godotsharp_variant_as_float(const godot_variant *p_self) {
return godot_variant_as_float(p_self);
}
GD_PINVOKE_EXPORT godot_string godotsharp_variant_as_string(const godot_variant *p_self) {
return godot_variant_as_string(p_self);
}
GD_PINVOKE_EXPORT godot_vector2 godotsharp_variant_as_vector2(const godot_variant *p_self) {
return godot_variant_as_vector2(p_self);
}
GD_PINVOKE_EXPORT godot_vector2i godotsharp_variant_as_vector2i(const godot_variant *p_self) {
return godot_variant_as_vector2i(p_self);
}
GD_PINVOKE_EXPORT godot_rect2 godotsharp_variant_as_rect2(const godot_variant *p_self) {
return godot_variant_as_rect2(p_self);
}
GD_PINVOKE_EXPORT godot_rect2i godotsharp_variant_as_rect2i(const godot_variant *p_self) {
return godot_variant_as_rect2i(p_self);
}
GD_PINVOKE_EXPORT godot_vector3 godotsharp_variant_as_vector3(const godot_variant *p_self) {
return godot_variant_as_vector3(p_self);
}
GD_PINVOKE_EXPORT godot_vector3i godotsharp_variant_as_vector3i(const godot_variant *p_self) {
return godot_variant_as_vector3i(p_self);
}
GD_PINVOKE_EXPORT godot_transform2d godotsharp_variant_as_transform2d(const godot_variant *p_self) {
return godot_variant_as_transform2d(p_self);
}
GD_PINVOKE_EXPORT godot_plane godotsharp_variant_as_plane(const godot_variant *p_self) {
return godot_variant_as_plane(p_self);
}
GD_PINVOKE_EXPORT godot_quaternion godotsharp_variant_as_quaternion(const godot_variant *p_self) {
return godot_variant_as_quaternion(p_self);
}
GD_PINVOKE_EXPORT godot_aabb godotsharp_variant_as_aabb(const godot_variant *p_self) {
return godot_variant_as_aabb(p_self);
}
GD_PINVOKE_EXPORT godot_basis godotsharp_variant_as_basis(const godot_variant *p_self) {
return godot_variant_as_basis(p_self);
}
GD_PINVOKE_EXPORT godot_transform3d godotsharp_variant_as_transform3d(const godot_variant *p_self) {
return godot_variant_as_transform3d(p_self);
}
GD_PINVOKE_EXPORT godot_color godotsharp_variant_as_color(const godot_variant *p_self) {
return godot_variant_as_color(p_self);
}
GD_PINVOKE_EXPORT godot_string_name godotsharp_variant_as_string_name(const godot_variant *p_self) {
return godot_variant_as_string_name(p_self);
}
GD_PINVOKE_EXPORT godot_node_path godotsharp_variant_as_node_path(const godot_variant *p_self) {
return godot_variant_as_node_path(p_self);
}
GD_PINVOKE_EXPORT godot_rid godotsharp_variant_as_rid(const godot_variant *p_self) {
return godot_variant_as_rid(p_self);
}
GD_PINVOKE_EXPORT godot_callable godotsharp_variant_as_callable(const godot_variant *p_self) {
return godot_variant_as_callable(p_self);
}
GD_PINVOKE_EXPORT godot_signal godotsharp_variant_as_signal(const godot_variant *p_self) {
return godot_variant_as_signal(p_self);
}
GD_PINVOKE_EXPORT godot_dictionary godotsharp_variant_as_dictionary(const godot_variant *p_self) {
return godot_variant_as_dictionary(p_self);
}
GD_PINVOKE_EXPORT godot_array godotsharp_variant_as_array(const godot_variant *p_self) {
return godot_variant_as_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_byte_array godotsharp_variant_as_packed_byte_array(const godot_variant *p_self) {
return godot_variant_as_packed_byte_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_int32_array godotsharp_variant_as_packed_int32_array(const godot_variant *p_self) {
return godot_variant_as_packed_int32_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_int64_array godotsharp_variant_as_packed_int64_array(const godot_variant *p_self) {
return godot_variant_as_packed_int64_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_float32_array godotsharp_variant_as_packed_float32_array(const godot_variant *p_self) {
return godot_variant_as_packed_float32_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_float64_array godotsharp_variant_as_packed_float64_array(const godot_variant *p_self) {
return godot_variant_as_packed_float64_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_string_array godotsharp_variant_as_packed_string_array(const godot_variant *p_self) {
return godot_variant_as_packed_string_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array(const godot_variant *p_self) {
return godot_variant_as_packed_vector2_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array(const godot_variant *p_self) {
return godot_variant_as_packed_vector3_array(p_self);
}
GD_PINVOKE_EXPORT godot_packed_color_array godotsharp_variant_as_packed_color_array(const godot_variant *p_self) {
return godot_variant_as_packed_color_array(p_self);
}
// string.h
GD_PINVOKE_EXPORT void godotsharp_string_new_with_utf16_chars(godot_string *r_dest, const char16_t *p_contents) {
godot_string_new_with_utf16_chars(r_dest, p_contents);
}
// string_name.h
GD_PINVOKE_EXPORT void godotsharp_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src) {
godot_string_name_new_copy(r_dest, p_src);
}
// node_path.h
GD_PINVOKE_EXPORT void godotsharp_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src) {
godot_node_path_new_copy(r_dest, p_src);
}
// array.h
GD_PINVOKE_EXPORT void godotsharp_array_new_copy(godot_array *r_dest, const godot_array *p_src) {
godot_array_new_copy(r_dest, p_src);
}
// dictionary.h
GD_PINVOKE_EXPORT void godotsharp_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src) {
godot_dictionary_new_copy(r_dest, p_src);
}
// destroy functions
GD_PINVOKE_EXPORT void godotsharp_packed_byte_array_destroy(godot_packed_byte_array *p_self) {
godot_packed_byte_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_int32_array_destroy(godot_packed_int32_array *p_self) {
godot_packed_int32_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_int64_array_destroy(godot_packed_int64_array *p_self) {
godot_packed_int64_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_float32_array_destroy(godot_packed_float32_array *p_self) {
godot_packed_float32_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_float64_array_destroy(godot_packed_float64_array *p_self) {
godot_packed_float64_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_string_array_destroy(godot_packed_string_array *p_self) {
godot_packed_string_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_vector2_array_destroy(godot_packed_vector2_array *p_self) {
godot_packed_vector2_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_vector3_array_destroy(godot_packed_vector3_array *p_self) {
godot_packed_vector3_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_packed_color_array_destroy(godot_packed_color_array *p_self) {
godot_packed_color_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_variant_destroy(godot_variant *p_self) {
godot_variant_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_string_destroy(godot_string *p_self) {
godot_string_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_string_name_destroy(godot_string_name *p_self) {
godot_string_name_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_node_path_destroy(godot_node_path *p_self) {
godot_node_path_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_signal_destroy(godot_signal *p_self) {
godot_signal_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_callable_destroy(godot_callable *p_self) {
godot_callable_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_array_destroy(godot_array *p_self) {
godot_array_destroy(p_self);
}
GD_PINVOKE_EXPORT void godotsharp_dictionary_destroy(godot_dictionary *p_self) {
godot_dictionary_destroy(p_self);
}
#ifdef __cplusplus
}
#endif
// We need this to prevent the functions from being stripped.
void *godotsharp_pinvoke_funcs[95] = {
(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_basis,
(void *)godotsharp_variant_new_transform3d,
(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_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_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
};

View file

@ -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

View file

@ -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"
@ -75,5 +73,3 @@ void godot_register_string_icalls() {
GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer);
GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
}
#endif // MONO_GLUE_ENABLED

View file

@ -1,62 +0,0 @@
/*************************************************************************/
/* string_name_glue.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. */
/*************************************************************************/
#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

View file

@ -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"

View file

@ -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,9 +69,7 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust
}
uint32_t ManagedCallable::hash() const {
// hmm
uint32_t hash = delegate_invoke->get_name().hash();
return hash_djb2_one_64(delegate_handle.handle, hash);
return hash_djb2_one_64((uint64_t)delegate_handle);
}
String ManagedCallable::get_as_text() const {
@ -92,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);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
}
delegate_handle = nullptr;
}
}
ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_delegate == nullptr);
#endif
set_delegate(p_delegate);
// 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);
@ -134,6 +128,7 @@ ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
}
#endif
}
/* clang-format on */
ManagedCallable::~ManagedCallable() {
#ifdef GD_MONO_HOT_RELOAD
@ -144,5 +139,5 @@ ManagedCallable::~ManagedCallable() {
}
#endif
delegate_handle.release();
release_delegate_handle();
}

View file

@ -42,8 +42,7 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
MonoGCHandleData delegate_handle;
GDMonoMethod *delegate_invoke;
void *delegate_handle;
#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();
};

View file

@ -410,10 +410,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.
@ -448,59 +444,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() {
@ -603,16 +574,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;
@ -701,12 +662,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;
}
@ -722,14 +679,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);
@ -771,7 +723,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)) {
@ -831,14 +783,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;
}
@ -861,14 +815,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;
}
@ -1098,13 +1054,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.");

View file

@ -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);

View file

@ -48,11 +48,8 @@ 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)
#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
{ \
@ -68,23 +65,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,35 +80,11 @@ 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_Basis = nullptr;
class_Quaternion = nullptr;
class_Transform3D = 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
@ -152,65 +109,37 @@ 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_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_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_ArrayGetElementType.nullify();
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
// End of MarshalUtils methods
methodthunk_Marshaling_SetFieldValue.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"));
@ -227,33 +156,11 @@ 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(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(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
@ -278,36 +185,38 @@ 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));
// Start of MarshalUtils methods
GDMonoClass *gd_mono_marshal_class = GDMono::get_singleton()->get_core_api_assembly()->get_class(
"Godot.NativeInterop", "Marshaling");
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));
ERR_FAIL_COND_MSG(gd_mono_marshal_class == nullptr,
"Mono Cache: Class `Godot.NativeInterop.Marshaling` not found.");
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(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(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
CACHE_METHOD_THUNK_AND_CHECK(Marshaling, SetFieldValue,
gd_mono_marshal_class->get_method("SetFieldValue", 3));
#ifdef DEBUG_ENABLED
CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));

View file

@ -42,23 +42,7 @@ struct CachedData {
// Let's use the no-namespace format for these too
GDMonoClass *class_MonoObject; // object
GDMonoClass *class_bool; // bool
GDMonoClass *class_int8_t; // sbyte
GDMonoClass *class_int16_t; // short
GDMonoClass *class_int32_t; // int
GDMonoClass *class_int64_t; // long
GDMonoClass *class_uint8_t; // byte
GDMonoClass *class_uint16_t; // ushort
GDMonoClass *class_uint32_t; // uint
GDMonoClass *class_uint64_t; // ulong
GDMonoClass *class_float; // float
GDMonoClass *class_double; // double
GDMonoClass *class_String; // string
GDMonoClass *class_IntPtr; // System.IntPtr
GDMonoClass *class_System_Collections_IEnumerable;
GDMonoClass *class_System_Collections_ICollection;
GDMonoClass *class_System_Collections_IDictionary;
#ifdef DEBUG_ENABLED
GDMonoClass *class_System_Diagnostics_StackTrace;
@ -68,37 +52,13 @@ struct CachedData {
#endif
GDMonoClass *class_KeyNotFoundException;
MonoClass *rawclass_Dictionary;
// -----------------------------------------------
GDMonoClass *class_Vector2;
GDMonoClass *class_Vector2i;
GDMonoClass *class_Rect2;
GDMonoClass *class_Rect2i;
GDMonoClass *class_Transform2D;
GDMonoClass *class_Vector3;
GDMonoClass *class_Vector3i;
GDMonoClass *class_Basis;
GDMonoClass *class_Quaternion;
GDMonoClass *class_Transform3D;
GDMonoClass *class_AABB;
GDMonoClass *class_Color;
GDMonoClass *class_Plane;
GDMonoClass *class_StringName;
GDMonoClass *class_NodePath;
GDMonoClass *class_RID;
GDMonoClass *class_GodotObject;
GDMonoClass *class_GodotResource;
GDMonoClass *class_Node;
GDMonoClass *class_Control;
GDMonoClass *class_Node3D;
GDMonoClass *class_WeakRef;
GDMonoClass *class_Callable;
GDMonoClass *class_SignalInfo;
GDMonoClass *class_Array;
GDMonoClass *class_Dictionary;
GDMonoClass *class_MarshalUtils;
GDMonoClass *class_ISerializationListener;
#ifdef DEBUG_ENABLED
@ -123,39 +83,30 @@ struct CachedData {
GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes;
GDMonoField *field_GodotObject_ptr;
GDMonoField *field_StringName_ptr;
GDMonoField *field_NodePath_ptr;
GDMonoField *field_Image_ptr;
GDMonoField *field_RID_ptr;
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
GDMonoMethodThunk<void *, const Variant **, uint32_t, const Variant *> methodthunk_DelegateUtils_InvokeWithVariantArgs;
GDMonoMethodThunkR<MonoBoolean, void *, void *> methodthunk_DelegateUtils_DelegateEquals;
GDMonoMethodThunk<void *> methodthunk_DelegateUtils_FreeGCHandle;
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<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;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
// End of MarshalUtils methods
GDMonoMethodThunk<MonoReflectionField *, MonoObject *, const Variant *> methodthunk_Marshaling_SetFieldValue;
Ref<MonoGCHandleRef> task_scheduler_handle;
@ -176,10 +127,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();
}
@ -187,10 +134,8 @@ 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)
#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property)
#endif // GD_MONO_CACHE_H

View file

@ -46,391 +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(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(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::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::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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -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,457 +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;
MonoObject *method_string_name;
MonoDelegate *delegate;
};
struct M_SignalInfo {
MonoObject *owner;
MonoObject *name_string_name;
};
#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_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_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_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_AABB && MATCHES_Color &&
MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i);
/* 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.elements[0]),
M_Vector2::convert_from(p_from.elements[1]),
M_Vector2::convert_from(p_from.elements[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_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.elements[0]),
M_Vector3::convert_from(p_from.elements[1]),
M_Vector3::convert_from(p_from.elements[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_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(Quaternion)
DECL_TYPE_MARSHAL_TEMPLATES(Transform3D)
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 // GDMONOMARSHAL_H

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
@ -540,109 +444,6 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc);
}
namespace Marshal {
#ifdef MONO_GLUE_ENABLED
#ifdef TOOLS_ENABLED
#define NO_GLUE_RET(m_ret) \
{ \
if (!GDMonoCache::cached_data.godot_api_cache_updated) \
return m_ret; \
}
#else
#define NO_GLUE_RET(m_ret) \
{}
#endif
#else
#define NO_GLUE_RET(m_ret) \
{ 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;
}
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() {
if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
mono_thread = GDMonoUtils::attach_current_thread();
@ -657,7 +458,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

View file

@ -52,23 +52,6 @@
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);
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) {
p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
}
@ -94,20 +77,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);
@ -138,6 +113,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);

View file

@ -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();

View file

@ -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;
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;

View file

@ -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;
}

View file

@ -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);