Merge pull request #48409 from neikeq/oh-im-die-ty-4ever

C#: Move marshaling logic and generated glue to C#
This commit is contained in:
Rémi Verschelde 2021-08-20 11:32:27 +02:00 committed by GitHub
commit f580b1efdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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);