summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2021-09-12 20:23:05 +0200
committerIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-08-22 03:35:59 +0200
commitf9a67ee9da1d6cc3562fa5a7443a2a66a673bd8c (patch)
tree724e3b0a0030cc0abc67710dcf9c4a14be5724f0 /modules
parent513ee857a938c466e0f7146f66db771b9c6e2024 (diff)
C#: Begin move to .NET Core
We're targeting .NET 5 for now to make development easier while .NET 6 is not yet released. TEMPORARY REGRESSIONS --------------------- Assembly unloading is not implemented yet. As such, many Godot resources are leaked at exit. This will be re-implemented later together with assembly hot-reloading.
Diffstat (limited to 'modules')
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py6
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py55
-rw-r--r--modules/mono/build_scripts/mono_android_config.xml28
-rw-r--r--modules/mono/build_scripts/mono_configure.py624
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py112
-rw-r--r--modules/mono/config.py30
-rw-r--r--modules/mono/csharp_script.cpp397
-rw-r--r--modules/mono/csharp_script.h8
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml47
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj24
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe0
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.sln2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs14
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs19
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs12
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs19
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs29
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs39
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs155
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs23
-rw-r--r--modules/mono/editor/bindings_generator.cpp30
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp175
-rw-r--r--modules/mono/editor/godotsharp_export.cpp144
-rw-r--r--modules/mono/editor/godotsharp_export.h44
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj17
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/Main.cs197
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs61
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs205
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs72
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs653
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs62
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs74
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs51
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs72
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs63
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs134
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs47
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj2
-rw-r--r--modules/mono/glue/base_object_glue.cpp137
-rw-r--r--modules/mono/glue/placeholder_glue.cpp201
-rw-r--r--modules/mono/glue/runtime_interop.cpp245
-rw-r--r--modules/mono/managed_callable.cpp29
-rw-r--r--modules/mono/managed_callable.h2
-rw-r--r--modules/mono/mono_gc_handle.cpp10
-rw-r--r--modules/mono/mono_gc_handle.h6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp779
-rw-r--r--modules/mono/mono_gd/gd_mono.h163
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp388
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h97
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp113
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h112
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp71
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp209
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h71
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h126
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp253
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h144
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.cpp79
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h263
-rw-r--r--modules/mono/signal_awaiter_utils.cpp19
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp242
-rw-r--r--modules/mono/utils/mono_reg_utils.h54
93 files changed, 2369 insertions, 5486 deletions
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index dd96f40f6b..67c2f7f70e 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -203,6 +203,9 @@ def build_godot_api(msbuild_tool, module_dir, output_dir):
"GodotSharpEditor.dll",
"GodotSharpEditor.pdb",
"GodotSharpEditor.xml",
+ "GodotPlugins.dll",
+ "GodotPlugins.pdb",
+ "GodotPlugins.runtimeconfig.json",
]
for build_config in ["Debug", "Release"]:
@@ -223,6 +226,7 @@ def build_godot_api(msbuild_tool, module_dir, output_dir):
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))
+ plugins_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotPlugins", "bin", build_config, "net5.0"))
if not os.path.isdir(editor_api_dir):
assert not os.path.isfile(editor_api_dir)
@@ -236,6 +240,8 @@ def build_godot_api(msbuild_tool, module_dir, output_dir):
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)
+ if not os.path.isfile(src_path):
+ src_path = os.path.join(plugins_src_dir, filename)
print(f"Copying assembly to {target_path}...")
copy(src_path, target_path)
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
deleted file mode 100644
index 3459244bc2..0000000000
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ /dev/null
@@ -1,55 +0,0 @@
-def generate_compressed_config(config_src, output_dir):
- import os.path
-
- # Source file
- with open(os.path.join(output_dir, "android_mono_config.gen.cpp"), "w") as cpp:
- with open(config_src, "rb") as f:
- buf = f.read()
- decompr_size = len(buf)
- import zlib
-
- # Use maximum zlib compression level to further reduce file size
- # (at the cost of initial build times).
- buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
- compr_size = len(buf)
-
- bytes_seq_str = ""
- for i, buf_idx in enumerate(range(compr_size)):
- if i > 0:
- bytes_seq_str += ", "
- bytes_seq_str += str(buf[buf_idx])
-
- cpp.write(
- """/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "android_mono_config.h"
-
-#ifdef ANDROID_ENABLED
-
-#include "core/io/compression.h"
-
-
-namespace {
-
-// config
-static const int config_compressed_size = %d;
-static const int config_uncompressed_size = %d;
-static const unsigned char config_compressed_data[] = { %s };
-} // namespace
-
-String get_godot_android_mono_config() {
- Vector<uint8_t> data;
- data.resize(config_uncompressed_size);
- uint8_t* w = data.ptrw();
- Compression::decompress(w, config_uncompressed_size, config_compressed_data,
- config_compressed_size, Compression::MODE_DEFLATE);
- String s;
- if (s.parse_utf8((const char *)w, data.size()) != OK) {
- ERR_FAIL_V(String());
- }
- return s;
-}
-
-#endif // ANDROID_ENABLED
-"""
- % (compr_size, decompr_size, bytes_seq_str)
- )
diff --git a/modules/mono/build_scripts/mono_android_config.xml b/modules/mono/build_scripts/mono_android_config.xml
deleted file mode 100644
index e79670afd2..0000000000
--- a/modules/mono/build_scripts/mono_android_config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<configuration>
- <dllmap wordsize="32" dll="i:cygwin1.dll" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:cygwin1.dll" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="libc" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="libc" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="intl" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="intl" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="libintl" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="libintl" target="/system/lib64/libc.so" />
- <dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.so" />
- <dllmap dll="System.Native" target="libmono-native.so" />
- <dllmap wordsize="32" dll="i:msvcrt" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:msvcrt" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="i:msvcrt.dll" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:msvcrt.dll" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="sqlite" target="/system/lib/libsqlite.so" />
- <dllmap wordsize="64" dll="sqlite" target="/system/lib64/libsqlite.so" />
- <dllmap wordsize="32" dll="sqlite3" target="/system/lib/libsqlite.so" />
- <dllmap wordsize="64" dll="sqlite3" target="/system/lib64/libsqlite.so" />
- <dllmap wordsize="32" dll="liblog" target="/system/lib/liblog.so" />
- <dllmap wordsize="64" dll="liblog" target="/system/lib64/liblog.so" />
- <dllmap dll="i:kernel32.dll">
- <dllentry dll="__Internal" name="CopyMemory" target="mono_win32_compat_CopyMemory"/>
- <dllentry dll="__Internal" name="FillMemory" target="mono_win32_compat_FillMemory"/>
- <dllentry dll="__Internal" name="MoveMemory" target="mono_win32_compat_MoveMemory"/>
- <dllentry dll="__Internal" name="ZeroMemory" target="mono_win32_compat_ZeroMemory"/>
- </dllmap>
-</configuration>
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index e69904c54b..071693d758 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -1,65 +1,5 @@
import os
import os.path
-import subprocess
-
-from SCons.Script import Dir, Environment
-
-if os.name == "nt":
- from . import mono_reg_utils as monoreg
-
-
-android_arch_dirs = {
- "armv7": "armeabi-v7a",
- "arm64v8": "arm64-v8a",
- "x86": "x86",
- "x86_64": "x86_64",
-}
-
-
-def get_android_out_dir(env):
- return os.path.join(
- Dir("#platform/android/java/lib/libs").abspath,
- "release" if env["target"] == "release" else "debug",
- android_arch_dirs[env["android_arch"]],
- )
-
-
-def find_name_in_dir_files(directory, names, prefixes=[""], extensions=[""]):
- for extension in extensions:
- if extension and not extension.startswith("."):
- extension = "." + extension
- for prefix in prefixes:
- for curname in names:
- if os.path.isfile(os.path.join(directory, prefix + curname + extension)):
- return curname
- return ""
-
-
-def find_file_in_dir(directory, names, prefixes=[""], extensions=[""]):
- for extension in extensions:
- if extension and not extension.startswith("."):
- extension = "." + extension
- for prefix in prefixes:
- for curname in names:
- filename = prefix + curname + extension
- if os.path.isfile(os.path.join(directory, filename)):
- return filename
- return ""
-
-
-def copy_file(src_dir, dst_dir, src_name, dst_name=""):
- from shutil import copy
-
- src_path = os.path.join(Dir(src_dir).abspath, src_name)
- dst_dir = Dir(dst_dir).abspath
-
- if not os.path.isdir(dst_dir):
- os.makedirs(dst_dir)
-
- if dst_name:
- copy(src_path, os.path.join(dst_dir, dst_name))
- else:
- copy(src_path, dst_dir)
def is_desktop(platform):
@@ -71,504 +11,176 @@ def is_unix_like(platform):
def module_supports_tools_on(platform):
- return platform not in ["android", "javascript", "ios"]
-
-
-def find_wasm_src_dir(mono_root):
- hint_dirs = [
- os.path.join(mono_root, "src"),
- os.path.join(mono_root, "../src"),
- ]
- for hint_dir in hint_dirs:
- if os.path.isfile(os.path.join(hint_dir, "driver.c")):
- return hint_dir
- return ""
+ return is_desktop(platform)
def configure(env, env_mono):
- bits = env["bits"]
- is_android = env["platform"] == "android"
- is_javascript = env["platform"] == "javascript"
- is_ios = env["platform"] == "ios"
- is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
+ # is_android = env["platform"] == "android"
+ # is_javascript = env["platform"] == "javascript"
+ # is_ios = env["platform"] == "ios"
+ # is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
tools_enabled = env["tools"]
- mono_static = env["mono_static"]
- copy_mono_root = env["copy_mono_root"]
-
- mono_prefix = env["mono_prefix"]
- mono_bcl = env["mono_bcl"]
-
- mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
-
- if is_android and not env["android_arch"] in android_arch_dirs:
- raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"])
if tools_enabled and not module_supports_tools_on(env["platform"]):
- # TODO:
- # Android: We have to add the data directory to the apk, concretely the Api and Tools folders.
raise RuntimeError("This module does not currently support building for this platform with tools enabled")
- if is_android and mono_static:
- # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native'
- # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook.
- raise RuntimeError("Statically linking Mono is not currently supported for this platform")
-
- if not mono_static and (is_javascript or is_ios):
- raise RuntimeError("Dynamically linking Mono is not currently supported for this platform")
-
- if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")):
- print(
- "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the"
- " 'mono_prefix' SCons parameter instead"
- )
-
- # Although we don't support building with tools for any platform where we currently use static AOT,
- # if these are supported in the future, we won't be using static AOT for them as that would be
- # too restrictive for the editor. These builds would probably be made to only use the interpreter.
- mono_aot_static = (is_ios and not is_ios_sim) and not env["tools"]
-
- # Static AOT is only supported on the root domain
- mono_single_appdomain = mono_aot_static
-
- if mono_single_appdomain:
- env_mono.Append(CPPDEFINES=["GD_MONO_SINGLE_APPDOMAIN"])
-
- if (env["tools"] or env["target"] != "release") and not mono_single_appdomain:
+ if env["tools"] or env["target"] != "release":
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
- if env["platform"] == "windows":
- mono_root = mono_prefix
-
- if not mono_root and os.name == "nt":
- mono_root = monoreg.find_mono_root_dir(bits)
-
- if not mono_root:
- raise RuntimeError(
- "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- print("Found Mono root directory: " + mono_root)
-
- mono_lib_path = os.path.join(mono_root, "lib")
-
- env.Append(LIBPATH=mono_lib_path)
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
+ app_host_dir = find_dotnet_app_host_dir(env)
- lib_suffixes = [".lib"]
+ def check_app_host_file_exists(file):
+ file_path = os.path.join(app_host_dir, file)
+ if not os.path.isfile(file_path):
+ raise RuntimeError("File not found: " + file_path)
- if not env.msvc:
- # MingW supports both '.a' and '.lib'
- lib_suffixes.insert(0, ".a")
+ # TODO:
+ # All libnethost does for us is provide a function to find hostfxr.
+ # If we could handle that logic ourselves we could void linking it.
- if mono_static:
- if env.msvc:
- mono_static_lib_name = "libmono-static-sgen"
- else:
- mono_static_lib_name = "libmonosgen-2.0"
+ # nethost file names:
+ # static: libnethost.a/lib
+ # shared: libnethost.a/dylib and nethost.dll
+ check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a")
+ check_app_host_file_exists("nethost.h")
+ check_app_host_file_exists("hostfxr.h")
+ check_app_host_file_exists("coreclr_delegates.h")
- mono_static_lib_file = find_file_in_dir(mono_lib_path, [mono_static_lib_name], extensions=lib_suffixes)
+ env.Append(LIBPATH=[app_host_dir])
+ env_mono.Prepend(CPPPATH=app_host_dir)
- if not mono_static_lib_file:
- raise RuntimeError("Could not find static mono library in: " + mono_lib_path)
+ libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a")
- if env.msvc:
- env.Append(LINKFLAGS=mono_static_lib_file)
-
- env.Append(LINKFLAGS="Mincore.lib")
- env.Append(LINKFLAGS="msvcrt.lib")
- env.Append(LINKFLAGS="LIBCMT.lib")
- env.Append(LINKFLAGS="Psapi.lib")
- else:
- mono_static_lib_file_path = os.path.join(mono_lib_path, mono_static_lib_file)
- env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_static_lib_file_path, "-Wl,-no-whole-archive"])
+ if env["platform"] == "windows":
+ env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"])
- env.Append(LIBS=["psapi"])
- env.Append(LIBS=["version"])
+ if env.msvc:
+ env.Append(LINKFLAGS="libnethost.lib")
else:
- mono_lib_file = find_file_in_dir(mono_lib_path, mono_lib_names, extensions=lib_suffixes)
-
- if not mono_lib_file:
- raise RuntimeError("Could not find mono library in: " + mono_lib_path)
-
- if env.msvc:
- env.Append(LINKFLAGS=mono_lib_file)
- else:
- mono_lib_file_path = os.path.join(mono_lib_path, mono_lib_file)
- env.Append(LINKFLAGS=mono_lib_file_path)
-
- mono_bin_path = os.path.join(mono_root, "bin")
-
- mono_dll_file = find_file_in_dir(mono_bin_path, mono_lib_names, prefixes=["", "lib"], extensions=[".dll"])
-
- if not mono_dll_file:
- raise RuntimeError("Could not find mono shared library in: " + mono_bin_path)
-
- copy_file(mono_bin_path, "#bin", mono_dll_file)
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
else:
is_apple = env["platform"] in ["macos", "ios"]
- is_macos = is_apple and not is_ios
-
- sharedlib_ext = ".dylib" if is_apple else ".so"
-
- mono_root = mono_prefix
- mono_lib_path = ""
- mono_so_file = ""
-
- if not mono_root and (is_android or is_javascript or is_ios):
- raise RuntimeError(
- "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- if not mono_root and is_macos:
- # Try with some known directories under macOS
- hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"]
- for hint_dir in hint_dirs:
- if os.path.isdir(hint_dir):
- mono_root = hint_dir
- break
-
- # We can't use pkg-config to link mono statically,
- # but we can still use it to find the mono root directory
- if not mono_root and mono_static:
- mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
- if not mono_root:
- raise RuntimeError(
- "Building with mono_static=yes, but failed to find the mono prefix with pkg-config; "
- + "specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- if is_ios and not is_ios_sim:
- env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
-
- if mono_root:
- print("Found Mono root directory: " + mono_root)
-
- mono_lib_path = os.path.join(mono_root, "lib")
-
- env.Append(LIBPATH=[mono_lib_path])
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
-
- mono_lib = find_name_in_dir_files(mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[".a"])
-
- if not mono_lib:
- raise RuntimeError("Could not find mono library in: " + mono_lib_path)
-
- env_mono.Append(CPPDEFINES=["_REENTRANT"])
-
- if mono_static:
- if not is_javascript:
- env.Append(LINKFLAGS=["-rdynamic"])
-
- mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
-
- if is_apple:
- if is_macos:
- env.Append(LINKFLAGS=["-Wl,-force_load," + mono_lib_file])
- else:
- arch = env["arch"]
-
- def copy_mono_lib(libname_wo_ext):
- copy_file(
- mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.ios.%s.a" % (libname_wo_ext, arch)
- )
-
- # Copy Mono libraries to the output folder. These are meant to be bundled with
- # the export templates and added to the Xcode project when exporting a game.
- copy_mono_lib("lib" + mono_lib)
- copy_mono_lib("libmono-native")
- copy_mono_lib("libmono-profiler-log")
-
- if not is_ios_sim:
- copy_mono_lib("libmono-ee-interp")
- copy_mono_lib("libmono-icall-table")
- copy_mono_lib("libmono-ilgen")
- else:
- assert is_desktop(env["platform"]) or is_android or is_javascript
- env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_lib_file, "-Wl,-no-whole-archive"])
-
- if is_javascript:
- env.Append(LIBS=["mono-icall-table", "mono-native", "mono-ilgen", "mono-ee-interp"])
-
- wasm_src_dir = os.path.join(mono_root, "src")
- if not os.path.isdir(wasm_src_dir):
- raise RuntimeError("Could not find mono wasm src directory")
-
- # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours
- env_mono.Append(CPPDEFINES=["CORE_BINDINGS"])
-
- env_mono.add_source_files(
- env.modules_sources,
- [
- os.path.join(wasm_src_dir, "driver.c"),
- os.path.join(wasm_src_dir, "zlib-helper.c"),
- os.path.join(wasm_src_dir, "corebindings.c"),
- ],
- )
-
- env.Append(
- LINKFLAGS=[
- "--js-library",
- os.path.join(wasm_src_dir, "library_mono.js"),
- "--js-library",
- os.path.join(wasm_src_dir, "binding_support.js"),
- "--js-library",
- os.path.join(wasm_src_dir, "dotnet_support.js"),
- ]
- )
- else:
- env.Append(LIBS=[mono_lib])
-
- if is_macos:
- env.Append(LIBS=["iconv", "pthread"])
- elif is_android:
- pass # Nothing
- elif is_ios:
- pass # Nothing, linking is delegated to the exported Xcode project
- elif is_javascript:
- env.Append(LIBS=["m", "rt", "dl", "pthread"])
- else:
- env.Append(LIBS=["m", "rt", "dl", "pthread"])
-
- if not mono_static:
- mono_so_file = find_file_in_dir(
- mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]
- )
-
- if not mono_so_file:
- raise RuntimeError("Could not find mono shared library in: " + mono_lib_path)
- else:
- assert not mono_static
+ # is_macos = is_apple and not is_ios
- # TODO: Add option to force using pkg-config
- print("Mono root directory not found. Using pkg-config instead")
+ # if is_ios and not is_ios_sim:
+ # env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
- env.ParseConfig("pkg-config monosgen-2 --libs")
- env_mono.ParseConfig("pkg-config monosgen-2 --cflags")
+ if is_apple:
+ env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path])
+ else:
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
- tmpenv = Environment()
- tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
- tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
- for hint_dir in tmpenv["LIBPATH"]:
- file_found = find_file_in_dir(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
- if file_found:
- mono_lib_path = hint_dir
- mono_so_file = file_found
- break
+def find_dotnet_app_host_dir(env):
+ dotnet_root = env["dotnet_root"]
- if not mono_so_file:
- raise RuntimeError("Could not find mono shared library in: " + str(tmpenv["LIBPATH"]))
+ if not dotnet_root:
+ dotnet_exe = find_executable("dotnet")
+ if dotnet_exe:
+ dotnet_exe_realpath = os.path.realpath(dotnet_exe) # Eliminate symbolic links
+ dotnet_root = os.path.abspath(os.path.join(dotnet_exe_realpath, os.pardir))
+ else:
+ raise RuntimeError("Cannot find .NET Core Sdk")
- if not mono_static:
- libs_output_dir = get_android_out_dir(env) if is_android else "#bin"
- copy_file(mono_lib_path, libs_output_dir, mono_so_file)
+ print("Found .NET Core Sdk root directory: " + dotnet_root)
- if not tools_enabled:
- if is_desktop(env["platform"]):
- if not mono_root:
- mono_root = (
- subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
- )
+ dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet")
- make_template_dir(env, mono_root)
- elif is_android:
- # Compress Android Mono Config
- from . import make_android_mono_config
+ runtime_identifier = determine_runtime_identifier(env)
- module_dir = os.getcwd()
- config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml")
- make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/")
+ # TODO: In the future, if it can't be found this way, we want to obtain it
+ # from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package.
+ app_host_search_version = "5.0"
+ app_host_version = find_app_host_version(dotnet_cmd, app_host_search_version)
+ if not app_host_version:
+ raise RuntimeError("Cannot find .NET app host for version: " + app_host_search_version)
- # Copy the required shared libraries
- copy_mono_shared_libs(env, mono_root, None)
- elif is_javascript:
- pass # No data directory for this platform
- elif is_ios:
- pass # No data directory for this platform
+ app_host_dir = os.path.join(
+ dotnet_root,
+ "packs",
+ "Microsoft.NETCore.App.Host." + runtime_identifier,
+ app_host_version,
+ "runtimes",
+ runtime_identifier,
+ "native",
+ )
- if copy_mono_root:
- if not mono_root:
- mono_root = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
+ return app_host_dir
- if tools_enabled:
- # Only supported for editor builds.
- copy_mono_root_files(env, mono_root, mono_bcl)
+def determine_runtime_identifier(env):
+ names_map = {
+ "windows": "win",
+ "macos": "osx",
+ "linuxbsd": "linux",
+ "server": "linux", # FIXME: Is server linux only, or also macos?
+ }
-def make_template_dir(env, mono_root):
- from shutil import rmtree
+ # .NET RID architectures: x86, x64, arm, or arm64
platform = env["platform"]
- target = env["target"]
-
- template_dir_name = ""
-
- assert is_desktop(platform)
-
- template_dir_name = "data.mono.%s.%s.%s" % (platform, env["bits"], target)
-
- output_dir = Dir("#bin").abspath
- template_dir = os.path.join(output_dir, template_dir_name)
-
- template_mono_root_dir = os.path.join(template_dir, "Mono")
-
- if os.path.isdir(template_mono_root_dir):
- rmtree(template_mono_root_dir) # Clean first
- # Copy etc/mono/
-
- template_mono_config_dir = os.path.join(template_mono_root_dir, "etc", "mono")
- copy_mono_etc_dir(mono_root, template_mono_config_dir, platform)
-
- # Copy the required shared libraries
-
- copy_mono_shared_libs(env, mono_root, template_mono_root_dir)
-
-
-def copy_mono_root_files(env, mono_root, mono_bcl):
- from glob import glob
- from shutil import copy
- from shutil import rmtree
-
- if not mono_root:
- raise RuntimeError("Mono installation directory not found")
-
- output_dir = Dir("#bin").abspath
- editor_mono_root_dir = os.path.join(output_dir, "GodotSharp", "Mono")
-
- if os.path.isdir(editor_mono_root_dir):
- rmtree(editor_mono_root_dir) # Clean first
-
- # Copy etc/mono/
-
- editor_mono_config_dir = os.path.join(editor_mono_root_dir, "etc", "mono")
- copy_mono_etc_dir(mono_root, editor_mono_config_dir, env["platform"])
-
- # Copy the required shared libraries
-
- copy_mono_shared_libs(env, mono_root, editor_mono_root_dir)
+ if is_desktop(platform):
+ if env["arch"] in ["arm", "arm32"]:
+ rid = "arm"
+ elif env["arch"] == "arm64":
+ rid = "arm64"
+ else:
+ bits = env["bits"]
+ bit_arch_map = {"64": "x64", "32": "x86"}
+ rid = bit_arch_map[bits]
+ return "%s-%s" % (names_map[platform], rid)
+ else:
+ raise NotImplementedError()
- # Copy framework assemblies
- mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5")
- mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades")
+def find_app_host_version(dotnet_cmd, search_version):
+ import subprocess
- editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5")
- editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, "Facades")
+ try:
+ lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"]).splitlines()
- if not os.path.isdir(editor_mono_framework_dir):
- os.makedirs(editor_mono_framework_dir)
- if not os.path.isdir(editor_mono_framework_facades_dir):
- os.makedirs(editor_mono_framework_facades_dir)
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
+ if not line.startswith("Microsoft.NETCore.App "):
+ continue
- for assembly in glob(os.path.join(mono_framework_dir, "*.dll")):
- copy(assembly, editor_mono_framework_dir)
- for assembly in glob(os.path.join(mono_framework_facades_dir, "*.dll")):
- copy(assembly, editor_mono_framework_facades_dir)
+ parts = line.split(" ")
+ if len(parts) < 2:
+ continue
+ version = parts[1]
-def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform):
- from distutils.dir_util import copy_tree
- from glob import glob
- from shutil import copy
+ # Look for 6.0.0 or 6.0.0-*
+ if version.startswith(search_version + "."):
+ return version
+ except (subprocess.CalledProcessError, OSError):
+ pass
+ return ""
- if not os.path.isdir(target_mono_config_dir):
- os.makedirs(target_mono_config_dir)
- mono_etc_dir = os.path.join(mono_root, "etc", "mono")
- if not os.path.isdir(mono_etc_dir):
- mono_etc_dir = ""
- etc_hint_dirs = []
- if platform != "windows":
- etc_hint_dirs += ["/etc/mono", "/usr/local/etc/mono"]
- if "MONO_CFG_DIR" in os.environ:
- etc_hint_dirs += [os.path.join(os.environ["MONO_CFG_DIR"], "mono")]
- for etc_hint_dir in etc_hint_dirs:
- if os.path.isdir(etc_hint_dir):
- mono_etc_dir = etc_hint_dir
- break
- if not mono_etc_dir:
- raise RuntimeError("Mono installation etc directory not found")
+ENV_PATH_SEP = ";" if os.name == "nt" else ":"
- copy_tree(os.path.join(mono_etc_dir, "2.0"), os.path.join(target_mono_config_dir, "2.0"))
- copy_tree(os.path.join(mono_etc_dir, "4.0"), os.path.join(target_mono_config_dir, "4.0"))
- copy_tree(os.path.join(mono_etc_dir, "4.5"), os.path.join(target_mono_config_dir, "4.5"))
- if os.path.isdir(os.path.join(mono_etc_dir, "mconfig")):
- copy_tree(os.path.join(mono_etc_dir, "mconfig"), os.path.join(target_mono_config_dir, "mconfig"))
- for file in glob(os.path.join(mono_etc_dir, "*")):
- if os.path.isfile(file):
- copy(file, target_mono_config_dir)
+def find_executable(name):
+ is_windows = os.name == "nt"
+ windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None
+ path_dirs = os.environ["PATH"].split(ENV_PATH_SEP)
+ search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
-def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
- from shutil import copy
+ for dir in search_dirs:
+ path = os.path.join(dir, name)
- def copy_if_exists(src, dst):
- if os.path.isfile(src):
- copy(src, dst)
+ if is_windows:
+ for extension in windows_exts:
+ path_with_ext = path + extension
- platform = env["platform"]
+ if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK):
+ return path_with_ext
+ else:
+ if os.path.isfile(path) and os.access(path, os.X_OK):
+ return path
- if platform == "windows":
- src_mono_bin_dir = os.path.join(mono_root, "bin")
- target_mono_bin_dir = os.path.join(target_mono_root_dir, "bin")
-
- if not os.path.isdir(target_mono_bin_dir):
- os.makedirs(target_mono_bin_dir)
-
- mono_posix_helper_file = find_file_in_dir(
- src_mono_bin_dir, ["MonoPosixHelper"], prefixes=["", "lib"], extensions=[".dll"]
- )
- copy(
- os.path.join(src_mono_bin_dir, mono_posix_helper_file),
- os.path.join(target_mono_bin_dir, "MonoPosixHelper.dll"),
- )
-
- # For newer versions
- btls_dll_path = os.path.join(src_mono_bin_dir, "libmono-btls-shared.dll")
- if os.path.isfile(btls_dll_path):
- copy(btls_dll_path, target_mono_bin_dir)
- else:
- target_mono_lib_dir = (
- get_android_out_dir(env) if platform == "android" else os.path.join(target_mono_root_dir, "lib")
- )
-
- if not os.path.isdir(target_mono_lib_dir):
- os.makedirs(target_mono_lib_dir)
-
- lib_file_names = []
- if platform == "macos":
- lib_file_names = [
- lib_name + ".dylib"
- for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"]
- ]
- elif is_unix_like(platform):
- lib_file_names = [
- lib_name + ".so"
- for lib_name in [
- "libmono-btls-shared",
- "libmono-ee-interp",
- "libmono-native",
- "libMonoPosixHelper",
- "libmono-profiler-aot",
- "libmono-profiler-coverage",
- "libmono-profiler-log",
- "libMonoSupportW",
- ]
- ]
-
- for lib_file_name in lib_file_names:
- copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir)
-
-
-def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
- tmpenv = Environment()
- tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
- tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
- for hint_dir in tmpenv["LIBPATH"]:
- name_found = find_name_in_dir_files(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
- if name_found and os.path.isdir(os.path.join(hint_dir, "..", "include", "mono-2.0")):
- return os.path.join(hint_dir, "..")
return ""
diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
deleted file mode 100644
index 43c1ec8f8a..0000000000
--- a/modules/mono/build_scripts/mono_reg_utils.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import os
-import platform
-
-if os.name == "nt":
- import winreg
-
-
-def _reg_open_key(key, subkey):
- try:
- return winreg.OpenKey(key, subkey)
- except OSError:
- if platform.architecture()[0] == "32bit":
- bitness_sam = winreg.KEY_WOW64_64KEY
- else:
- bitness_sam = winreg.KEY_WOW64_32KEY
- return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
-
-
-def _reg_open_key_bits(key, subkey, bits):
- sam = winreg.KEY_READ
-
- if platform.architecture()[0] == "32bit":
- if bits == "64":
- # Force 32bit process to search in 64bit registry
- sam |= winreg.KEY_WOW64_64KEY
- else:
- if bits == "32":
- # Force 64bit process to search in 32bit registry
- sam |= winreg.KEY_WOW64_32KEY
-
- return winreg.OpenKey(key, subkey, 0, sam)
-
-
-def _find_mono_in_reg(subkey, bits):
- try:
- with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value = winreg.QueryValueEx(hKey, "SdkInstallRoot")[0]
- return value
- except OSError:
- return None
-
-
-def _find_mono_in_reg_old(subkey, bits):
- try:
- with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr = winreg.QueryValueEx(hKey, "DefaultCLR")[0]
- if default_clr:
- return _find_mono_in_reg(subkey + "\\" + default_clr, bits)
- return None
- except OSError:
- return None
-
-
-def find_mono_root_dir(bits):
- root_dir = _find_mono_in_reg(r"SOFTWARE\Mono", bits)
- if root_dir is not None:
- return str(root_dir)
- root_dir = _find_mono_in_reg_old(r"SOFTWARE\Novell\Mono", bits)
- if root_dir is not None:
- return str(root_dir)
- return ""
-
-
-def find_msbuild_tools_path_reg():
- import subprocess
-
- vswhere = os.getenv("PROGRAMFILES(X86)")
- if not vswhere:
- vswhere = os.getenv("PROGRAMFILES")
- vswhere += r"\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: " + e.message)
- except subprocess.CalledProcessError as e:
- print(e.output)
- except OSError as e:
- print(e)
-
- # Try to find 14.0 in the Registry
-
- try:
- subkey = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0"
- with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0]
- return value
- except OSError:
- return ""
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 010f1ef1e5..d156877929 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,4 +1,6 @@
-supported_platforms = ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"]
+# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"]
+# Eventually support for each them should be added back (except Haiku if not supported by .NET Core)
+supported_platforms = ["windows", "macos", "linuxbsd", "server"]
def can_build(env, platform):
@@ -13,26 +15,11 @@ def get_opts(platform):
return [
PathVariable(
- "mono_prefix",
- "Path to the Mono installation directory for the target platform and architecture",
+ "dotnet_root",
+ "Path to the .NET Sdk installation directory for the target platform and architecture",
"",
PathVariable.PathAccept,
),
- PathVariable(
- "mono_bcl",
- "Path to a custom Mono BCL (Base Class Library) directory for the target platform",
- "",
- PathVariable.PathAccept,
- ),
- BoolVariable("mono_static", "Statically link Mono", default_mono_static),
- BoolVariable("build_cil", "Build C# solutions", True),
- BoolVariable(
- "copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True
- ),
- # TODO: It would be great if this could be detected automatically instead
- BoolVariable(
- "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib
- ),
]
@@ -44,13 +31,6 @@ def configure(env):
env.add_module_version_string("mono")
- if env["mono_bundles_zlib"]:
- # Mono may come with zlib bundled for WASM or on newer version when built with MinGW.
- print("This Mono runtime comes with zlib bundled. Disabling 'builtin_zlib'...")
- env["builtin_zlib"] = False
- thirdparty_zlib_dir = "#thirdparty/zlib/"
- env.Prepend(CPPPATH=[thirdparty_zlib_dir])
-
def get_doc_classes():
return [
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index b088271b18..772c705981 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -30,8 +30,6 @@
#include "csharp_script.h"
-#include <mono/metadata/threads.h>
-#include <mono/metadata/tokentype.h>
#include <stdint.h>
#include "core/config/project_settings.h"
@@ -59,7 +57,6 @@
#include "godotsharp_dirs.h"
#include "managed_callable.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_utils.h"
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
#include "utils/string_utils.h"
@@ -107,8 +104,12 @@ Error CSharpLanguage::execute_file(const String &p_path) {
return OK;
}
-extern void *godotsharp_pinvoke_funcs[164];
+extern void *godotsharp_pinvoke_funcs[176];
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
+#ifdef TOOLS_ENABLED
+extern void *godotsharp_editor_pinvoke_funcs[32];
+[[maybe_unused]] volatile void **do_not_strip_godotsharp_editor_pinvoke_funcs;
+#endif
void CSharpLanguage::init() {
#ifdef DEBUG_METHODS_ENABLED
@@ -122,6 +123,9 @@ void CSharpLanguage::init() {
// 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;
+#ifdef TOOLS_ENABLED
+ do_not_strip_godotsharp_editor_pinvoke_funcs = (volatile void **)godotsharp_editor_pinvoke_funcs;
+#endif
#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
// Generate the bindings here, before loading assemblies. The Godot assemblies
@@ -709,19 +713,14 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
}
void CSharpLanguage::frame() {
- if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) {
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_FrameCallback.invoke(&exc);
- if (exc) {
- GDMonoUtils::debug_unhandled_exception(exc);
- }
+ if (gdmono && gdmono->is_runtime_initialized() && GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_FrameCallback();
}
}
void CSharpLanguage::reload_all_scripts() {
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
- GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(false);
}
#endif
@@ -738,7 +737,6 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
- GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(p_soft_reload);
}
#endif
@@ -750,6 +748,8 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
return false;
}
+#warning TODO
+#if 0
GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
String appname_safe = ProjectSettings::get_singleton()->get_safe_project_name();
@@ -777,6 +777,9 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
}
return true;
+#else
+ return false;
+#endif
}
void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
@@ -812,7 +815,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoException *exc = nullptr;
- bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle
+ bool success = (bool)GDMonoCache::managed_callbacks.methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle
.invoke(managed_callable->delegate_handle,
managed_serialized_data, &exc);
@@ -1098,7 +1101,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
MonoDelegate *delegate = nullptr;
MonoException *exc = nullptr;
- bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TryDeserializeDelegate.invoke(managed_serialized_data, &delegate, &exc);
+ bool success = (bool)GDMonoCache::managed_callbacks.methodthunk_DelegateUtils_TryDeserializeDelegate.invoke(managed_serialized_data, &delegate, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -1135,7 +1138,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
void *delegate = nullptr;
MonoException *exc = nullptr;
- bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle
+ bool success = (bool)GDMonoCache::managed_callbacks.methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle
.invoke(managed_serialized_data, &delegate, &exc);
if (exc) {
@@ -1179,22 +1182,6 @@ bool CSharpLanguage::overrides_external_editor() {
}
#endif
-void CSharpLanguage::thread_enter() {
-#if 0
- if (gdmono->is_runtime_initialized()) {
- GDMonoUtils::attach_current_thread();
- }
-#endif
-}
-
-void CSharpLanguage::thread_exit() {
-#if 0
- if (gdmono->is_runtime_initialized()) {
- GDMonoUtils::detach_current_thread();
- }
-#endif
-}
-
bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
// Not a parser error in our case, but it's still used for other type of errors
if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
@@ -1241,27 +1228,16 @@ void CSharpLanguage::_on_scripts_domain_about_to_unload() {
#ifdef TOOLS_ENABLED
void CSharpLanguage::_editor_init_callback() {
- register_editor_internal_calls();
-
- // Initialize GodotSharpEditor
-
- MonoClass *editor_klass = mono_class_from_name(
- GDMono::get_singleton()->get_tools_assembly()->get_image(),
- "GodotTools", "GodotSharpEditor");
- CRASH_COND(editor_klass == nullptr);
+ // Load GodotTools and initialize GodotSharpEditor
- MonoMethod *create_instance = mono_class_get_method_from_name(editor_klass, "InternalCreateInstance", 0);
- CRASH_COND(create_instance == nullptr);
-
- MonoException *exc = nullptr;
- MonoObject *ret = mono_runtime_invoke(create_instance, nullptr, nullptr, (MonoObject **)&exc);
- UNHANDLED_EXCEPTION(exc);
-
- EditorPlugin *godotsharp_editor = *(EditorPlugin **)mono_object_unbox(ret);
+ Object *editor_plugin_obj = GDMono::get_singleton()->plugin_callbacks.LoadToolsAssemblyCallback(
+ GodotSharpDirs::get_data_editor_tools_dir().plus_file("GodotTools.dll").utf16());
+ CRASH_COND(editor_plugin_obj == nullptr);
+ EditorPlugin *godotsharp_editor = Object::cast_to<EditorPlugin>(editor_plugin_obj);
CRASH_COND(godotsharp_editor == nullptr);
- // Enable it as a plugin
+ // Add plugin to EditorNode and enable it
EditorNode::add_editor_plugin(godotsharp_editor);
ED_SHORTCUT("mono/build_solution", TTR("Build Solution"), KeyModifierMask::ALT | Key::B);
godotsharp_editor->enable_plugin();
@@ -1328,15 +1304,8 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
ERR_FAIL_COND_V_MSG(!parent_is_object_class, false,
"Type inherits from native type '" + type_name + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'.");
- MonoException *exc = nullptr;
GCHandleIntPtr strong_gchandle =
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding
- .invoke(&type_name, p_object, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return false;
- }
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding(&type_name, p_object);
ERR_FAIL_NULL_V(strong_gchandle.value, false);
@@ -1395,8 +1364,6 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
}
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
{
MutexLock lock(csharp_lang->language_bind_mutex);
@@ -1407,10 +1374,8 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
if (script_binding.inited) {
// Set the native instance field to IntPtr.Zero, if not yet garbage collected.
// This is done to avoid trying to dispose the native instance from Dispose(bool).
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SetGodotObjectPtr
- .invoke(script_binding.gchandle.get_intptr(), nullptr, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_SetGodotObjectPtr(
+ script_binding.gchandle.get_intptr(), nullptr);
script_binding.gchandle.release();
script_binding.inited = false;
@@ -1442,8 +1407,6 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
if (p_reference) {
// Refcount incremented
if (refcount > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -1455,10 +1418,8 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
GCHandleIntPtr new_gchandle;
bool create_weak = false;
- MonoException *exc = nullptr;
- bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
- .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
- UNHANDLED_EXCEPTION(exc);
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
if (!target_alive) {
return false; // Called after the managed side was collected, so nothing to do here
@@ -1471,8 +1432,6 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
} else {
// Refcount decremented
if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -1483,10 +1442,8 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
GCHandleIntPtr new_gchandle;
bool create_weak = true;
- MonoException *exc = nullptr;
- bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
- .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
- UNHANDLED_EXCEPTION(exc);
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
if (!target_alive) {
return refcount == 0; // Called after the managed side was collected, so nothing to do here
@@ -1668,35 +1625,19 @@ Object *CSharpInstance::get_owner() {
bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND_V(!script.is_valid(), false);
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- MonoException *exc = nullptr;
- bool ret = GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Set.invoke(
- gchandle.get_intptr(), &p_name, &p_value, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- } else if (ret) {
- return true;
- }
-
- return false;
+ return GDMonoCache::managed_callbacks.CSharpInstanceBridge_Set(
+ gchandle.get_intptr(), &p_name, &p_value);
}
bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
ERR_FAIL_COND_V(!script.is_valid(), false);
- GD_MONO_SCOPE_THREAD_ATTACH;
-
Variant ret_value;
- MonoException *exc = nullptr;
- bool ret = GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Get.invoke(
- gchandle.get_intptr(), &p_name, &ret_value, &exc);
+ bool ret = GDMonoCache::managed_callbacks.CSharpInstanceBridge_Get(
+ gchandle.get_intptr(), &p_name, &ret_value);
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- } else if (ret) {
+ if (ret) {
r_ret = ret_value;
return true;
}
@@ -1756,7 +1697,7 @@ 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)GDMonoCache::cached_data.methodthunk_DelegateUtils_TrySerializeDelegate
+ bool success = (bool)GDMonoCache::managed_callbacks.methodthunk_DelegateUtils_TrySerializeDelegate
.invoke(delegate_field_value, managed_serialized_data, &exc);
if (exc) {
@@ -1781,26 +1722,25 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
ERR_FAIL_COND(!script.is_valid());
- GD_MONO_SCOPE_THREAD_ATTACH;
-
StringName method = SNAME("_get_property_list");
Variant ret;
Callable::CallError call_error;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
- gchandle.get_intptr(), &method, nullptr, 0, &call_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
-
- ERR_FAIL_COND_MSG(call_error.error != Callable::CallError::CALL_OK,
- "Error calling '_get_property_list': " + Variant::get_call_error_text(method, nullptr, 0, call_error));
-
- Array array = ret;
- for (int i = 0, size = array.size(); i < size; i++) {
- p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
+ bool ok = GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &method, nullptr, 0, &call_error, &ret);
+
+ // CALL_ERROR_INVALID_METHOD would simply mean it was not overridden
+ if (call_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT("Error calling '_get_property_list': " + Variant::get_call_error_text(method, nullptr, 0, call_error));
+ } else if (!ok) {
+ ERR_PRINT("Unexpected error calling '_get_property_list'");
+ } else {
+ Array array = ret;
+ for (int i = 0, size = array.size(); i < size; i++) {
+ p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
+ }
+ }
}
for (const PropertyInfo &prop : props) {
@@ -1826,22 +1766,13 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *
bool CSharpInstance::property_can_revert(const StringName &p_name) const {
ERR_FAIL_COND_V(!script.is_valid(), false);
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- Callable::CallError call_error;
-
Variant name_arg = p_name;
const Variant *args[1] = { &name_arg };
Variant ret;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
- gchandle.get_intptr(), &CACHED_STRING_NAME(_property_can_revert), args, 1, &call_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return false;
- }
+ Callable::CallError call_error;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_can_revert), args, 1, &call_error, &ret);
if (call_error.error != Callable::CallError::CALL_OK) {
return false;
@@ -1853,22 +1784,13 @@ bool CSharpInstance::property_can_revert(const StringName &p_name) const {
bool CSharpInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
ERR_FAIL_COND_V(!script.is_valid(), false);
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- Callable::CallError call_error;
-
Variant name_arg = p_name;
const Variant *args[1] = { &name_arg };
Variant ret;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
- gchandle.get_intptr(), &CACHED_STRING_NAME(_property_get_revert), args, 1, &call_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return false;
- }
+ Callable::CallError call_error;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_get_revert), args, 1, &call_error, &ret);
if (call_error.error != Callable::CallError::CALL_OK) {
return false;
@@ -1909,36 +1831,23 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
return false;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ if (!GDMonoCache::godot_api_cache_updated) {
return false;
}
String method = p_method;
bool deep = true;
- MonoException *exc = nullptr;
- bool found = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasMethodUnknownParams
- .invoke(script.ptr(), &method, deep, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return found;
+ return GDMonoCache::managed_callbacks.ScriptManagerBridge_HasMethodUnknownParams(
+ script.ptr(), &method, deep);
}
Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
ERR_FAIL_COND_V(!script.is_valid(), Variant());
- GD_MONO_SCOPE_THREAD_ATTACH;
-
Variant ret;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
- gchandle.get_intptr(), &p_method, p_args, p_argcount, &r_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &p_method, p_args, p_argcount, &r_error, &ret);
return ret;
}
@@ -1992,13 +1901,10 @@ bool CSharpInstance::_internal_new_managed() {
ERR_FAIL_NULL_V(owner, false);
ERR_FAIL_COND_V(script.is_null(), false);
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance
- .invoke(script.ptr(), owner, nullptr, 0, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
+ bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance(
+ script.ptr(), owner, nullptr, 0);
+ if (!ok) {
// Important to clear this before destroying the script instance here
script = Ref<CSharpScript>();
owner = nullptr;
@@ -2084,8 +1990,6 @@ void CSharpInstance::refcount_incremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
@@ -2097,10 +2001,8 @@ void CSharpInstance::refcount_incremented() {
GCHandleIntPtr new_gchandle;
bool create_weak = false;
- MonoException *exc = nullptr;
- bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
- .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
- UNHANDLED_EXCEPTION(exc);
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
if (!target_alive) {
return; // Called after the managed side was collected, so nothing to do here
@@ -2121,8 +2023,6 @@ bool CSharpInstance::refcount_decremented() {
int refcount = rc_owner->reference_get_count();
if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
@@ -2133,10 +2033,8 @@ bool CSharpInstance::refcount_decremented() {
GCHandleIntPtr new_gchandle;
bool create_weak = true;
- MonoException *exc = nullptr;
- bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
- .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
- UNHANDLED_EXCEPTION(exc);
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
if (!target_alive) {
return refcount == 0; // Called after the managed side was collected, so nothing to do here
@@ -2157,8 +2055,6 @@ const Variant CSharpInstance::get_rpc_config() const {
}
void CSharpInstance::notification(int p_notification) {
- GD_MONO_SCOPE_THREAD_ATTACH;
-
if (p_notification == Object::NOTIFICATION_PREDELETE) {
// When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
@@ -2178,13 +2074,8 @@ void CSharpInstance::notification(int p_notification) {
_call_notification(p_notification);
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
- .invoke(gchandle.get_intptr(), /* okIfNull */ false, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ gchandle.get_intptr(), /* okIfNull */ false);
return;
}
@@ -2193,8 +2084,6 @@ void CSharpInstance::notification(int p_notification) {
}
void CSharpInstance::_call_notification(int p_notification) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
Variant arg = p_notification;
const Variant *args[1] = { &arg };
StringName method_name = SNAME("_notification");
@@ -2202,32 +2091,16 @@ void CSharpInstance::_call_notification(int p_notification) {
Callable::CallError call_error;
Variant ret;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
- gchandle.get_intptr(), &method_name, args, 1, &call_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &method_name, args, 1, &call_error, &ret);
}
String CSharpInstance::to_string(bool *r_valid) {
- GD_MONO_SCOPE_THREAD_ATTACH;
-
String res;
bool valid;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallToString
- .invoke(gchandle.get_intptr(), &res, &valid, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- if (r_valid) {
- *r_valid = false;
- }
- return String();
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallToString(
+ gchandle.get_intptr(), &res, &valid);
if (r_valid) {
*r_valid = valid;
@@ -2249,8 +2122,6 @@ CSharpInstance::CSharpInstance(const Ref<CSharpScript> &p_script) :
}
CSharpInstance::~CSharpInstance() {
- GD_MONO_SCOPE_THREAD_ATTACH;
-
destructing_script_instance = true;
// Must make sure event signals are not left dangling
@@ -2264,13 +2135,8 @@ CSharpInstance::~CSharpInstance() {
// we must call Dispose here, because Dispose calls owner->set_script_instance(nullptr)
// and that would mess up with the new script instance if called later.
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
- .invoke(gchandle.get_intptr(), /* okIfNull */ true, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ gchandle.get_intptr(), /* okIfNull */ true);
}
gchandle.release(); // Make sure the gchandle is released
@@ -2341,8 +2207,6 @@ void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values,
void CSharpScript::_update_member_info_no_exports() {
if (exports_invalidated) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
exports_invalidated = false;
member_info.clear();
@@ -2888,10 +2752,8 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
// only for this, so need to call the destructor manually before passing this to C#.
rpc_functions_dict.~Dictionary();
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_UpdateScriptClassInfo
- .invoke(p_script.ptr(), &tool, &rpc_functions_dict, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo(
+ p_script.ptr(), &tool, &rpc_functions_dict);
p_script->tool = tool;
@@ -2910,13 +2772,7 @@ bool CSharpScript::can_instantiate() const {
// For tool scripts, this will never fire if the class is not found. That's because we
// don't know if it's a tool script if we can't find the class to access the attributes.
if (extra_cond && !valid) {
- if (GDMono::get_singleton()->get_project_assembly() == nullptr) {
- // The project assembly is not loaded
- ERR_FAIL_V_MSG(false, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
- } else {
- // The project assembly is loaded, but the class could not found
- ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'.");
- }
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'.");
}
return valid && extra_cond;
@@ -2924,16 +2780,11 @@ bool CSharpScript::can_instantiate() const {
StringName CSharpScript::get_instance_base_type() const {
StringName native_name;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
- .invoke(this, &native_name, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
return native_name;
}
CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
/* STEP 1, CREATE */
Ref<RefCounted> ref;
@@ -2949,13 +2800,8 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited && !script_binding.gchandle.is_released()) {
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
- .invoke(script_binding.gchandle.get_intptr(), /* okIfNull */ true, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ script_binding.gchandle.get_intptr(), /* okIfNull */ true);
script_binding.gchandle.release(); // Just in case
script_binding.inited = false;
@@ -2969,13 +2815,10 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
/* STEP 2, INITIALIZE AND CONSTRUCT */
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance
- .invoke(this, p_owner, p_args, p_argcount, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
+ bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance(
+ this, p_owner, p_args, p_argcount);
+ if (!ok) {
// Important to clear this before destroying the script instance here
instance->script = Ref<CSharpScript>();
instance->owner = nullptr;
@@ -3001,15 +2844,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
r_error.error = Callable::CallError::CALL_OK;
StringName native_name;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
- .invoke(this, &native_name, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
ERR_FAIL_COND_V(native_name == StringName(), Variant());
- GD_MONO_SCOPE_THREAD_ATTACH;
-
Object *owner = ClassDB::instantiate(native_name);
Ref<RefCounted> ref;
@@ -3038,13 +2876,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
CRASH_COND(!valid);
#endif
- GD_MONO_SCOPE_THREAD_ATTACH;
-
StringName native_name;
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
- .invoke(this, &native_name, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
ERR_FAIL_COND_V(native_name == StringName(), nullptr);
@@ -3100,8 +2933,6 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
return;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
#warning TODO
#if 0
// TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
@@ -3126,19 +2957,15 @@ bool CSharpScript::has_method(const StringName &p_method) const {
return false;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ if (!GDMonoCache::godot_api_cache_updated) {
return false;
}
String method = p_method;
bool deep = false;
- MonoException *exc = nullptr;
- bool found = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasMethodUnknownParams
- .invoke(this, &method, deep, &exc);
- UNHANDLED_EXCEPTION(exc);
+ bool found = GDMonoCache::managed_callbacks.ScriptManagerBridge_HasMethodUnknownParams(
+ this, &method, deep);
return found;
}
@@ -3148,8 +2975,6 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
return MethodInfo();
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
#warning TODO
#if 0
GDMonoClass *top = script_class;
@@ -3176,14 +3001,9 @@ Error CSharpScript::reload(bool p_keep_state) {
// That's done separately via domain reloading.
reload_invalidated = false;
- GD_MONO_SCOPE_THREAD_ATTACH;
-
String script_path = get_path();
- MonoException *exc = nullptr;
- valid = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_AddScriptBridge
- .invoke(this, &script_path, &exc);
- UNHANDLED_EXCEPTION(exc);
+ valid = GDMonoCache::managed_callbacks.ScriptManagerBridge_AddScriptBridge(this, &script_path);
if (valid) {
#ifdef DEBUG_ENABLED
@@ -3230,18 +3050,13 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const {
return false;
}
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ if (!GDMonoCache::godot_api_cache_updated) {
return false;
}
String signal = p_signal;
- MonoException *exc = nullptr;
- bool res = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasScriptSignal
- .invoke(this, &signal, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return res;
+ return GDMonoCache::managed_callbacks.ScriptManagerBridge_HasScriptSignal(this, &signal);
}
void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
@@ -3251,7 +3066,7 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
// Performance is not critical here as this will be replaced with source generators.
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ if (!GDMonoCache::godot_api_cache_updated) {
return;
}
@@ -3260,10 +3075,7 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
// only for this, so need to call the destructor manually before passing this to C#.
signals_dict.~Dictionary();
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptSignalList
- .invoke(this, &signals_dict, &exc);
- UNHANDLED_EXCEPTION(exc);
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptSignalList(this, &signals_dict);
for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) {
MethodInfo mi;
@@ -3296,16 +3108,11 @@ bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
return false;
}
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ if (!GDMonoCache::godot_api_cache_updated) {
return false;
}
- MonoException *exc = nullptr;
- bool res = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_ScriptIsOrInherits
- .invoke(this, cs.ptr(), &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return res;
+ return GDMonoCache::managed_callbacks.ScriptManagerBridge_ScriptIsOrInherits(this, cs.ptr());
}
Ref<Script> CSharpScript::get_base_script() const {
@@ -3379,10 +3186,8 @@ CSharpScript::~CSharpScript() {
CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
#endif
- if (GDMonoCache::cached_data.godot_api_cache_updated) {
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_RemoveScriptBridge.invoke(this, &exc);
- UNHANDLED_EXCEPTION(exc);
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_RemoveScriptBridge(this);
}
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 34b2e7f735..9be4c9c130 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -39,7 +39,6 @@
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
-#include "mono_gd/gd_mono_internals.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_plugin.h"
@@ -465,10 +464,6 @@ public:
bool overrides_external_editor() override;
#endif
- /* THREAD ATTACHING */
- void thread_enter() override;
- void thread_exit() override;
-
RBMap<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
@@ -476,9 +471,12 @@ public:
static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted);
static void tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged);
+#warning TODO
+#if 0
#ifdef DEBUG_ENABLED
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
#endif
+#endif
void post_unsafe_reference(Object *p_obj);
void pre_unsafe_unreference(Object *p_obj);
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index b981542801..faf3512da7 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -10,55 +10,10 @@
<tutorials>
</tutorials>
<methods>
- <method name="attach_thread">
- <return type="void" />
- <description>
- Attaches the current thread to the Mono runtime.
- </description>
- </method>
- <method name="detach_thread">
- <return type="void" />
- <description>
- Detaches the current thread from the Mono runtime.
- </description>
- </method>
- <method name="get_domain_id">
- <return type="int" />
- <description>
- Returns the current MonoDomain ID.
- [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash.
- </description>
- </method>
- <method name="get_scripts_domain_id">
- <return type="int" />
- <description>
- Returns the scripts MonoDomain's ID. This will be the same MonoDomain ID as [method get_domain_id], unless the scripts domain isn't loaded.
- [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash.
- </description>
- </method>
- <method name="is_domain_finalizing_for_unload">
- <return type="bool" />
- <param index="0" name="domain_id" type="int" />
- <description>
- Returns [code]true[/code] if the domain is being finalized, [code]false[/code] otherwise.
- </description>
- </method>
<method name="is_runtime_initialized">
<return type="bool" />
<description>
- Returns [code]true[/code] if the Mono runtime is initialized, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="is_runtime_shutting_down">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the Mono runtime is shutting down, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="is_scripts_domain_loaded">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the scripts domain is loaded, [code]false[/code] otherwise.
+ Returns [code]true[/code] if the .NET runtime is initialized, [code]false[/code] otherwise.
</description>
</method>
</methods>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
index d1868f52ef..03a7dc453c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.NET.Sdk", "Godot.NET.Sdk\Godot.NET.Sdk.csproj", "{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}"
EndProject
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
index 24f7909861..c5a29a53f7 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
index 2bf1cb7a18..01aa65bfc3 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
@@ -7,8 +7,6 @@ namespace GodotTools.BuildLogger
{
public class GodotBuildLogger : ILogger
{
- public static readonly string AssemblyPath = Path.GetFullPath(typeof(GodotBuildLogger).Assembly.Location);
-
public string Parameters { get; set; }
public LoggerVerbosity Verbosity { get; set; }
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
index 0afec970c6..9e36497b06 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
@@ -5,6 +5,6 @@
<LangVersion>7.2</LangVersion>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Build.Framework" Version="16.5.0" />
+ <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
index d6d8962f90..caf0b9c7bb 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</ProjectGuid>
- <TargetFramework>netstandard2.0</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
index 303ca3a293..d2132115f3 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{B06C2951-C8E3-4F28-80B2-717CF327EB19}</ProjectGuid>
<OutputType>Exe</OutputType>
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
index 5b3ed0b1b7..c05096bdcc 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid>
<OutputType>Exe</OutputType>
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
index 37123ba2b2..dff40fb846 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
@@ -1,32 +1,16 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
- <TargetFramework>net472</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Build" Version="16.5.0" />
+ <PackageReference Include="Microsoft.Build" Version="15.1.548" ExcludeAssets="runtime" />
+ <PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
<ProjectReference Include="..\GodotTools.Shared\GodotTools.Shared.csproj" />
</ItemGroup>
- <!--
- The Microsoft.Build.Runtime package is too problematic so we create a MSBuild.exe stub. The workaround described
- here doesn't work with Microsoft.NETFramework.ReferenceAssemblies: https://github.com/microsoft/msbuild/issues/3486
- We need a MSBuild.exe file as there's an issue in Microsoft.Build where it executes platform dependent code when
- searching for MSBuild.exe before the fallback to not using it. A stub is fine as it should never be executed.
- -->
- <ItemGroup>
- <None Include="MSBuild.exe" CopyToOutputDirectory="Always" />
- </ItemGroup>
- <Target Name="CopyMSBuildStubWindows" AfterTargets="Build" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) ">
- <PropertyGroup>
- <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
- <GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir>
- </PropertyGroup>
- <!-- Need to copy it here as well on Windows -->
- <Copy SourceFiles="MSBuild.exe" DestinationFiles="$(GodotOutputDataDir)\Mono\lib\mono\v4.0\MSBuild.exe" />
- </Target>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe
deleted file mode 100644
index e69de29bb2..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe
+++ /dev/null
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index 7d49d251dd..c549cf5f12 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -21,7 +21,8 @@ namespace GodotTools.ProjectEditor
root.Sdk = GodotSdkAttrValue;
var mainGroup = root.AddPropertyGroup();
- mainGroup.AddProperty("TargetFramework", "netstandard2.1");
+ mainGroup.AddProperty("TargetFramework", "net5.0");
+ mainGroup.AddProperty("EnableDynamicLoading", "true");
string sanitizedName = IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true);
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index cdac9acb25..9b921c517c 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -19,6 +19,9 @@ namespace GodotTools.ProjectEditor
public static class ProjectUtils
{
+ public static void MSBuildLocatorRegisterDefaults()
+ => Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
+
public static MSBuildProject Open(string path)
{
var root = ProjectRootElement.Open(path);
@@ -42,7 +45,8 @@ namespace GodotTools.ProjectEditor
var root = project.Root;
string godotSdkAttrValue = ProjectGenerator.GodotSdkAttrValue;
- if (!string.IsNullOrEmpty(root.Sdk) && root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(root.Sdk) &&
+ root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase))
return;
root.Sdk = godotSdkAttrValue;
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
index 3bc1698c15..4b058a5daa 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.0</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<Import Project="GenerateGodotNupkgsVersions.targets" />
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln
index d3107a69db..415e49b426 100644
--- a/modules/mono/editor/GodotTools/GodotTools.sln
+++ b/modules/mono/editor/GodotTools/GodotTools.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.ProjectEditor", "GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index 33967ffa71..58677625c6 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -1,9 +1,9 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
using GodotTools.Ides.Rider;
using GodotTools.Internals;
-using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS;
@@ -159,7 +159,7 @@ namespace GodotTools.Build
}
}
- public static bool BuildProjectBlocking(string config, [CanBeNull] string[] targets = null, [CanBeNull] string platform = null)
+ public static bool BuildProjectBlocking(string config, [MaybeNull] string[] targets = null, [MaybeNull] string platform = null)
{
var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets ?? new[] {"Build"}, config, restore: true);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index ebdaca0ce8..ed5ee10585 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -1,8 +1,8 @@
using Godot;
using System;
+using System.Diagnostics.CodeAnalysis;
using Godot.Collections;
using GodotTools.Internals;
-using JetBrains.Annotations;
using File = GodotTools.Utils.File;
using Path = System.IO.Path;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index 02e9d98647..0e793a44ba 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -127,7 +127,7 @@ namespace GodotTools.Build
arguments += $@" /t:{string.Join(",", buildInfo.Targets)} " +
$@"""/p:{"Configuration=" + buildInfo.Configuration}"" /v:normal " +
- $@"""/l:{typeof(GodotBuildLogger).FullName},{GodotBuildLogger.AssemblyPath};{buildInfo.LogsDirPath}""";
+ $@"""{AddLoggerArgument(buildInfo)}""";
foreach (string customProperty in buildInfo.CustomProperties)
{
@@ -137,6 +137,14 @@ namespace GodotTools.Build
return arguments;
}
+ private static string AddLoggerArgument(BuildInfo buildInfo)
+ {
+ string buildLoggerPath = Path.Combine(GodotSharpDirs.DataEditorToolsDir,
+ "GodotTools.BuildLogger.dll");
+
+ return $"/l:{typeof(GodotBuildLogger).FullName},{buildLoggerPath};{buildInfo.LogsDirPath}";
+ }
+
private static void RemovePlatformVariable(StringDictionary environmentVariables)
{
// EnvironmentVariables is case sensitive? Seriously?
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 3c020a2589..13b3ab7da2 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -1,7 +1,6 @@
using System;
using Godot;
using GodotTools.Internals;
-using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
@@ -28,7 +27,6 @@ namespace GodotTools.Build
BuildOutputView.UpdateIssuesList();
}
- [UsedImplicitly]
public void BuildSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
@@ -57,7 +55,6 @@ namespace GodotTools.Build
Internal.ReloadAssemblies(softReload: false);
}
- [UsedImplicitly]
private void RebuildSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
@@ -86,7 +83,6 @@ namespace GodotTools.Build
Internal.ReloadAssemblies(softReload: false);
}
- [UsedImplicitly]
private void CleanSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index ee3f5999cd..25c2e4ab59 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -3,13 +3,13 @@ using Godot.NativeInterop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using GodotTools.Build;
using GodotTools.Core;
using GodotTools.Internals;
-using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using Directory = GodotTools.Utils.Directory;
using File = GodotTools.Utils.File;
@@ -238,8 +238,9 @@ namespace GodotTools.Export
using godot_string buildConfigAux = Marshaling.mono_string_to_godot(buildConfig);
using godot_string bclDirAux = Marshaling.mono_string_to_godot(bclDir);
godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue;
- internal_GetExportedAssemblyDependencies(initialAssembliesAux, buildConfigAux, bclDirAux,
- ref assembliesAux);
+ // TODO
+ throw new NotImplementedException();
+ //internal_GetExportedAssemblyDependencies(initialAssembliesAux, buildConfigAux, bclDirAux, ref assembliesAux);
AddI18NAssemblies(assemblies, bclDir);
@@ -349,7 +350,7 @@ namespace GodotTools.Export
}
}
- [NotNull]
+ [return: NotNull]
private static string ExportDataDirectory(string[] features, string platform, bool isDebug, string outputDir)
{
string target = isDebug ? "release_debug" : "release";
@@ -498,10 +499,5 @@ namespace GodotTools.Export
string appNameSafe = appName.ToSafeDirName();
return $"data_{appNameSafe}";
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GetExportedAssemblyDependencies(
- in godot_dictionary initialAssemblies, in godot_string buildConfig,
- in godot_string customBclDir, ref godot_dictionary dependencyAssemblies);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 5167333716..2d85513766 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -51,6 +51,7 @@ namespace GodotTools
}
}
+ [UsedImplicitly]
private bool CreateProjectSolution()
{
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
@@ -75,7 +76,7 @@ namespace GodotTools
{
Guid = guid,
PathRelativeToSolution = name + ".csproj",
- Configs = new List<string> {"Debug", "ExportDebug", "ExportRelease"}
+ Configs = new List<string> { "Debug", "ExportDebug", "ExportRelease" }
};
solution.AddNewProject(name, projectInfo);
@@ -123,7 +124,8 @@ namespace GodotTools
try
{
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, fallbackFolder);
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ fallbackFolder);
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
}
catch (Exception e)
@@ -201,13 +203,15 @@ namespace GodotTools
try
{
if (Godot.OS.IsStdoutVerbose())
- Console.WriteLine($"Running: \"{command}\" {string.Join(" ", args.Select(a => $"\"{a}\""))}");
+ Console.WriteLine(
+ $"Running: \"{command}\" {string.Join(" ", args.Select(a => $"\"{a}\""))}");
OS.RunProcess(command, args);
}
catch (Exception e)
{
- GD.PushError($"Error when trying to run code editor: VisualStudio. Exception message: '{e.Message}'");
+ GD.PushError(
+ $"Error when trying to run code editor: VisualStudio. Exception message: '{e.Message}'");
}
break;
@@ -378,6 +382,8 @@ namespace GodotTools
{
base._EnablePlugin();
+ ProjectUtils.MSBuildLocatorRegisterDefaults();
+
if (Instance != null)
throw new InvalidOperationException();
Instance = this;
@@ -393,7 +399,7 @@ namespace GodotTools
MSBuildPanel = new MSBuildPanel();
_bottomPanelBtn = AddControlToBottomPanel(MSBuildPanel, "MSBuild".TTR());
- AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
+ AddChild(new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" });
_menuPopup = new PopupMenu();
_menuPopup.Hide();
@@ -469,7 +475,8 @@ namespace GodotTools
try
{
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, NuGetUtils.GodotFallbackFolderPath);
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index d44cd75155..d0fae02d5d 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid>
- <TargetFramework>net472</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
+ <EnableDynamicLoading>true</EnableDynamicLoading>
<LangVersion>8</LangVersion>
<!-- The Godot editor uses the Debug Godot API assemblies -->
<GodotApiConfiguration>Debug</GodotApiConfiguration>
@@ -21,6 +22,8 @@
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
+ <!-- For RiderPathLocator -->
+ <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<Reference Include="GodotSharp">
<HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath>
<Private>False</Private>
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
index 43b1cf0f64..414729b18e 100644
--- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -1,5 +1,6 @@
using Godot;
using GodotTools.Internals;
+using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
namespace GodotTools
@@ -25,6 +26,7 @@ namespace GodotTools
Internal.ReloadAssemblies(softReload: false);
}
+ [UsedImplicitly]
public void RestartTimer()
{
_watchTimer.Stop();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
index 71055f0125..4caab035de 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Runtime.Versioning;
using Godot;
-using JetBrains.Annotations;
using Microsoft.Win32;
using Newtonsoft.Json;
using Directory = System.IO.Directory;
@@ -113,6 +114,7 @@ namespace GodotTools.Ides.Rider
return installInfos.ToArray();
}
+ [SupportedOSPlatform("windows")]
private static RiderInfo[] CollectRiderInfosWindows()
{
var installInfos = new List<RiderInfo>();
@@ -217,6 +219,7 @@ namespace GodotTools.Ides.Rider
throw new Exception("Unknown OS.");
}
+ [SupportedOSPlatform("windows")]
private static void CollectPathsFromRegistry(string registryKey, List<string> installPaths)
{
using (var key = Registry.CurrentUser.OpenSubKey(registryKey))
@@ -229,6 +232,7 @@ namespace GodotTools.Ides.Rider
}
}
+ [SupportedOSPlatform("windows")]
private static void CollectPathsFromRegistry(List<string> installPaths, RegistryKey key)
{
if (key == null) return;
@@ -324,7 +328,7 @@ namespace GodotTools.Ides.Rider
{
public string install_location;
- [CanBeNull]
+ [return: MaybeNull]
public static string GetInstallLocationFromJson(string json)
{
try
@@ -378,7 +382,7 @@ namespace GodotTools.Ides.Rider
public string version;
public string versionSuffix;
- [CanBeNull]
+ [return: MaybeNull]
internal static ProductInfo GetProductInfo(string json)
{
try
@@ -402,7 +406,7 @@ namespace GodotTools.Ides.Rider
// ReSharper disable once InconsistentNaming
public ActiveApplication active_application;
- [CanBeNull]
+ [return: MaybeNull]
public static string GetLatestBuildFromJson(string json)
{
try
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
index b221ae7c5c..7d2eb2d869 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
@@ -9,23 +9,12 @@ namespace GodotTools.Internals
{
public string Task { get; }
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Create(in godot_string task, in godot_string label, int amount,
- bool canCancel);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Dispose(in godot_string task);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_Step(in godot_string task, in godot_string state, int step,
- bool forceRefresh);
-
public EditorProgress(string task, string label, int amount, bool canCancel = false)
{
Task = task;
using godot_string taskIn = Marshaling.mono_string_to_godot(task);
using godot_string labelIn = Marshaling.mono_string_to_godot(label);
- internal_Create(taskIn, labelIn, amount, canCancel);
+ Internal.godot_icall_EditorProgress_Create(taskIn, labelIn, amount, canCancel);
}
~EditorProgress()
@@ -39,7 +28,7 @@ namespace GodotTools.Internals
public void Dispose()
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
- internal_Dispose(taskIn);
+ Internal.godot_icall_EditorProgress_Dispose(taskIn);
GC.SuppressFinalize(this);
}
@@ -47,14 +36,14 @@ namespace GodotTools.Internals
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
using godot_string stateIn = Marshaling.mono_string_to_godot(state);
- internal_Step(taskIn, stateIn, step, forceRefresh);
+ Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
public bool TryStep(string state, int step = -1, bool forceRefresh = true)
{
using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
using godot_string stateIn = Marshaling.mono_string_to_godot(state);
- return internal_Step(taskIn, stateIn, step, forceRefresh);
+ return Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
index d79821de3c..3b65263aa9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
@@ -6,13 +6,13 @@ namespace GodotTools.Internals
{
public static class Globals
{
- public static float EditorScale => internal_EditorScale();
+ public static float EditorScale => Internal.godot_icall_Globals_EditorScale();
public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
- internal_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
}
@@ -21,7 +21,7 @@ namespace GodotTools.Internals
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
- internal_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
}
@@ -29,7 +29,7 @@ namespace GodotTools.Internals
public static unsafe object EditorShortcut(string setting)
{
using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
- internal_EditorShortcut(settingIn, out godot_variant result);
+ Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result);
using (result)
return Marshaling.variant_to_mono_object(&result);
}
@@ -38,28 +38,9 @@ namespace GodotTools.Internals
public static string TTR(this string text)
{
using godot_string textIn = Marshaling.mono_string_to_godot(text);
- internal_TTR(textIn, out godot_string dest);
+ Internal.godot_icall_Globals_TTR(textIn, out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
-
- // Internal Calls
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern float internal_EditorScale();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GlobalDef(in godot_string setting, in godot_variant defaultValue,
- bool restartIfChanged, out godot_variant result);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorDef(in godot_string setting, in godot_variant defaultValue,
- bool restartIfChanged, out godot_variant result);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorShortcut(in godot_string setting, out godot_variant result);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_TTR(in godot_string text, out godot_string dest);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index b15ebc1ae2..9011662248 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -9,7 +9,7 @@ namespace GodotTools.Internals
{
get
{
- internal_ResMetadataDir(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -19,7 +19,7 @@ namespace GodotTools.Internals
{
get
{
- internal_ResTempAssembliesBaseDir(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -29,7 +29,7 @@ namespace GodotTools.Internals
{
get
{
- internal_MonoUserDir(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_MonoUserDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -39,7 +39,7 @@ namespace GodotTools.Internals
{
get
{
- internal_BuildLogsDirs(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -49,7 +49,7 @@ namespace GodotTools.Internals
{
get
{
- internal_ProjectSlnPath(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_ProjectSlnPath(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -59,7 +59,7 @@ namespace GodotTools.Internals
{
get
{
- internal_ProjectCsProjPath(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_ProjectCsProjPath(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -69,35 +69,10 @@ namespace GodotTools.Internals
{
get
{
- internal_DataEditorToolsDir(out godot_string dest);
+ Internal.godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
}
-
- #region Internal
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ResMetadataDir(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ResTempAssembliesBaseDir(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_MonoUserDir(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_BuildLogsDirs(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ProjectSlnPath(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ProjectCsProjPath(out godot_string r_dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_DataEditorToolsDir(out godot_string r_dest);
-
- #endregion
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 7ba26939fa..8e4eb031db 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -1,12 +1,13 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Godot;
using Godot.NativeInterop;
using GodotTools.IdeMessaging.Requests;
namespace GodotTools.Internals
{
- public static class Internal
+ internal static class Internal
{
public const string CSharpLanguageType = "CSharpScript";
public const string CSharpLanguageExtension = ".cs";
@@ -15,7 +16,7 @@ namespace GodotTools.Internals
{
get
{
- internal_FullExportTemplatesDir(out godot_string dest);
+ godot_icall_Internal_FullExportTemplatesDir(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
@@ -26,99 +27,161 @@ namespace GodotTools.Internals
public static bool IsMacOSAppBundleInstalled(string bundleId)
{
using godot_string bundleIdIn = Marshaling.mono_string_to_godot(bundleId);
- return internal_IsMacOSAppBundleInstalled(bundleIdIn);
+ return godot_icall_Internal_IsMacOSAppBundleInstalled(bundleIdIn);
}
- public static bool GodotIs32Bits() => internal_GodotIs32Bits();
+ public static bool GodotIs32Bits() => godot_icall_Internal_GodotIs32Bits();
- public static bool GodotIsRealTDouble() => internal_GodotIsRealTDouble();
+ public static bool GodotIsRealTDouble() => godot_icall_Internal_GodotIsRealTDouble();
- public static void GodotMainIteration() => internal_GodotMainIteration();
+ public static void GodotMainIteration() => godot_icall_Internal_GodotMainIteration();
- public static bool IsAssembliesReloadingNeeded() => internal_IsAssembliesReloadingNeeded();
+ public static bool IsAssembliesReloadingNeeded() => godot_icall_Internal_IsAssembliesReloadingNeeded();
- public static void ReloadAssemblies(bool softReload) => internal_ReloadAssemblies(softReload);
+ public static void ReloadAssemblies(bool softReload) => godot_icall_Internal_ReloadAssemblies(softReload);
- public static void EditorDebuggerNodeReloadScripts() => internal_EditorDebuggerNodeReloadScripts();
+ public static void EditorDebuggerNodeReloadScripts() => godot_icall_Internal_EditorDebuggerNodeReloadScripts();
public static bool ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus = true) =>
- internal_ScriptEditorEdit(resource.NativeInstance, line, col, grabFocus);
+ godot_icall_Internal_ScriptEditorEdit(resource.NativeInstance, line, col, grabFocus);
- public static void EditorNodeShowScriptScreen() => internal_EditorNodeShowScriptScreen();
+ public static void EditorNodeShowScriptScreen() => godot_icall_Internal_EditorNodeShowScriptScreen();
public static string MonoWindowsInstallRoot
{
get
{
- internal_MonoWindowsInstallRoot(out godot_string dest);
+ godot_icall_Internal_MonoWindowsInstallRoot(out godot_string dest);
using (dest)
return Marshaling.mono_string_from_godot(dest);
}
}
- public static void EditorRunPlay() => internal_EditorRunPlay();
+ public static void EditorRunPlay() => godot_icall_Internal_EditorRunPlay();
- public static void EditorRunStop() => internal_EditorRunStop();
+ public static void EditorRunStop() => godot_icall_Internal_EditorRunStop();
- public static void ScriptEditorDebugger_ReloadScripts() => internal_ScriptEditorDebugger_ReloadScripts();
+ public static void ScriptEditorDebugger_ReloadScripts() =>
+ godot_icall_Internal_ScriptEditorDebugger_ReloadScripts();
public static unsafe string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind,
string scriptFile)
{
using godot_string scriptFileIn = Marshaling.mono_string_to_godot(scriptFile);
- internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res);
+ godot_icall_Internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res);
using (res)
return Marshaling.PackedStringArray_to_mono_array(&res);
}
#region Internal
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_FullExportTemplatesDir(out godot_string dest);
+ private const string GodotDllName = "__Internal";
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsMacOSAppBundleInstalled(in godot_string bundleId);
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_GodotIs32Bits();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_GodotIsRealTDouble();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_MonoUserDir(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GodotMainIteration();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsAssembliesReloadingNeeded();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_ProjectSlnPath(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ReloadAssemblies(bool softReload);
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_ProjectCsProjPath(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorDebuggerNodeReloadScripts();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string r_dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_ScriptEditorEdit(IntPtr resource, int line, int col, bool grabFocus);
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_EditorProgress_Create(in godot_string task, in godot_string label,
+ int amount, bool canCancel);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorNodeShowScriptScreen();
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_EditorProgress_Dispose(in godot_string task);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_MonoWindowsInstallRoot(out godot_string dest);
+ [DllImport(GodotDllName)]
+ public static extern bool godot_icall_EditorProgress_Step(in godot_string task, in godot_string state, int step,
+ bool forceRefresh);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorRunPlay();
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_FullExportTemplatesDir(out godot_string dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorRunStop();
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_SimplifyGodotPath(in godot_string path, out godot_string dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ScriptEditorDebugger_ReloadScripts();
+ [DllImport(GodotDllName)]
+ private static extern bool godot_icall_Internal_IsMacOSAppBundleInstalled(in godot_string bundleId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_CodeCompletionRequest(int kind, in godot_string scriptFile,
+ [DllImport(GodotDllName)]
+ private static extern bool godot_icall_Internal_GodotIs32Bits();
+
+ [DllImport(GodotDllName)]
+ private static extern bool godot_icall_Internal_GodotIsRealTDouble();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_GodotMainIteration();
+
+ [DllImport(GodotDllName)]
+ private static extern bool godot_icall_Internal_IsAssembliesReloadingNeeded();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_ReloadAssemblies(bool softReload);
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_EditorDebuggerNodeReloadScripts();
+
+ [DllImport(GodotDllName)]
+ private static extern bool godot_icall_Internal_ScriptEditorEdit(IntPtr resource, int line, int col,
+ bool grabFocus);
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_EditorNodeShowScriptScreen();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_MonoWindowsInstallRoot(out godot_string dest);
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_EditorRunPlay();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_EditorRunStop();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts();
+
+ [DllImport(GodotDllName)]
+ private static extern void godot_icall_Internal_CodeCompletionRequest(int kind, in godot_string scriptFile,
out godot_packed_string_array res);
+ [DllImport(GodotDllName)]
+ public static extern float godot_icall_Globals_EditorScale();
+
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_Globals_GlobalDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
+
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_Globals_EditorDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
+
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_Globals_EditorShortcut(in godot_string setting, out godot_variant result);
+
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_Globals_TTR(in godot_string text, out godot_string dest);
+
+ [DllImport(GodotDllName)]
+ public static extern void godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
+
+ [DllImport(GodotDllName)]
+ public static extern bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(in godot_string filePath);
+
#endregion
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
index 05499339b1..4f03d46570 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
@@ -1,8 +1,8 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using Godot;
using GodotTools.Core;
-using JetBrains.Annotations;
namespace GodotTools.Utils
{
@@ -30,7 +30,7 @@ namespace GodotTools.Utils
return childPathNorm.PathStartsWithAlreadyNorm(parentPathNorm);
}
- [CanBeNull]
+ [return: MaybeNull]
public static string LocalizePathWithCaseChecked(string path)
{
string pathNorm = path.NormalizePath() + Path.DirectorySeparatorChar;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index aa100433c9..d9b5942237 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -6,19 +6,13 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
-using JetBrains.Annotations;
+using GodotTools.Internals;
namespace GodotTools.Utils
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static class OS
{
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void GetPlatformName(out godot_string dest);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool UnixFileHasExecutableAccess(in godot_string filePath);
-
public static class Names
{
public const string Windows = "Windows";
@@ -66,7 +60,7 @@ namespace GodotTools.Utils
private static unsafe bool IsOS(string name)
{
- GetPlatformName(out godot_string dest);
+ Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
using (dest)
{
string platformName = Marshaling.mono_string_from_godot(dest);
@@ -76,7 +70,7 @@ namespace GodotTools.Utils
private static unsafe bool IsAnyOS(IEnumerable<string> names)
{
- GetPlatformName(out godot_string dest);
+ Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
using (dest)
{
string platformName = Marshaling.mono_string_from_godot(dest);
@@ -102,14 +96,23 @@ namespace GodotTools.Utils
private static readonly Lazy<bool> _isHTML5 = new Lazy<bool>(() => IsOS(Names.HTML5));
private static readonly Lazy<bool> _isUnixLike = new Lazy<bool>(() => IsAnyOS(UnixLikePlatforms));
+ // TODO SupportedOSPlatformGuard once we target .NET 6
+ // [SupportedOSPlatformGuard("windows")]
public static bool IsWindows => _isWindows.Value || IsUWP;
+ // [SupportedOSPlatformGuard("osx")]
public static bool IsMacOS => _isMacOS.Value;
+ // [SupportedOSPlatformGuard("linux")]
public static bool IsLinuxBSD => _isLinuxBSD.Value;
+ // [SupportedOSPlatformGuard("linux")]
public static bool IsServer => _isServer.Value;
+ // [SupportedOSPlatformGuard("windows")]
public static bool IsUWP => _isUWP.Value;
public static bool IsHaiku => _isHaiku.Value;
+ // [SupportedOSPlatformGuard("android")]
public static bool IsAndroid => _isAndroid.Value;
+ // [SupportedOSPlatformGuard("ios")]
public static bool IsiOS => _isiOS.Value;
+ // [SupportedOSPlatformGuard("browser")]
public static bool IsHTML5 => _isHTML5.Value;
public static bool IsUnixLike => _isUnixLike.Value;
@@ -183,7 +186,7 @@ namespace GodotTools.Utils
.FirstOrDefault(path =>
{
using godot_string pathIn = Marshaling.mono_string_to_godot(path);
- return File.Exists(path) && UnixFileHasExecutableAccess(pathIn);
+ return File.Exists(path) && Internal.godot_icall_Utils_OS_UnixFileHasExecutableAccess(pathIn);
});
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index f70155f4e8..1d4750a2a5 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1143,9 +1143,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
- cs_icalls_content.append("#if NET\n");
cs_icalls_content.append(INDENT1 "[System.Runtime.CompilerServices.SkipLocalsInit]\n");
- cs_icalls_content.append("#endif\n");
cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 "{");
cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
@@ -1252,9 +1250,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
cs_icalls_content.append(INDENT1 "[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
- cs_icalls_content.append("#if NET\n");
cs_icalls_content.append(INDENT1 "[System.Runtime.CompilerServices.SkipLocalsInit]\n");
- cs_icalls_content.append("#endif\n");
cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" OPEN_BLOCK_L1);
cs_icalls_content.append(INDENT2 "internal static ulong godot_api_hash = ");
@@ -1550,20 +1546,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add native constructor static field
output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
-
- << "#if NET\n"
-
<< INDENT2 "private static unsafe readonly delegate* unmanaged<IntPtr> "
<< CS_STATIC_FIELD_NATIVE_CTOR " = " ICALL_CLASSDB_GET_CONSTRUCTOR
- << "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
-
- << "#else\n"
-
- // Get rid of this one once we switch to .NET 5/6
- << INDENT2 "private static readonly IntPtr " CS_STATIC_FIELD_NATIVE_CTOR
- << " = " ICALL_CLASSDB_GET_CONSTRUCTOR "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
-
- << "#endif\n";
+ << "(" BINDINGS_NATIVE_NAME_FIELD ");\n";
}
if (is_derived_type) {
@@ -1576,20 +1561,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// The engine will initialize the pointer field of the managed side before calling the constructor
// This is why we only allocate a new native object from the constructor if the pointer field is not set
output << INDENT3 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" OPEN_BLOCK_L3
-
- << "#if NET\n"
-
<< INDENT4 "unsafe\n" INDENT4 OPEN_BLOCK
<< INDENT5 BINDINGS_PTR_FIELD " = " CS_STATIC_FIELD_NATIVE_CTOR "();\n"
<< CLOSE_BLOCK_L4
-
- << "#else\n"
-
- // Get rid of this one once we switch to .NET 5/6
- << INDENT4 BINDINGS_PTR_FIELD " = _gd__invoke_class_constructor(" CS_STATIC_FIELD_NATIVE_CTOR ");\n"
-
- << "#endif\n"
-
<< INDENT4 C_METHOD_TIE_MANAGED_TO_UNMANAGED "(this, " BINDINGS_PTR_FIELD ", "
<< BINDINGS_NATIVE_NAME_FIELD << ", refCounted: " << (itype.is_ref_counted ? "true" : "false")
<< ", ((object)this).GetType(), _cachedType);\n" CLOSE_BLOCK_L3
@@ -3337,6 +3311,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// bool
itype = TypeInterface::create_value_type(String("bool"));
+ itype.cs_in = "%s.ToGodotBool()";
+ itype.cs_out = "%5return %0(%1).ToBool();";
itype.c_type = "godot_bool";
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.c_type;
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index dd0d94121d..5b1bc8ccbf 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -49,23 +49,40 @@
#include "../godotsharp_dirs.h"
#include "../utils/macos_utils.h"
#include "code_completion.h"
-#include "godotsharp_export.h"
#include "../interop_types.h"
-void godot_icall_GodotSharpDirs_ResMetadataDir(godot_string *r_dest) {
+#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
+
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_ResMetadataDir(godot_string *r_dest) {
memnew_placement(r_dest, String(GodotSharpDirs::get_res_metadata_dir()));
}
-void godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(godot_string *r_dest) {
memnew_placement(r_dest, String(GodotSharpDirs::get_res_temp_assemblies_base_dir()));
}
-void godot_icall_GodotSharpDirs_MonoUserDir(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_MonoUserDir(godot_string *r_dest) {
memnew_placement(r_dest, String(GodotSharpDirs::get_mono_user_dir()));
}
-void godot_icall_GodotSharpDirs_BuildLogsDirs(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_BuildLogsDirs(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
memnew_placement(r_dest, String(GodotSharpDirs::get_build_logs_dir()));
#else
@@ -73,7 +90,7 @@ void godot_icall_GodotSharpDirs_BuildLogsDirs(godot_string *r_dest) {
#endif
}
-void godot_icall_GodotSharpDirs_ProjectSlnPath(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_ProjectSlnPath(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
memnew_placement(r_dest, String(GodotSharpDirs::get_project_sln_path()));
#else
@@ -81,7 +98,7 @@ void godot_icall_GodotSharpDirs_ProjectSlnPath(godot_string *r_dest) {
#endif
}
-void godot_icall_GodotSharpDirs_ProjectCsProjPath(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_ProjectCsProjPath(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
memnew_placement(r_dest, String(GodotSharpDirs::get_project_csproj_path()));
#else
@@ -89,7 +106,7 @@ void godot_icall_GodotSharpDirs_ProjectCsProjPath(godot_string *r_dest) {
#endif
}
-void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
memnew_placement(r_dest, String(GodotSharpDirs::get_data_editor_tools_dir()));
#else
@@ -97,39 +114,29 @@ void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
#endif
}
-void godot_icall_EditorProgress_Create(const godot_string *p_task, const godot_string *p_label, int32_t p_amount, bool p_can_cancel) {
+GD_PINVOKE_EXPORT void godot_icall_EditorProgress_Create(const godot_string *p_task, const godot_string *p_label, int32_t p_amount, bool p_can_cancel) {
String task = *reinterpret_cast<const String *>(p_task);
String label = *reinterpret_cast<const String *>(p_label);
EditorNode::progress_add_task(task, label, p_amount, (bool)p_can_cancel);
}
-void godot_icall_EditorProgress_Dispose(const godot_string *p_task) {
+GD_PINVOKE_EXPORT void godot_icall_EditorProgress_Dispose(const godot_string *p_task) {
String task = *reinterpret_cast<const String *>(p_task);
EditorNode::progress_end_task(task);
}
-bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_string *p_state, int32_t p_step, bool p_force_refresh) {
+GD_PINVOKE_EXPORT bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_string *p_state, int32_t p_step, bool p_force_refresh) {
String task = *reinterpret_cast<const String *>(p_task);
String state = *reinterpret_cast<const String *>(p_state);
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(const godot_dictionary *p_initial_assemblies,
- const godot_string *p_build_config, const godot_string *p_custom_bcl_dir, godot_dictionary *r_assembly_dependencies) {
- Dictionary initial_dependencies = *reinterpret_cast<const Dictionary *>(p_initial_assemblies);
- String build_config = *reinterpret_cast<const String *>(p_build_config);
- String custom_bcl_dir = *reinterpret_cast<const String *>(p_custom_bcl_dir);
- Dictionary assembly_dependencies = *reinterpret_cast<Dictionary *>(r_assembly_dependencies);
-
- return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, assembly_dependencies);
-}
-
-void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
memnew_placement(r_dest, String(full_templates_dir));
}
-bool godot_icall_Internal_IsMacOSAppBundleInstalled(const godot_string *p_bundle_id) {
+GD_PINVOKE_EXPORT bool godot_icall_Internal_IsMacOSAppBundleInstalled(const godot_string *p_bundle_id) {
#ifdef MACOS_ENABLED
String bundle_id = *reinterpret_cast<const String *>(p_bundle_id);
return (bool)macos_is_app_bundle_installed(bundle_id);
@@ -139,11 +146,11 @@ bool godot_icall_Internal_IsMacOSAppBundleInstalled(const godot_string *p_bundle
#endif
}
-bool godot_icall_Internal_GodotIs32Bits() {
+GD_PINVOKE_EXPORT bool godot_icall_Internal_GodotIs32Bits() {
return sizeof(void *) == 4;
}
-bool godot_icall_Internal_GodotIsRealTDouble() {
+GD_PINVOKE_EXPORT bool godot_icall_Internal_GodotIsRealTDouble() {
#ifdef REAL_T_IS_DOUBLE
return (bool)true;
#else
@@ -151,11 +158,11 @@ bool godot_icall_Internal_GodotIsRealTDouble() {
#endif
}
-void godot_icall_Internal_GodotMainIteration() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_GodotMainIteration() {
Main::iteration();
}
-bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
+GD_PINVOKE_EXPORT bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
#ifdef GD_MONO_HOT_RELOAD
return (bool)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
#else
@@ -163,26 +170,26 @@ bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
#endif
}
-void godot_icall_Internal_ReloadAssemblies(bool p_soft_reload) {
+GD_PINVOKE_EXPORT void godot_icall_Internal_ReloadAssemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
#endif
}
-void godot_icall_Internal_EditorDebuggerNodeReloadScripts() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_EditorDebuggerNodeReloadScripts() {
EditorDebuggerNode::get_singleton()->reload_scripts();
}
-bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, int32_t p_col, bool p_grab_focus) {
+GD_PINVOKE_EXPORT bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, int32_t p_col, bool p_grab_focus) {
Ref<Resource> resource = p_resource;
return (bool)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
}
-void godot_icall_Internal_EditorNodeShowScriptScreen() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_EditorNodeShowScriptScreen() {
EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
}
-void godot_icall_Internal_MonoWindowsInstallRoot(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_Internal_MonoWindowsInstallRoot(godot_string *r_dest) {
#ifdef WINDOWS_ENABLED
String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
memnew_placement(r_dest, String(install_root_dir));
@@ -192,62 +199,62 @@ void godot_icall_Internal_MonoWindowsInstallRoot(godot_string *r_dest) {
#endif
}
-void godot_icall_Internal_EditorRunPlay() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_EditorRunPlay() {
EditorNode::get_singleton()->run_play();
}
-void godot_icall_Internal_EditorRunStop() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_EditorRunStop() {
EditorNode::get_singleton()->run_stop();
}
-void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
+GD_PINVOKE_EXPORT void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
if (ed) {
ed->reload_scripts();
}
}
-void godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, const godot_string *p_script_file, godot_packed_array *r_ret) {
+GD_PINVOKE_EXPORT void godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, const godot_string *p_script_file, godot_packed_array *r_ret) {
String script_file = *reinterpret_cast<const String *>(p_script_file);
PackedStringArray suggestions = gdmono::get_code_completion((gdmono::CompletionKind)p_kind, script_file);
memnew_placement(r_ret, PackedStringArray(suggestions));
}
-float godot_icall_Globals_EditorScale() {
+GD_PINVOKE_EXPORT float godot_icall_Globals_EditorScale() {
return EDSCALE;
}
-void godot_icall_Globals_GlobalDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+GD_PINVOKE_EXPORT void godot_icall_Globals_GlobalDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
String setting = *reinterpret_cast<const String *>(p_setting);
Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
memnew_placement(r_result, Variant(result));
}
-void godot_icall_Globals_EditorDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+GD_PINVOKE_EXPORT void godot_icall_Globals_EditorDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
String setting = *reinterpret_cast<const String *>(p_setting);
Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
memnew_placement(r_result, Variant(result));
}
-void godot_icall_Globals_EditorShortcut(const godot_string *p_setting, godot_variant *r_result) {
+GD_PINVOKE_EXPORT void godot_icall_Globals_EditorShortcut(const godot_string *p_setting, godot_variant *r_result) {
String setting = *reinterpret_cast<const String *>(p_setting);
Ref<Shortcut> result = ED_GET_SHORTCUT(setting);
memnew_placement(r_result, Variant(result));
}
-void godot_icall_Globals_TTR(const godot_string *p_text, godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_Globals_TTR(const godot_string *p_text, godot_string *r_dest) {
String text = *reinterpret_cast<const String *>(p_text);
memnew_placement(r_dest, String(TTR(text)));
}
-void godot_icall_Utils_OS_GetPlatformName(godot_string *r_dest) {
+GD_PINVOKE_EXPORT void godot_icall_Utils_OS_GetPlatformName(godot_string *r_dest) {
String os_name = OS::get_singleton()->get_name();
memnew_placement(r_dest, String(os_name));
}
-bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(const godot_string *p_file_path) {
+GD_PINVOKE_EXPORT bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(const godot_string *p_file_path) {
#ifdef UNIX_ENABLED
String file_path = *reinterpret_cast<const String *>(p_file_path);
return access(file_path.utf8().get_data(), X_OK) == 0;
@@ -256,49 +263,41 @@ bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(const godot_string *p_file
#endif
}
-void register_editor_internal_calls() {
- // GodotSharpDirs
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
-
- // EditorProgress
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
-
- // ExportPlugin
- GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
-
- // Internals
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullExportTemplatesDir", godot_icall_Internal_FullExportTemplatesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsMacOSAppBundleInstalled", godot_icall_Internal_IsMacOSAppBundleInstalled);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", godot_icall_Internal_CodeCompletionRequest);
-
- // Globals
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorShortcut", godot_icall_Globals_EditorShortcut);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
-
- // Utils.OS
- GDMonoUtils::add_internal_call("GodotTools.Utils.OS::GetPlatformName", godot_icall_Utils_OS_GetPlatformName);
- GDMonoUtils::add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", godot_icall_Utils_OS_UnixFileHasExecutableAccess);
+#ifdef __cplusplus
}
+#endif
+
+void *godotsharp_editor_pinvoke_funcs[32] = {
+ (void *)godot_icall_GodotSharpDirs_ResMetadataDir,
+ (void *)godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir,
+ (void *)godot_icall_GodotSharpDirs_MonoUserDir,
+ (void *)godot_icall_GodotSharpDirs_BuildLogsDirs,
+ (void *)godot_icall_GodotSharpDirs_ProjectSlnPath,
+ (void *)godot_icall_GodotSharpDirs_ProjectCsProjPath,
+ (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir,
+ (void *)godot_icall_EditorProgress_Create,
+ (void *)godot_icall_EditorProgress_Dispose,
+ (void *)godot_icall_EditorProgress_Step,
+ (void *)godot_icall_Internal_FullExportTemplatesDir,
+ (void *)godot_icall_Internal_IsMacOSAppBundleInstalled,
+ (void *)godot_icall_Internal_GodotIs32Bits,
+ (void *)godot_icall_Internal_GodotIsRealTDouble,
+ (void *)godot_icall_Internal_GodotMainIteration,
+ (void *)godot_icall_Internal_IsAssembliesReloadingNeeded,
+ (void *)godot_icall_Internal_ReloadAssemblies,
+ (void *)godot_icall_Internal_EditorDebuggerNodeReloadScripts,
+ (void *)godot_icall_Internal_ScriptEditorEdit,
+ (void *)godot_icall_Internal_EditorNodeShowScriptScreen,
+ (void *)godot_icall_Internal_MonoWindowsInstallRoot,
+ (void *)godot_icall_Internal_EditorRunPlay,
+ (void *)godot_icall_Internal_EditorRunStop,
+ (void *)godot_icall_Internal_ScriptEditorDebugger_ReloadScripts,
+ (void *)godot_icall_Internal_CodeCompletionRequest,
+ (void *)godot_icall_Globals_EditorScale,
+ (void *)godot_icall_Globals_GlobalDef,
+ (void *)godot_icall_Globals_EditorDef,
+ (void *)godot_icall_Globals_EditorShortcut,
+ (void *)godot_icall_Globals_TTR,
+ (void *)godot_icall_Utils_OS_GetPlatformName,
+ (void *)godot_icall_Utils_OS_UnixFileHasExecutableAccess,
+};
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
deleted file mode 100644
index d065aa30e5..0000000000
--- a/modules/mono/editor/godotsharp_export.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*************************************************************************/
-/* godotsharp_export.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "godotsharp_export.h"
-
-#include <mono/metadata/image.h>
-
-#include "core/config/project_settings.h"
-#include "core/io/file_access_pack.h"
-#include "core/os/os.h"
-
-#include "../mono_gd/gd_mono.h"
-#include "../mono_gd/gd_mono_assembly.h"
-#include "../mono_gd/gd_mono_cache.h"
-#include "../utils/macros.h"
-
-namespace GodotSharpExport {
-
-MonoAssemblyName *new_mono_assembly_name() {
- // Mono has no public API to create an empty MonoAssemblyName and the struct is private.
- // As such the only way to create it is with a stub name and then clear it.
-
- MonoAssemblyName *aname = mono_assembly_name_new("stub");
- CRASH_COND(aname == nullptr);
- mono_assembly_name_free(aname); // Frees the string fields, not the struct
- return aname;
-}
-
-struct AssemblyRefInfo {
- String name;
- uint16_t major = 0;
- uint16_t minor = 0;
- uint16_t build = 0;
- uint16_t revision = 0;
-};
-
-AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {
- const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
-
- uint32_t cols[MONO_ASSEMBLYREF_SIZE];
-
- mono_metadata_decode_row(table_info, index, cols, MONO_ASSEMBLYREF_SIZE);
-
- return {
- String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME])),
- (uint16_t)cols[MONO_ASSEMBLYREF_MAJOR_VERSION],
- (uint16_t)cols[MONO_ASSEMBLYREF_MINOR_VERSION],
- (uint16_t)cols[MONO_ASSEMBLYREF_BUILD_NUMBER],
- (uint16_t)cols[MONO_ASSEMBLYREF_REV_NUMBER]
- };
-}
-
-Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *reusable_aname, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) {
- MonoImage *image = p_assembly->get_image();
-
- for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
- AssemblyRefInfo ref_info = get_assemblyref_name(image, i);
-
- const String &ref_name = ref_info.name;
-
- if (r_assembly_dependencies.has(ref_name)) {
- continue;
- }
-
- mono_assembly_get_assemblyref(image, i, reusable_aname);
-
- GDMonoAssembly *ref_assembly = nullptr;
- if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, p_search_dirs)) {
- ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
- }
-
- r_assembly_dependencies[ref_name] = ref_assembly->get_path();
-
- Error err = get_assembly_dependencies(ref_assembly, reusable_aname, p_search_dirs, r_assembly_dependencies);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");
- }
-
- return OK;
-}
-
-Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
- const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_assembly_dependencies) {
- MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport");
- ERR_FAIL_NULL_V(export_domain, FAILED);
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
-
- _GDMONO_SCOPE_DOMAIN_(export_domain);
-
- Vector<String> search_dirs;
- GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir);
-
- if (p_custom_bcl_dir.length()) {
- // Only one mscorlib can be loaded. We need this workaround to make sure we get it from the right BCL directory.
- r_assembly_dependencies["mscorlib"] = p_custom_bcl_dir.plus_file("mscorlib.dll").simplify_path();
- }
-
- for (const Variant *key = p_initial_assemblies.next(); key; key = p_initial_assemblies.next(key)) {
- String assembly_name = *key;
- String assembly_path = p_initial_assemblies[*key];
-
- GDMonoAssembly *assembly = nullptr;
- bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly);
-
- ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
-
- MonoAssemblyName *reusable_aname = new_mono_assembly_name();
- SCOPE_EXIT { mono_free(reusable_aname); };
-
- Error err = get_assembly_dependencies(assembly, reusable_aname, search_dirs, r_assembly_dependencies);
- if (err != OK) {
- return err;
- }
- }
-
- return OK;
-}
-} // namespace GodotSharpExport
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
deleted file mode 100644
index 20d6f6fe73..0000000000
--- a/modules/mono/editor/godotsharp_export.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*************************************************************************/
-/* godotsharp_export.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GODOTSHARP_EXPORT_H
-#define GODOTSHARP_EXPORT_H
-
-#include "core/error/error_list.h"
-#include "core/string/ustring.h"
-#include "core/variant/dictionary.h"
-
-namespace GodotSharpExport {
-
-Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
- const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies);
-} // namespace GodotSharpExport
-
-#endif // GODOTSHARP_EXPORT_H
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
new file mode 100644
index 0000000000..38cd2ece4e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <LangVersion>9</LangVersion>
+ <Nullable>enable</Nullable>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+
+ <!-- To generate the .runtimeconfig.json file-->
+ <EnableDynamicLoading>true</EnableDynamicLoading>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\GodotSharp\GodotSharp.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
new file mode 100644
index 0000000000..9f938373c4
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using Godot.NativeInterop;
+
+namespace GodotPlugins
+{
+ public static class Main
+ {
+ private static readonly List<AssemblyName> SharedAssemblies = new();
+ private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
+ private static Assembly? _editorApiAssembly;
+
+ private static readonly AssemblyLoadContext MainLoadContext =
+ AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
+ AssemblyLoadContext.Default;
+
+ // Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later.
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Initialize(godot_bool editorHint,
+ PluginsCallbacks* pluginsCallbacks, Godot.Bridge.ManagedCallbacks* managedCallbacks)
+ {
+ try
+ {
+ SharedAssemblies.Add(CoreApiAssembly.GetName());
+
+ if (editorHint.ToBool())
+ {
+ _editorApiAssembly = Assembly.Load("GodotSharpEditor");
+ SharedAssemblies.Add(_editorApiAssembly.GetName());
+ }
+
+ NativeLibrary.SetDllImportResolver(CoreApiAssembly, OnResolveDllImport);
+
+ *pluginsCallbacks = new()
+ {
+ LoadProjectAssemblyCallback = &LoadProjectAssembly,
+ LoadToolsAssemblyCallback = &LoadToolsAssembly,
+ };
+
+ *managedCallbacks = Godot.Bridge.ManagedCallbacks.Create();
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ *pluginsCallbacks = default;
+ *managedCallbacks = default;
+ return false.ToGodotBool();
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PluginsCallbacks
+ {
+ public unsafe delegate* unmanaged<char*, godot_bool> LoadProjectAssemblyCallback;
+ public unsafe delegate* unmanaged<char*, IntPtr> LoadToolsAssemblyCallback;
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath)
+ {
+ try
+ {
+ string assemblyPath = new(nAssemblyPath);
+
+ var assembly = LoadPlugin(assemblyPath);
+
+ var method = CoreApiAssembly.GetType("Godot.Bridge.ScriptManagerBridge")?
+ .GetMethod("LookupScriptsInAssembly",
+ BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (method == null)
+ {
+ throw new MissingMethodException("Godot.Bridge.ScriptManagerBridge",
+ "LookupScriptsInAssembly");
+ }
+
+ method.Invoke(null, new object[] { assembly });
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return false.ToGodotBool();
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath)
+ {
+ try
+ {
+ string assemblyPath = new(nAssemblyPath);
+
+ if (_editorApiAssembly == null)
+ throw new InvalidOperationException("The Godot editor API assembly is not loaded");
+
+ var assembly = LoadPlugin(assemblyPath);
+
+ NativeLibrary.SetDllImportResolver(assembly, OnResolveDllImport);
+
+ var method = assembly.GetType("GodotTools.GodotSharpEditor")?
+ .GetMethod("InternalCreateInstance",
+ BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (method == null)
+ {
+ throw new MissingMethodException("GodotTools.GodotSharpEditor",
+ "InternalCreateInstance");
+ }
+
+ return (IntPtr?)method.Invoke(null, null) ?? IntPtr.Zero;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return IntPtr.Zero;
+ }
+ }
+
+ private static Assembly LoadPlugin(string assemblyPath)
+ {
+ string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
+
+ var sharedAssemblies = new List<string>();
+
+ foreach (var sharedAssembly in SharedAssemblies)
+ {
+ string? sharedAssemblyName = sharedAssembly.Name;
+ if (sharedAssemblyName != null)
+ sharedAssemblies.Add(sharedAssemblyName);
+ }
+
+ var loadContext = new PluginLoadContext(assemblyPath, sharedAssemblies, MainLoadContext);
+ return loadContext.LoadFromAssemblyName(new AssemblyName(assemblyName));
+ }
+
+ public static IntPtr OnResolveDllImport(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (libraryName == "__Internal")
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return Win32.GetModuleHandle(IntPtr.Zero);
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return Linux.dlopen(IntPtr.Zero, Linux.RTLD_LAZY);
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return MacOS.dlopen(IntPtr.Zero, MacOS.RTLD_LAZY);
+ }
+ }
+
+ return IntPtr.Zero;
+ }
+
+ // ReSharper disable InconsistentNaming
+ private static class MacOS
+ {
+ private const string SystemLibrary = "/usr/lib/libSystem.dylib";
+
+ public const int RTLD_LAZY = 1;
+
+ [DllImport(SystemLibrary)]
+ public static extern IntPtr dlopen(IntPtr path, int mode);
+ }
+
+ private static class Linux
+ {
+ // libdl.so was resulting in DllNotFoundException, for some reason...
+ // libcoreclr.so should work with both CoreCLR and the .NET Core version of Mono.
+ private const string SystemLibrary = "libcoreclr.so";
+
+ public const int RTLD_LAZY = 1;
+
+ [DllImport(SystemLibrary)]
+ public static extern IntPtr dlopen(IntPtr path, int mode);
+ }
+
+ private static class Win32
+ {
+ private const string SystemLibrary = "Kernel32.dll";
+
+ [DllImport(SystemLibrary)]
+ public static extern IntPtr GetModuleHandle(IntPtr lpModuleName);
+ }
+ // ReSharper restore InconsistentNaming
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
new file mode 100644
index 0000000000..1b969716aa
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace GodotPlugins
+{
+ public class PluginLoadContext : AssemblyLoadContext
+ {
+ private readonly AssemblyDependencyResolver _resolver;
+ private readonly ICollection<string> _sharedAssemblies;
+ private readonly AssemblyLoadContext _mainLoadContext;
+
+ public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
+ AssemblyLoadContext mainLoadContext)
+ {
+ Console.WriteLine(pluginPath);
+ Console.Out.Flush();
+ _resolver = new AssemblyDependencyResolver(pluginPath);
+ _sharedAssemblies = sharedAssemblies;
+ _mainLoadContext = mainLoadContext;
+ }
+
+ protected override Assembly? Load(AssemblyName assemblyName)
+ {
+ if (assemblyName.Name == null)
+ return null;
+
+ if (_sharedAssemblies.Contains(assemblyName.Name))
+ return _mainLoadContext.LoadFromAssemblyName(assemblyName);
+
+ string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
+ if (assemblyPath != null)
+ {
+ // Load in memory to prevent locking the file
+ using var assemblyFile = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ string pdbPath = Path.ChangeExtension(assemblyPath, ".pdb");
+
+ if (File.Exists(pdbPath))
+ {
+ using var pdbFile = File.Open(pdbPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ return LoadFromStream(assemblyFile, pdbFile);
+ }
+
+ return LoadFromStream(assemblyFile);
+ }
+
+ return null;
+ }
+
+ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
+ {
+ string? libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
+ if (libraryPath != null)
+ return LoadUnmanagedDllFromPath(libraryPath);
+
+ return IntPtr.Zero;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln b/modules/mono/glue/GodotSharp/GodotSharp.sln
index 4896d0a07d..fc4e6e91f1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp.sln
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln
@@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "GodotSharp\Go
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpEditor", "GodotSharpEditor\GodotSharpEditor.csproj", "{8FBEC238-D944-4074-8548-B3B524305905}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotPlugins", "GodotPlugins\GodotPlugins.csproj", "{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +20,9 @@ Global
{8FBEC238-D944-4074-8548-B3B524305905}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.Build.0 = Release|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index a2a97e0a3e..2aa2ece803 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -95,7 +95,7 @@ namespace Godot.Collections
public Array Duplicate(bool deep = false)
{
godot_array newArray;
- NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep, out newArray);
+ NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep.ToGodotBool(), out newArray);
return CreateTakingOwnershipOfDisposableValue(newArray);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
index 16fde2a900..db27989bdb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -6,118 +6,167 @@ namespace Godot.Bridge
{
internal static class CSharpInstanceBridge
{
- private static unsafe void Call(IntPtr godotObjectGCHandle, godot_string_name* method,
- godot_variant** args, int argCount, godot_variant_call_error* ref_callError, godot_variant* r_ret)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Call(IntPtr godotObjectGCHandle, godot_string_name* method,
+ godot_variant** args, int argCount, godot_variant_call_error* refCallError, godot_variant* ret)
{
- // Performance is not critical here as this will be replaced with source generators.
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
-
- if (godotObject == null)
+ try
{
- *r_ret = default;
- (*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
- return;
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ {
+ *ret = default;
+ (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
+ return false.ToGodotBool();
+ }
+
+ using godot_string dest = default;
+ NativeFuncs.godotsharp_string_name_as_string(&dest, method);
+ string methodStr = Marshaling.mono_string_from_godot(dest);
+
+ bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant retValue);
+
+ if (!methodInvoked)
+ {
+ *ret = default;
+ // This is important, as it tells Object::call that no method was called.
+ // Otherwise, it would prevent Object::call from calling native methods.
+ (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
+ return false.ToGodotBool();
+ }
+
+ *ret = retValue;
+ return true.ToGodotBool();
}
-
- using godot_string dest = default;
- NativeFuncs.godotsharp_string_name_as_string(&dest, method);
- string methodStr = Marshaling.mono_string_from_godot(dest);
-
- bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant outRet);
-
- if (!methodInvoked)
+ catch (Exception e)
{
- *r_ret = default;
- // This is important, as it tells Object::call that no method was called.
- // Otherwise, it would prevent Object::call from calling native methods.
- (*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
- return;
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *ret = default;
+ return false.ToGodotBool();
}
-
- *r_ret = outRet;
}
- private static unsafe bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
{
- // Performance is not critical here as this will be replaced with source generators.
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
- if (godotObject == null)
- throw new InvalidOperationException();
+ if (godotObject == null)
+ throw new InvalidOperationException();
- var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_string_name_new_copy(name));
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(name));
- if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
- return true;
+ if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
+ return true.ToGodotBool();
- object valueManaged = Marshaling.variant_to_mono_object(value);
+ object valueManaged = Marshaling.variant_to_mono_object(value);
- return godotObject._Set(nameManaged, valueManaged);
+ return godotObject._Set(nameManaged, valueManaged).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ return false.ToGodotBool();
+ }
}
- private static unsafe bool Get(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* r_retValue)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Get(IntPtr godotObjectGCHandle, godot_string_name* name,
+ godot_variant* outRet)
{
- // Performance is not critical here as this will be replaced with source generators.
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
- if (godotObject == null)
- throw new InvalidOperationException();
+ if (godotObject == null)
+ throw new InvalidOperationException();
- var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
- NativeFuncs.godotsharp_string_name_new_copy(name));
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(name));
- if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
- out godot_variant outRet))
- {
- *r_retValue = outRet;
- return true;
- }
+ if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
+ out godot_variant outRetValue))
+ {
+ *outRet = outRetValue;
+ return true.ToGodotBool();
+ }
- object ret = godotObject._Get(nameManaged);
+ object ret = godotObject._Get(nameManaged);
- if (ret == null)
+ if (ret == null)
+ {
+ *outRet = default;
+ return false.ToGodotBool();
+ }
+
+ *outRet = Marshaling.mono_object_to_variant(ret);
+ return true.ToGodotBool();
+ }
+ catch (Exception e)
{
- *r_retValue = default;
- return false;
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *outRet = default;
+ return false.ToGodotBool();
}
-
- *r_retValue = Marshaling.mono_object_to_variant(ret);
- return true;
}
- private static void CallDispose(IntPtr godotObjectGCHandle, bool okIfNull)
+ [UnmanagedCallersOnly]
+ internal static void CallDispose(IntPtr godotObjectGCHandle, godot_bool okIfNull)
{
- var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
- if (okIfNull)
- godotObject?.Dispose();
- else
- godotObject!.Dispose();
+ if (okIfNull.ToBool())
+ godotObject?.Dispose();
+ else
+ godotObject!.Dispose();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ }
}
- private static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* r_res, bool* r_valid)
+ [UnmanagedCallersOnly]
+ internal static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* outRes, godot_bool* outValid)
{
- var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
-
- if (self == null)
+ try
{
- *r_res = default;
- *r_valid = false;
- return;
+ var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (self == null)
+ {
+ *outRes = default;
+ *outValid = false.ToGodotBool();
+ return;
+ }
+
+ var resultStr = self.ToString();
+
+ if (resultStr == null)
+ {
+ *outRes = default;
+ *outValid = false.ToGodotBool();
+ return;
+ }
+
+ *outRes = Marshaling.mono_string_to_godot(resultStr);
+ *outValid = true.ToGodotBool();
}
-
- var resultStr = self.ToString();
-
- if (resultStr == null)
+ catch (Exception e)
{
- *r_res = default;
- *r_valid = false;
- return;
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *outRes = default;
+ *outValid = false.ToGodotBool();
}
-
- *r_res = Marshaling.mono_string_to_godot(resultStr);
- *r_valid = true;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
index aa9e434b07..c6f2e8f77d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
@@ -1,11 +1,22 @@
using System;
using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot.Bridge
{
internal static class GCHandleBridge
{
- private static void FreeGCHandle(IntPtr gcHandlePtr)
- => GCHandle.FromIntPtr(gcHandlePtr).Free();
+ [UnmanagedCallersOnly]
+ internal static void FreeGCHandle(IntPtr gcHandlePtr)
+ {
+ try
+ {
+ GCHandle.FromIntPtr(gcHandlePtr).Free();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
new file mode 100644
index 0000000000..1d19376cdd
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct ManagedCallbacks
+ {
+ // @formatter:off
+ public delegate* unmanaged<IntPtr, godot_variant**, int, godot_bool*, void> SignalAwaiter_SignalCallback;
+ public delegate* unmanaged<IntPtr, godot_variant**, uint, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
+ public delegate* unmanaged<void> ScriptManagerBridge_FrameCallback;
+ public delegate* unmanaged<godot_string_name*, IntPtr, IntPtr> ScriptManagerBridge_CreateManagedForGodotObjectBinding;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_variant**, int, godot_bool> ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
+ public delegate* unmanaged<IntPtr, godot_string_name*, void> ScriptManagerBridge_GetScriptNativeName;
+ public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagerBridge_SetGodotObjectPtr;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_bool*, void> ScriptManagerBridge_RaiseEventSignal;
+ public delegate* unmanaged<IntPtr, godot_dictionary*, void> ScriptManagerBridge_GetScriptSignalList;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_HasScriptSignal;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool, godot_bool> ScriptManagerBridge_HasMethodUnknownParams;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
+ public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
+ public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, void> ScriptManagerBridge_UpdateScriptClassInfo;
+ public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Get;
+ public delegate* unmanaged<IntPtr, godot_bool, void> CSharpInstanceBridge_CallDispose;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, void> CSharpInstanceBridge_CallToString;
+ public delegate* unmanaged<IntPtr, void> GCHandleBridge_FreeGCHandle;
+ public delegate* unmanaged<void> DebuggingUtils_InstallTraceListener;
+ public delegate* unmanaged<void> Dispatcher_InitializeDefaultGodotTaskScheduler;
+ // @formatter:on
+
+ public static ManagedCallbacks Create()
+ {
+ return new()
+ {
+ // @formatter:off
+ SignalAwaiter_SignalCallback = &SignalAwaiter.SignalCallback,
+ DelegateUtils_InvokeWithVariantArgs = &DelegateUtils.InvokeWithVariantArgs,
+ DelegateUtils_DelegateEquals = &DelegateUtils.DelegateEquals,
+ ScriptManagerBridge_FrameCallback = &ScriptManagerBridge.FrameCallback,
+ ScriptManagerBridge_CreateManagedForGodotObjectBinding = &ScriptManagerBridge.CreateManagedForGodotObjectBinding,
+ ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = &ScriptManagerBridge.CreateManagedForGodotObjectScriptInstance,
+ ScriptManagerBridge_GetScriptNativeName = &ScriptManagerBridge.GetScriptNativeName,
+ ScriptManagerBridge_SetGodotObjectPtr = &ScriptManagerBridge.SetGodotObjectPtr,
+ ScriptManagerBridge_RaiseEventSignal = &ScriptManagerBridge.RaiseEventSignal,
+ ScriptManagerBridge_GetScriptSignalList = &ScriptManagerBridge.GetScriptSignalList,
+ ScriptManagerBridge_HasScriptSignal = &ScriptManagerBridge.HasScriptSignal,
+ ScriptManagerBridge_HasMethodUnknownParams = &ScriptManagerBridge.HasMethodUnknownParams,
+ ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
+ ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
+ ScriptManagerBridge_RemoveScriptBridge = &ScriptManagerBridge.RemoveScriptBridge,
+ ScriptManagerBridge_UpdateScriptClassInfo = &ScriptManagerBridge.UpdateScriptClassInfo,
+ ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
+ CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call,
+ CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set,
+ CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get,
+ CSharpInstanceBridge_CallDispose = &CSharpInstanceBridge.CallDispose,
+ CSharpInstanceBridge_CallToString = &CSharpInstanceBridge.CallToString,
+ GCHandleBridge_FreeGCHandle = &GCHandleBridge.FreeGCHandle,
+ DebuggingUtils_InstallTraceListener = &DebuggingUtils.InstallTraceListener,
+ Dispatcher_InitializeDefaultGodotTaskScheduler = &Dispatcher.InitializeDefaultGodotTaskScheduler,
+ // @formatter:on
+ };
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index a39da68a02..9655887e52 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -27,99 +27,150 @@ namespace Godot.Bridge
}
};
+ [UnmanagedCallersOnly]
internal static void FrameCallback()
{
- Dispatcher.DefaultGodotTaskScheduler?.Activate();
+ try
+ {
+ Dispatcher.DefaultGodotTaskScheduler?.Activate();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
}
+ [UnmanagedCallersOnly]
internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName,
IntPtr godotObject)
{
- Type nativeType = TypeGetProxyClass(nativeTypeName);
- var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
+ try
+ {
+ Type nativeType = TypeGetProxyClass(nativeTypeName);
+ var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
- obj.NativePtr = godotObject;
+ obj.NativePtr = godotObject;
- var ctor = nativeType.GetConstructor(
- BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
- null, Type.EmptyTypes, null);
- _ = ctor!.Invoke(obj, null);
+ var ctor = nativeType.GetConstructor(
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ null, Type.EmptyTypes, null);
+ _ = ctor!.Invoke(obj, null);
- return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
+ return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ return IntPtr.Zero;
+ }
}
- internal static unsafe void CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr, IntPtr godotObject,
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr,
+ IntPtr godotObject,
godot_variant** args, int argCount)
{
- // Performance is not critical here as this will be replaced with source generators.
- Type scriptType = _scriptBridgeMap[scriptPtr];
- var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type scriptType = _scriptBridgeMap[scriptPtr];
+ var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
- obj.NativePtr = godotObject;
+ obj.NativePtr = godotObject;
- var ctor = scriptType
- .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
- .Where(c => c.GetParameters().Length == argCount)
- .FirstOrDefault();
+ var ctor = scriptType
+ .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ .Where(c => c.GetParameters().Length == argCount)
+ .FirstOrDefault();
- if (ctor == null)
- {
- if (argCount == 0)
- {
- throw new MissingMemberException(
- $"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
- }
- else
+ if (ctor == null)
{
- throw new MissingMemberException(
- $"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
+ if (argCount == 0)
+ {
+ throw new MissingMemberException(
+ $"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
+ }
+ else
+ {
+ throw new MissingMemberException(
+ $"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
+ }
}
- }
- var parameters = ctor.GetParameters();
- int paramCount = parameters.Length;
+ var parameters = ctor.GetParameters();
+ int paramCount = parameters.Length;
- object[] invokeParams = new object[paramCount];
+ object[] invokeParams = new object[paramCount];
- for (int i = 0; i < paramCount; i++)
+ for (int i = 0; i < paramCount; i++)
+ {
+ invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
+ args[i], parameters[i].ParameterType);
+ }
+
+ ctor.Invoke(obj, invokeParams);
+ return true.ToGodotBool();
+ }
+ catch (Exception e)
{
- invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
- args[i], parameters[i].ParameterType);
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ return false.ToGodotBool();
}
-
- ctor.Invoke(obj, invokeParams);
}
- private static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* r_res)
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* outRes)
{
- // Performance is not critical here as this will be replaced with source generators.
- if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ try
{
- *r_res = default;
- return;
- }
+ // Performance is not critical here as this will be replaced with source generators.
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ {
+ *outRes = default;
+ return;
+ }
- var native = Object.InternalGetClassNativeBase(scriptType);
+ var native = Object.InternalGetClassNativeBase(scriptType);
- var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
- BindingFlags.Public | BindingFlags.NonPublic);
+ var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.NonPublic);
- if (field == null)
- {
- *r_res = default;
- return;
- }
+ if (field == null)
+ {
+ *outRes = default;
+ return;
+ }
- var nativeName = (StringName)field.GetValue(null);
+ var nativeName = (StringName)field.GetValue(null);
- *r_res = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
+ if (nativeName == null)
+ {
+ *outRes = default;
+ return;
+ }
+
+ *outRes = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ *outRes = default;
+ }
}
- private static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
+ [UnmanagedCallersOnly]
+ internal static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
{
- var target = (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
- if (target != null)
- target.NativePtr = newPtr;
+ try
+ {
+ var target = (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
+ if (target != null)
+ target.NativePtr = newPtr;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
}
private static unsafe Type TypeGetProxyClass(godot_string_name* nativeTypeName)
@@ -152,7 +203,9 @@ namespace Godot.Bridge
return wrapperType;
}
- internal static void LookupScriptsInAssembly(Assembly assembly)
+ // Called from GodotPlugins
+ // ReSharper disable once UnusedMember.Local
+ private static void LookupScriptsInAssembly(Assembly assembly)
{
static void LookupScriptForClass(Type type)
{
@@ -208,294 +261,398 @@ namespace Godot.Bridge
}
}
+ [UnmanagedCallersOnly]
internal static unsafe void RaiseEventSignal(IntPtr ownerGCHandlePtr,
- godot_string_name* eventSignalName, godot_variant** args, int argCount, bool* r_ownerIsNull)
+ godot_string_name* eventSignalName, godot_variant** args, int argCount, godot_bool* outOwnerIsNull)
{
- var owner = (Object)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
-
- if (owner == null)
+ try
{
- *r_ownerIsNull = true;
- return;
- }
+ var owner = (Object)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
+
+ if (owner == null)
+ {
+ *outOwnerIsNull = true.ToGodotBool();
+ return;
+ }
- *r_ownerIsNull = false;
+ *outOwnerIsNull = false.ToGodotBool();
- owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
+ owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *outOwnerIsNull = false.ToGodotBool();
+ }
}
- internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* r_retSignals)
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* outRetSignals)
{
- // Performance is not critical here as this will be replaced with source generators.
- using var signals = new Dictionary();
-
- Type top = _scriptBridgeMap[scriptPtr];
- Type native = Object.InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
+ try
{
- // Legacy signals
+ // Performance is not critical here as this will be replaced with source generators.
+ using var signals = new Dictionary();
+
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
- foreach (var signalDelegate in top
- .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
- .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
- .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
+ while (top != null && top != native)
{
- var invokeMethod = signalDelegate.GetMethod("Invoke");
+ // Legacy signals
- if (invokeMethod == null)
- throw new MissingMethodException(signalDelegate.FullName, "Invoke");
+ foreach (var signalDelegate in top
+ .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
+ .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
+ {
+ var invokeMethod = signalDelegate.GetMethod("Invoke");
- var signalParams = new Collections.Array();
+ if (invokeMethod == null)
+ throw new MissingMethodException(signalDelegate.FullName, "Invoke");
- foreach (var parameters in invokeMethod.GetParameters())
- {
- var paramType = Marshaling.managed_to_variant_type(
- parameters.ParameterType, out bool nilIsVariant);
- signalParams.Add(new Dictionary()
+ var signalParams = new Collections.Array();
+
+ foreach (var parameters in invokeMethod.GetParameters())
{
- { "name", parameters.Name },
- { "type", paramType },
- { "nil_is_variant", nilIsVariant }
- });
+ var paramType = Marshaling.managed_to_variant_type(
+ parameters.ParameterType, out bool nilIsVariant);
+ signalParams.Add(new Dictionary()
+ {
+ { "name", parameters.Name },
+ { "type", paramType },
+ { "nil_is_variant", nilIsVariant }
+ });
+ }
+
+ signals.Add(signalDelegate.Name, signalParams);
}
- signals.Add(signalDelegate.Name, signalParams);
- }
+ // Event signals
- // Event signals
+ var foundEventSignals = top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Select(ev => ev.Name);
- var foundEventSignals = top.GetEvents(
+ var fields = top.GetFields(
BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public)
- .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
- .Select(ev => ev.Name);
-
- var fields = top.GetFields(
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
+ BindingFlags.NonPublic | BindingFlags.Public);
- foreach (var eventSignalField in fields
- .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
- .Where(f => foundEventSignals.Contains(f.Name)))
- {
- var delegateType = eventSignalField.FieldType;
- var invokeMethod = delegateType.GetMethod("Invoke");
+ foreach (var eventSignalField in fields
+ .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
+ .Where(f => foundEventSignals.Contains(f.Name)))
+ {
+ var delegateType = eventSignalField.FieldType;
+ var invokeMethod = delegateType.GetMethod("Invoke");
- if (invokeMethod == null)
- throw new MissingMethodException(delegateType.FullName, "Invoke");
+ if (invokeMethod == null)
+ throw new MissingMethodException(delegateType.FullName, "Invoke");
- var signalParams = new Collections.Array();
+ var signalParams = new Collections.Array();
- foreach (var parameters in invokeMethod.GetParameters())
- {
- var paramType = Marshaling.managed_to_variant_type(
- parameters.ParameterType, out bool nilIsVariant);
- signalParams.Add(new Dictionary()
+ foreach (var parameters in invokeMethod.GetParameters())
{
- { "name", parameters.Name },
- { "type", paramType },
- { "nil_is_variant", nilIsVariant }
- });
+ var paramType = Marshaling.managed_to_variant_type(
+ parameters.ParameterType, out bool nilIsVariant);
+ signalParams.Add(new Dictionary()
+ {
+ { "name", parameters.Name },
+ { "type", paramType },
+ { "nil_is_variant", nilIsVariant }
+ });
+ }
+
+ signals.Add(eventSignalField.Name, signalParams);
}
- signals.Add(eventSignalField.Name, signalParams);
+ top = top.BaseType;
}
- top = top.BaseType;
+ *outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ *outRetSignals = NativeFuncs.godotsharp_dictionary_new();
}
-
- *r_retSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
}
- internal static unsafe bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
{
- // Performance is not critical here as this will be replaced with source generators.
- using var signals = new Dictionary();
-
- string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ using var signals = new Dictionary();
- Type top = _scriptBridgeMap[scriptPtr];
- Type native = Object.InternalGetClassNativeBase(top);
+ string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
- while (top != null && top != native)
- {
- // Legacy signals
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
- if (top
- .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
- .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
- .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
- .Any(signalDelegate => signalDelegate.Name == signalNameStr)
- )
+ while (top != null && top != native)
{
- return true;
- }
+ // Legacy signals
+
+ if (top
+ .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
+ .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Any(signalDelegate => signalDelegate.Name == signalNameStr)
+ )
+ {
+ return true.ToGodotBool();
+ }
- // Event signals
+ // Event signals
- if (top.GetEvents(
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public)
- .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
- .Any(eventSignal => eventSignal.Name == signalNameStr)
- )
- {
- return true;
+ if (top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Any(eventSignal => eventSignal.Name == signalNameStr)
+ )
+ {
+ return true.ToGodotBool();
+ }
+
+ top = top.BaseType;
}
- top = top.BaseType;
+ return false.ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ return false.ToGodotBool();
}
-
- return false;
}
- internal static unsafe bool HasMethodUnknownParams(IntPtr scriptPtr, godot_string* method, bool deep)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool HasMethodUnknownParams(IntPtr scriptPtr, godot_string* method,
+ godot_bool deep)
{
- // Performance is not critical here as this will be replaced with source generators.
- if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
- return false;
-
- string methodStr = Marshaling.mono_string_from_godot(*method);
-
- if (deep)
+ try
{
- Type top = scriptType;
- Type native = Object.InternalGetClassNativeBase(scriptType);
+ // Performance is not critical here as this will be replaced with source generators.
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ return false.ToGodotBool();
- while (top != null && top != native)
+ string methodStr = Marshaling.mono_string_from_godot(*method);
+
+ if (deep.ToBool())
{
- var methodInfo = top.GetMethod(methodStr,
- BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
+ Type top = scriptType;
+ Type native = Object.InternalGetClassNativeBase(scriptType);
- if (methodInfo != null)
- return true;
+ while (top != null && top != native)
+ {
+ var methodInfo = top.GetMethod(methodStr,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
- top = top.BaseType;
- }
+ if (methodInfo != null)
+ return true.ToGodotBool();
+
+ top = top.BaseType;
+ }
+
+ top = native;
+ Type typeOfSystemObject = typeof(System.Object);
+ while (top != null && top != typeOfSystemObject)
+ {
+ bool found = top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(m => m.GetCustomAttributes(false).OfType<GodotMethodAttribute>()
+ .Where(a => a.MethodName == methodStr)
+ .Any())
+ .Any();
+
+ if (found)
+ return true.ToGodotBool();
- return false;
+ top = top.BaseType;
+ }
+
+ return false.ToGodotBool();
+ }
+ else
+ {
+ var methodInfo = scriptType.GetMethod(methodStr, BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+ return (methodInfo != null).ToGodotBool();
+ }
}
- else
+ catch (Exception e)
{
- var methodInfo = scriptType.GetMethod(methodStr, BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public);
- return methodInfo != null;
+ ExceptionUtils.DebugUnhandledException(e);
+ return false.ToGodotBool();
}
}
- internal static bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
+ [UnmanagedCallersOnly]
+ internal static godot_bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
{
- if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
- return false;
+ try
+ {
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ return false.ToGodotBool();
- if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
- return false;
+ if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
+ return false.ToGodotBool();
- return scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType);
+ return (scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType)).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ return false.ToGodotBool();
+ }
}
- internal static unsafe bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
{
- string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
+ try
+ {
+ string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
- if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
- return false;
+ if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
+ return false.ToGodotBool();
- _scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
+ _scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
- return true;
+ return true.ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ return false.ToGodotBool();
+ }
}
internal static void AddScriptBridgeWithType(IntPtr scriptPtr, Type scriptType)
=> _scriptBridgeMap.Add(scriptPtr, scriptType);
+ [UnmanagedCallersOnly]
internal static void RemoveScriptBridge(IntPtr scriptPtr)
- => _scriptBridgeMap.Remove(scriptPtr);
-
- internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, bool* r_tool,
- godot_dictionary* r_rpcFunctionsDest)
{
- // Performance is not critical here as this will be replaced with source generators.
- var scriptType = _scriptBridgeMap[scriptPtr];
-
- *r_tool = scriptType.GetCustomAttributes(inherit: false)
- .OfType<ToolAttribute>()
- .Any();
+ try
+ {
+ _scriptBridgeMap.Remove(scriptPtr);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
+ }
- if (!*r_tool && scriptType.IsNested)
+ [UnmanagedCallersOnly]
+ internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_bool* outTool,
+ godot_dictionary* outRpcFunctionsDest)
+ {
+ try
{
- *r_tool = scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
+ // Performance is not critical here as this will be replaced with source generators.
+ var scriptType = _scriptBridgeMap[scriptPtr];
+
+ *outTool = scriptType.GetCustomAttributes(inherit: false)
.OfType<ToolAttribute>()
- .Any() ?? false;
- }
+ .Any().ToGodotBool();
- if (!*r_tool && scriptType.Assembly.GetName().Name == "GodotTools")
- *r_tool = true;
+ if (!(*outTool).ToBool() && scriptType.IsNested)
+ {
+ *outTool = (scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
+ .OfType<ToolAttribute>()
+ .Any() ?? false).ToGodotBool();
+ }
- // RPC functions
+ if (!(*outTool).ToBool() && scriptType.Assembly.GetName().Name == "GodotTools")
+ *outTool = true.ToGodotBool();
- Dictionary<string, Dictionary> rpcFunctions = new();
+ // RPC functions
- Type top = _scriptBridgeMap[scriptPtr];
- Type native = Object.InternalGetClassNativeBase(top);
+ Dictionary<string, Dictionary> rpcFunctions = new();
- while (top != null && top != native)
- {
- foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
- BindingFlags.NonPublic | BindingFlags.Public))
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
{
- if (method.IsStatic)
- continue;
+ foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public))
+ {
+ if (method.IsStatic)
+ continue;
- string methodName = method.Name;
+ string methodName = method.Name;
- if (rpcFunctions.ContainsKey(methodName))
- continue;
+ if (rpcFunctions.ContainsKey(methodName))
+ continue;
- var rpcAttr = method.GetCustomAttributes(inherit: false)
- .OfType<RPCAttribute>().FirstOrDefault();
+ var rpcAttr = method.GetCustomAttributes(inherit: false)
+ .OfType<RPCAttribute>().FirstOrDefault();
- if (rpcAttr == null)
- continue;
+ if (rpcAttr == null)
+ continue;
- var rpcConfig = new Dictionary();
+ var rpcConfig = new Dictionary();
- rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
- rpcConfig["call_local"] = rpcAttr.CallLocal;
- rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
- rpcConfig["channel"] = rpcAttr.TransferChannel;
+ rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
+ rpcConfig["call_local"] = rpcAttr.CallLocal;
+ rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
+ rpcConfig["channel"] = rpcAttr.TransferChannel;
+
+ rpcFunctions.Add(methodName, rpcConfig);
+ }
- rpcFunctions.Add(methodName, rpcConfig);
+ top = top.BaseType;
}
- top = top.BaseType;
+ *outRpcFunctionsDest =
+ NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ *outTool = false.ToGodotBool();
+ *outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
}
-
- *r_rpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
}
- internal static unsafe bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* r_newGCHandlePtr,
- bool createWeak)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* outNewGCHandlePtr,
+ godot_bool createWeak)
{
- var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
+ try
+ {
+ var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
- object target = oldGCHandle.Target;
+ object target = oldGCHandle.Target;
- if (target == null)
- {
- oldGCHandle.Free();
- *r_newGCHandlePtr = IntPtr.Zero;
- return false; // Called after the managed side was collected, so nothing to do here
- }
+ if (target == null)
+ {
+ oldGCHandle.Free();
+ *outNewGCHandlePtr = IntPtr.Zero;
+ return false.ToGodotBool(); // Called after the managed side was collected, so nothing to do here
+ }
- // Release the current weak handle and replace it with a strong handle.
- var newGCHandle = GCHandle.Alloc(target, createWeak ? GCHandleType.Weak : GCHandleType.Normal);
+ // Release the current weak handle and replace it with a strong handle.
+ var newGCHandle = GCHandle.Alloc(target,
+ createWeak.ToBool() ? GCHandleType.Weak : GCHandleType.Normal);
- oldGCHandle.Free();
- *r_newGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
- return true;
+ oldGCHandle.Free();
+ *outNewGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
+ return true.ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ *outNewGCHandlePtr = IntPtr.Zero;
+ return false.ToGodotBool();
+ }
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
index edfe3464ec..e446b3db1c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
@@ -1,7 +1,9 @@
using System;
using System.Diagnostics;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Text;
+using Godot.NativeInterop;
namespace Godot
{
@@ -19,13 +21,23 @@ namespace Godot
sb.Append(" ");
}
- public static void InstallTraceListener()
+ [UnmanagedCallersOnly]
+ internal static void InstallTraceListener()
{
- Trace.Listeners.Clear();
- Trace.Listeners.Add(new GodotTraceListener());
+ try
+ {
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(new GodotTraceListener());
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ ExceptionUtils.PushError("Failed to install 'System.Diagnostics.Trace' listener.");
+ }
}
- public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl)
+ public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber,
+ out string methodDecl)
{
fileName = frame.GetFileName();
fileLineNumber = frame.GetFileLineNumber();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 2a562d4d48..87c93e35f5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -11,38 +11,56 @@ namespace Godot
{
internal static class DelegateUtils
{
- internal static bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
+ [UnmanagedCallersOnly]
+ internal static godot_bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
{
- var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
- var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target;
- return @delegateA == @delegateB;
+ try
+ {
+ var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
+ var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target;
+ return (@delegateA == @delegateB).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ return false.ToGodotBool();
+ }
}
+ [UnmanagedCallersOnly]
internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
- godot_variant* ret)
+ godot_variant* outRet)
{
- // TODO: Optimize
- var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
- var managedArgs = new object[argc];
+ try
+ {
+ // TODO: Optimize
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
+ var managedArgs = new object[argc];
- var parameterInfos = @delegate.Method.GetParameters();
- var paramsLength = parameterInfos.Length;
+ var parameterInfos = @delegate!.Method.GetParameters();
+ var paramsLength = parameterInfos.Length;
- if (argc != paramsLength)
- {
- throw new InvalidOperationException(
- $"The delegate expects {paramsLength} arguments, but received {argc}.");
- }
+ 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);
- }
+ 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);
+ object invokeRet = @delegate.DynamicInvoke(managedArgs);
- *ret = Marshaling.mono_object_to_variant(invokeRet);
+ *outRet = Marshaling.mono_object_to_variant(invokeRet);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *outRet = default;
+ }
}
// TODO: Check if we should be using BindingFlags.DeclaredOnly (would give better reflection performance).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 8bc33837e6..c21d53b4d4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -76,7 +76,7 @@ namespace Godot.Collections
public Dictionary Duplicate(bool deep = false)
{
godot_dictionary newDictionary;
- NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep, out newDictionary);
+ NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep.ToGodotBool(), out newDictionary);
return CreateTakingOwnershipOfDisposableValue(newDictionary);
}
@@ -137,7 +137,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref NativeValue, &variantKey,
- out godot_variant value))
+ out godot_variant value).ToBool())
{
using (value)
return Marshaling.variant_to_mono_object(&value);
@@ -165,7 +165,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
- if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey))
+ if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool())
throw new ArgumentException("An element with the same key already exists", nameof(key));
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
@@ -185,7 +185,7 @@ namespace Godot.Collections
public unsafe bool Contains(object key)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
- return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey);
+ return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool();
}
/// <summary>
@@ -432,7 +432,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
- &variantKey, out godot_variant value))
+ &variantKey, out godot_variant value).ToBool())
{
using (value)
return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues);
@@ -513,7 +513,7 @@ namespace Godot.Collections
public unsafe bool Remove(TKey key)
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
- return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey);
+ return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey).ToBool();
}
/// <summary>
@@ -526,7 +526,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
- &variantKey, out godot_variant retValue);
+ &variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
@@ -566,7 +566,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
- &variantKey, out godot_variant retValue);
+ &variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
@@ -574,7 +574,7 @@ namespace Godot.Collections
return false;
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
- return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue);
+ return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool();
}
}
@@ -610,7 +610,7 @@ namespace Godot.Collections
{
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
- &variantKey, out godot_variant retValue);
+ &variantKey, out godot_variant retValue).ToBool();
using (retValue)
{
@@ -618,8 +618,11 @@ namespace Godot.Collections
return false;
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
- if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue))
- return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey);
+ if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool())
+ {
+ return NativeFuncs.godotsharp_dictionary_remove_key(
+ ref _underlyingDict.NativeValue, &variantKey).ToBool();
+ }
return false;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
index 5f84bb530f..e8cfb8e1b1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -1,12 +1,24 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
namespace Godot
{
public static class Dispatcher
{
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
- private static void InitializeDefaultGodotTaskScheduler()
+ [UnmanagedCallersOnly]
+ internal static void InitializeDefaultGodotTaskScheduler()
{
- DefaultGodotTaskScheduler = new GodotTaskScheduler();
+ try
+ {
+ DefaultGodotTaskScheduler = new GodotTaskScheduler();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugUnhandledException(e);
+ }
}
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
index b939da8778..17bca19fab 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
@@ -24,14 +24,16 @@ namespace Godot
if (nativeBase)
{
// Native type
- var field = typeOfT.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
- BindingFlags.Public | BindingFlags.NonPublic);
+ var field = typeOfT.GetField("NativeName",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.NonPublic);
var nativeName = (StringName)field!.GetValue(null);
godot_string_name nativeNameAux = nativeName.NativeValue;
godot_array inputAux = array.NativeValue;
godot_array filteredArray;
- godotsharp_array_filter_godot_objects_by_native(&nativeNameAux, &inputAux, &filteredArray);
+ NativeFuncs.godotsharp_array_filter_godot_objects_by_native(
+ &nativeNameAux, &inputAux, &filteredArray);
return Array<T>.CreateTakingOwnershipOfDisposableValue(filteredArray);
}
else
@@ -39,7 +41,7 @@ namespace Godot
// Custom derived type
godot_array inputAux = array.NativeValue;
godot_array filteredArray;
- godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
+ NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray);
@@ -62,13 +64,5 @@ namespace Godot
return resWrapped;
}
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal extern unsafe void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
- godot_array* p_input, godot_array* r_output);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal extern unsafe void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
- godot_array* r_output);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index f428100ff7..39271d3daf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -30,7 +30,7 @@ namespace Godot
{
using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes);
using godot_variant ret = default;
- NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects, &ret);
+ NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects.ToGodotBool(), &ret);
return Marshaling.variant_to_mono_object(&ret);
}
@@ -561,7 +561,7 @@ namespace Godot
{
using var variant = Marshaling.mono_object_to_variant(var);
using godot_packed_byte_array varBytes = default;
- NativeFuncs.godotsharp_var2bytes(&variant, fullObjects, &varBytes);
+ NativeFuncs.godotsharp_var2bytes(&variant, fullObjects.ToGodotBool(), &varBytes);
using (varBytes)
return Marshaling.PackedByteArray_to_mono_array(&varBytes);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
new file mode 100644
index 0000000000..2830d9c527
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
@@ -0,0 +1,74 @@
+using System;
+
+namespace Godot.NativeInterop
+{
+ internal static class ExceptionUtils
+ {
+ public static void PushError(string message)
+ {
+ GD.PushError(message);
+ }
+
+ private static void OnExceptionLoggerException(Exception loggerException, Exception exceptionToLog)
+ {
+ // This better not throw
+ PushError("Exception thrown when trying to log another exception...");
+ PushError("Exception:");
+ PushError(exceptionToLog.ToString());
+ PushError("Logger exception:");
+ PushError(loggerException.ToString());
+ }
+
+ public static void DebugPrintUnhandledException(Exception e)
+ {
+ try
+ {
+ // TODO Not implemented (debug_print_unhandled_exception)
+ GD.PushError(e.ToString());
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+
+ public static void DebugSendUnhandledExceptionError(Exception e)
+ {
+ try
+ {
+ // TODO Not implemented (debug_send_unhandled_exception_error)
+ GD.PushError(e.ToString());
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+
+ public static void DebugUnhandledException(Exception e)
+ {
+ try
+ {
+ // TODO Not implemented (debug_unhandled_exception)
+ GD.PushError(e.ToString());
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+
+ public static void PrintUnhandledException(Exception e)
+ {
+ try
+ {
+ // TODO Not implemented (print_unhandled_exception)
+ GD.PushError(e.ToString());
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
index d8931f8348..0942d8f722 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -1,26 +1,36 @@
-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
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace Godot.NativeInterop
{
- [StructLayout(LayoutKind.Sequential)]
- // ReSharper disable once InconsistentNaming
- public struct godot_bool
+ internal static class GodotBoolExtensions
{
- public byte _value;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_bool ToGodotBool(this bool @bool)
+ {
+ return *(godot_bool*)&@bool;
+ }
- public unsafe godot_bool(bool value) => _value = *(byte*)&value;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe bool ToBool(this godot_bool godotBool)
+ {
+ return *(bool*)&godotBool;
+ }
+ }
- public static unsafe implicit operator bool(godot_bool godotBool) => *(bool*)&godotBool._value;
- public static implicit operator godot_bool(bool @bool) => new godot_bool(@bool);
+ // Apparently a struct with a byte is not blittable? It crashes when calling a UnmanagedCallersOnly function ptr.
+ // ReSharper disable once InconsistentNaming
+ public enum godot_bool : byte
+ {
+ True = 1,
+ False = 0
}
[StructLayout(LayoutKind.Sequential)]
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
index 5d53006140..5779421c69 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
@@ -16,13 +16,14 @@ namespace Godot.NativeInterop
return null;
IntPtr gcHandlePtr;
- bool has_cs_script_instance = false;
+ godot_bool has_cs_script_instance = false.ToGodotBool();
// First try to get the tied managed instance from a CSharpInstance script instance
unsafe
{
- gcHandlePtr = unmanaged_get_script_instance_managed(unmanaged, &has_cs_script_instance);
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed(
+ unmanaged, &has_cs_script_instance);
}
if (gcHandlePtr != IntPtr.Zero)
@@ -30,12 +31,12 @@ namespace Godot.NativeInterop
// Otherwise, if the object has a CSharpInstance script instance, return null
- if (has_cs_script_instance)
+ if (has_cs_script_instance.ToBool())
return null;
// If it doesn't have a CSharpInstance script instance, try with native instance bindings
- gcHandlePtr = unmanaged_get_instance_binding_managed(unmanaged);
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_instance_binding_managed(unmanaged);
object target = gcHandlePtr != IntPtr.Zero ? GCHandle.FromIntPtr(gcHandlePtr).Target : null;
@@ -44,22 +45,12 @@ namespace Godot.NativeInterop
// If the native instance binding GC handle target was collected, create a new one
- gcHandlePtr = unmanaged_instance_binding_create_managed(unmanaged, gcHandlePtr);
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_instance_binding_create_managed(
+ unmanaged, gcHandlePtr);
return gcHandlePtr != IntPtr.Zero ? (Object)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe IntPtr unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
- bool* r_has_cs_script_instance);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
- IntPtr oldGCHandlePtr);
-
public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged,
StringName nativeName, bool refCounted, Type type, Type nativeType)
{
@@ -70,30 +61,22 @@ namespace Godot.NativeInterop
unsafe
{
godot_string_name nativeNameAux = nativeName.NativeValue;
- internal_tie_native_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
- &nativeNameAux, refCounted);
+ NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged(
+ GCHandle.ToIntPtr(gcHandle), unmanaged, &nativeNameAux, refCounted.ToGodotBool());
}
}
else
{
- IntPtr scriptPtr = internal_new_csharp_script();
+ IntPtr scriptPtr = NativeFuncs.godotsharp_internal_new_csharp_script();
ScriptManagerBridge.AddScriptBridgeWithType(scriptPtr, type);
// IMPORTANT: This must be called after AddScriptWithTypeBridge
- internal_tie_user_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
- scriptPtr, refCounted);
+ NativeFuncs.godotsharp_internal_tie_user_managed_to_unmanaged(
+ GCHandle.ToIntPtr(gcHandle), unmanaged, scriptPtr, refCounted.ToGodotBool());
}
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern unsafe void internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
- IntPtr unmanaged, godot_string_name* nativeName, bool refCounted);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
- IntPtr unmanaged, IntPtr scriptPtr, bool refCounted);
-
public static void TieManagedToUnmanagedWithPreSetup(Object managed, IntPtr unmanaged,
Type type, Type nativeType)
{
@@ -101,16 +84,10 @@ namespace Godot.NativeInterop
return;
var strongGCHandle = GCHandle.Alloc(managed, GCHandleType.Normal);
- internal_tie_managed_to_unmanaged_with_pre_setup(GCHandle.ToIntPtr(strongGCHandle), unmanaged);
+ NativeFuncs.godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
+ GCHandle.ToIntPtr(strongGCHandle), unmanaged);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_tie_managed_to_unmanaged_with_pre_setup(
- IntPtr gcHandleIntPtr, IntPtr unmanaged);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr internal_new_csharp_script();
-
public static unsafe Object EngineGetSingleton(string name)
{
using godot_string src = Marshaling.mono_string_to_godot(name);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index eae644af85..74232425bb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
@@ -420,44 +421,18 @@ namespace Godot.NativeInterop
if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>))
{
// TODO: Validate key and value types are compatible with Variant
-#if NET
- Collections.IGenericGodotDictionary genericGodotDictionary =
- IDictionaryToGenericGodotDictionary((dynamic)p_obj);
-#else
- var genericArguments = type.GetGenericArguments();
-
- // With .NET Standard we need a package reference for Microsoft.CSharp in order to
- // use dynamic, so we have this workaround for now until we switch to .NET 5/6.
- var method = typeof(Marshaling).GetMethod(nameof(IDictionaryToGenericGodotDictionary),
- BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!
- .MakeGenericMethod(genericArguments[0], genericArguments[1]);
+ var godotDict = new Collections.Dictionary();
- var genericGodotDictionary = (Collections.IGenericGodotDictionary)method
- .Invoke(null, new[] { p_obj });
-#endif
+ foreach (KeyValuePair<object, object> entry in (IDictionary)p_obj)
+ godotDict.Add(entry.Key, entry.Value);
- var godotDict = genericGodotDictionary.UnderlyingDictionary;
- if (godotDict == null)
- return new godot_variant();
return VariantUtils.CreateFromDictionary(godotDict.NativeValue);
}
if (genericTypeDefinition == typeof(System.Collections.Generic.List<>))
{
// TODO: Validate element type is compatible with Variant
-#if NET
- var nativeGodotArray =
- (godot_array)mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj));
-#else
- // With .NET Standard we need a package reference for Microsoft.CSharp in order to
- // use dynamic, so we have this workaround for now until we switch to .NET 5/6.
- // Also CollectionsMarshal.AsSpan is not available with .NET Standard.
-
- var collection = (System.Collections.ICollection)p_obj;
- var array = new object[collection.Count];
- collection.CopyTo(array, 0);
- var nativeGodotArray = mono_array_to_Array(array);
-#endif
+ var nativeGodotArray = mono_array_to_Array((IList)p_obj);
return VariantUtils.CreateFromArray(&nativeGodotArray);
}
}
@@ -478,9 +453,6 @@ namespace Godot.NativeInterop
}
}
- private static Collections.Dictionary<TKey, TValue> IDictionaryToGenericGodotDictionary<TKey, TValue>
- (IDictionary<TKey, TValue> dictionary) => new(dictionary);
-
public static unsafe string variant_to_mono_string(godot_variant* p_var)
{
switch ((*p_var)._type)
@@ -855,7 +827,7 @@ namespace Godot.NativeInterop
switch ((*p_var)._type)
{
case Variant.Type.Bool:
- return (bool)(*p_var)._data._bool;
+ return (*p_var)._data._bool.ToBool();
case Variant.Type.Int:
return (*p_var)._data._int;
case Variant.Type.Float:
@@ -1058,7 +1030,7 @@ namespace Godot.NativeInterop
godot_string_name name;
if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(
- p_callable, &delegateGCHandle, &godotObject, &name))
+ p_callable, &delegateGCHandle, &godotObject, &name).ToBool())
{
if (delegateGCHandle != IntPtr.Zero)
{
@@ -1141,15 +1113,37 @@ namespace Godot.NativeInterop
return ret;
}
- public static godot_array mono_array_to_Array(Span<object> p_array)
+ public static godot_array mono_array_to_Array(object[] p_array)
{
- if (p_array.IsEmpty)
+ int length = p_array.Length;
+
+ if (length == 0)
return NativeFuncs.godotsharp_array_new();
using var array = new Collections.Array();
- array.Resize(p_array.Length);
+ array.Resize(length);
- for (int i = 0; i < p_array.Length; i++)
+ for (int i = 0; i < length; i++)
+ array[i] = p_array[i];
+
+ godot_array src = array.NativeValue;
+ unsafe
+ {
+ return NativeFuncs.godotsharp_array_new_copy(&src);
+ }
+ }
+
+ public static godot_array mono_array_to_Array(IList p_array)
+ {
+ int length = p_array.Count;
+
+ if (length == 0)
+ return NativeFuncs.godotsharp_array_new();
+
+ using var array = new Collections.Array();
+ array.Resize(length);
+
+ for (int i = 0; i < length; i++)
array[i] = p_array[i];
godot_array src = array.NativeValue;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index 73ac837fe1..8bc785f375 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -20,20 +20,61 @@ namespace Godot.NativeInterop
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
+ public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(
+ ref godot_string_name p_classname);
+
[DllImport(GodotDllName)]
- public static extern IntPtr godotsharp_get_class_constructor(ref godot_string_name p_classname);
+ public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name);
[DllImport(GodotDllName)]
- public static extern IntPtr godotsharp_invoke_class_constructor(IntPtr p_creation_func);
-#endif
+ internal static extern void godotsharp_internal_object_disposed(IntPtr ptr);
[DllImport(GodotDllName)]
- public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name);
+ internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, godot_bool isFinalizer);
+
+ [DllImport(GodotDllName)]
+ internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
+ godot_string_name* eventSignal);
+
+ [DllImport(GodotDllName)]
+ internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
+ ref godot_string_name signal,
+ IntPtr target, IntPtr awaiterHandlePtr);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, godot_string_name* nativeName, godot_bool refCounted);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
+ IntPtr gcHandleIntPtr, IntPtr unmanaged);
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
+ godot_bool* r_has_cs_script_instance);
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
+ IntPtr oldGCHandlePtr);
+
+ [DllImport(GodotDllName)]
+ public static extern IntPtr godotsharp_internal_new_csharp_script();
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
+ godot_array* p_input, godot_array* r_output);
+
+ [DllImport(GodotDllName)]
+ public static extern void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
+ godot_array* r_output);
[DllImport(GodotDllName)]
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
@@ -509,12 +550,12 @@ namespace Godot.NativeInterop
public static extern int godotsharp_node_path_get_subname_count(ref godot_node_path p_self);
[DllImport(GodotDllName)]
- public static extern bool godotsharp_node_path_is_absolute(ref godot_node_path p_self);
+ public static extern godot_bool godotsharp_node_path_is_absolute(ref godot_node_path p_self);
// GD, etc
[DllImport(GodotDllName)]
- public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, bool p_allow_objects,
+ public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, godot_bool p_allow_objects,
godot_variant* r_ret);
[DllImport(GodotDllName)]
@@ -578,7 +619,7 @@ namespace Godot.NativeInterop
public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret);
[DllImport(GodotDllName)]
- public static extern void godotsharp_var2bytes(godot_variant* what, bool fullObjects,
+ public static extern void godotsharp_var2bytes(godot_variant* what, godot_bool fullObjects,
godot_packed_byte_array* bytes);
[DllImport(GodotDllName)]
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 91ba864687..e52454a2e3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -8,46 +8,46 @@ namespace Godot.NativeInterop
public static class VariantUtils
{
public static godot_variant CreateFromRID(RID from)
- => new() {_type = Variant.Type.Rid, _data = {_m_rid = from}};
+ => new() { _type = Variant.Type.Rid, _data = { _m_rid = from } };
public static godot_variant CreateFromBool(bool from)
- => new() {_type = Variant.Type.Bool, _data = {_bool = from}};
+ => new() { _type = Variant.Type.Bool, _data = { _bool = from.ToGodotBool() } };
public static godot_variant CreateFromInt(long from)
- => new() {_type = Variant.Type.Int, _data = {_int = 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}};
+ => new() { _type = Variant.Type.Int, _data = { _int = (long)from } };
public static godot_variant CreateFromFloat(double from)
- => new() {_type = Variant.Type.Float, _data = {_float = 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => 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}};
+ => new() { _type = Variant.Type.Plane, _data = { _m_plane = from } };
public static unsafe godot_variant CreateFromTransform2D(Transform2D from)
{
@@ -100,15 +100,15 @@ namespace Godot.NativeInterop
// Explicit name to make it very clear
public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from)
- => new() {_type = Variant.Type.Callable, _data = {_m_callable = from}};
+ => new() { _type = Variant.Type.Callable, _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}};
+ => 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}};
+ => new() { _type = Variant.Type.String, _data = { _m_string = from } };
public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from)
{
@@ -223,61 +223,97 @@ namespace Godot.NativeInterop
// 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);
+ => (*p_var)._type == Variant.Type.Bool ?
+ (*p_var)._data._bool.ToBool() :
+ NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool();
public static unsafe char ConvertToChar(godot_variant* p_var)
- => (char)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(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));
+ => (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));
+ => (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));
+ => (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));
+ => (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));
+ => (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));
+ => (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));
+ => (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));
+ => (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);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*p_var)._type == Variant.Type.Vector3i ?
+ (*p_var)._data._m_vector3i :
+ NativeFuncs.godotsharp_variant_as_vector3i(p_var);
public static unsafe Vector4 ConvertToVector4(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var);
@@ -286,31 +322,45 @@ namespace Godot.NativeInterop
=> (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var);
public static unsafe Basis ConvertToBasis(godot_variant* p_var)
- => (*p_var)._type == Variant.Type.Basis ? *(*p_var)._data._basis : NativeFuncs.godotsharp_variant_as_basis(p_var);
+ => (*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);
+ => (*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);
+ => (*p_var)._type == Variant.Type.Transform3d ?
+ *(*p_var)._data._transform3d :
+ NativeFuncs.godotsharp_variant_as_transform3d(p_var);
public static unsafe Projection ConvertToProjection(godot_variant* p_var)
=> (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var);
public static unsafe AABB ConvertToAABB(godot_variant* p_var)
- => (*p_var)._type == Variant.Type.Aabb ? *(*p_var)._data._aabb : NativeFuncs.godotsharp_variant_as_aabb(p_var);
+ => (*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);
+ => (*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);
+ => (*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);
+ => (*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 ?
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index 824f29558f..b18606b47e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -263,7 +263,7 @@ namespace Godot
/// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
public bool IsAbsolute()
{
- return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue);
+ return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue).ToBool();
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 763483a11f..98266ffdfc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -21,14 +21,11 @@ namespace Godot
{
if (NativePtr == IntPtr.Zero)
{
-#if NET
unsafe
{
NativePtr = NativeCtor();
}
-#else
- NativePtr = _gd__invoke_class_constructor(NativeCtor);
-#endif
+
InteropUtils.TieManagedToUnmanaged(this, NativePtr,
NativeName, refCounted: false, GetType(), _cachedType);
}
@@ -58,7 +55,7 @@ namespace Godot
{
using var eventSignalName = new StringName(eventSignal.Name);
godot_string_name eventSignalNameAux = eventSignalName.NativeValue;
- godot_icall_Object_ConnectEventSignal(NativePtr, &eventSignalNameAux);
+ NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, &eventSignalNameAux);
}
}
@@ -114,14 +111,14 @@ namespace Godot
if (MemoryOwn)
{
MemoryOwn = false;
- godot_icall_RefCounted_Disposed(NativePtr, !disposing);
+ NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, (!disposing).ToGodotBool());
}
else
{
- godot_icall_Object_Disposed(NativePtr);
+ NativeFuncs.godotsharp_internal_object_disposed(NativePtr);
}
- this.NativePtr = IntPtr.Zero;
+ NativePtr = IntPtr.Zero;
}
_disposed = true;
@@ -391,7 +388,6 @@ namespace Godot
return methodBind;
}
-#if NET
internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
{
// for some reason the '??' operator doesn't support 'delegate*'
@@ -402,30 +398,5 @@ namespace Godot
return nativeConstructor;
}
-#else
- internal static IntPtr ClassDB_get_constructor(StringName type)
- {
- // for some reason the '??' operator doesn't support 'delegate*'
- var nativeConstructor = 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)
- => NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr);
-#endif
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Object_Disposed(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_RefCounted_Disposed(IntPtr ptr, bool isFinalizer);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern unsafe void godot_icall_Object_ConnectEventSignal(IntPtr obj,
- godot_string_name* eventSignal);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index fd6636e410..62dec81582 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -1,5 +1,4 @@
using System;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Godot.NativeInterop;
@@ -13,14 +12,10 @@ namespace Godot
public SignalAwaiter(Object source, StringName signal, Object target)
{
- godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
+ NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this)));
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal,
- IntPtr target, IntPtr awaiterHandlePtr);
-
public bool IsCompleted => _completed;
public void OnCompleted(Action action)
@@ -32,30 +27,38 @@ namespace Godot
public IAwaiter<object[]> GetAwaiter() => this;
- internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr,
- godot_variant** args, int argCount,
- bool* r_awaiterIsNull)
+ [UnmanagedCallersOnly]
+ internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr, godot_variant** args, int argCount,
+ godot_bool* outAwaiterIsNull)
{
- var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
-
- if (awaiter == null)
+ try
{
- *r_awaiterIsNull = true;
- return;
- }
+ var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
+
+ if (awaiter == null)
+ {
+ *outAwaiterIsNull = true.ToGodotBool();
+ return;
+ }
- *r_awaiterIsNull = false;
+ *outAwaiterIsNull = false.ToGodotBool();
- awaiter._completed = true;
+ awaiter._completed = true;
- object[] signalArgs = new object[argCount];
+ object[] signalArgs = new object[argCount];
- for (int i = 0; i < argCount; i++)
- signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
+ for (int i = 0; i < argCount; i++)
+ signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
- awaiter._result = signalArgs;
+ awaiter._result = signalArgs;
- awaiter._action?.Invoke();
+ awaiter._action?.Invoke();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.DebugPrintUnhandledException(e);
+ *outAwaiterIsNull = false.ToGodotBool();
+ }
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 6a529de99b..763ded8809 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -4,7 +4,7 @@
<OutputPath>bin/$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace>Godot</RootNamespace>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -34,6 +34,7 @@
<Compile Include="Core\Basis.cs" />
<Compile Include="Core\Bridge\CSharpInstanceBridge.cs" />
<Compile Include="Core\Bridge\GCHandleBridge.cs" />
+ <Compile Include="Core\Bridge\ManagedCallbacks.cs" />
<Compile Include="Core\Bridge\ScriptManagerBridge.cs" />
<Compile Include="Core\Callable.cs" />
<Compile Include="Core\Color.cs" />
@@ -58,6 +59,7 @@
<Compile Include="Core\MarshalUtils.cs" />
<Compile Include="Core\Mathf.cs" />
<Compile Include="Core\MathfEx.cs" />
+ <Compile Include="Core\NativeInterop\ExceptionUtils.cs" />
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
<Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
index da6f293871..dbd98d0afb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("GodotSharpEditor")]
+[assembly: InternalsVisibleTo("GodotPlugins")]
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index 1082c74448..c0c1b91dc9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -4,7 +4,7 @@
<OutputPath>bin/$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace>Godot</RootNamespace>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net5.0</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
deleted file mode 100644
index dbf2ae84aa..0000000000
--- a/modules/mono/glue/base_object_glue.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*************************************************************************/
-/* base_object_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
-#include "core/string/string_name.h"
-
-#include "../csharp_script.h"
-#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_utils.h"
-#include "../signal_awaiter_utils.h"
-
-void godot_icall_Object_Disposed(Object *p_ptr) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == nullptr);
-#endif
-
- if (p_ptr->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
- if (cs_instance) {
- if (!cs_instance->is_destructing_script_instance()) {
- cs_instance->mono_object_disposed();
- p_ptr->set_script_instance(nullptr);
- }
- return;
- }
- }
-
- void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
-
- if (data) {
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
- if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(nullptr, gchandle);
- script_binding.inited = false;
- }
- }
- }
-}
-
-void godot_icall_RefCounted_Disposed(Object *p_ptr, MonoBoolean p_is_finalizer) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == nullptr);
- // This is only called with RefCounted derived classes
- CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
-#endif
-
- RefCounted *rc = static_cast<RefCounted *>(p_ptr);
-
- if (rc->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance());
- if (cs_instance) {
- if (!cs_instance->is_destructing_script_instance()) {
- bool delete_owner;
- bool remove_script_instance;
-
- cs_instance->mono_object_disposed_baseref(p_is_finalizer, delete_owner, remove_script_instance);
-
- if (delete_owner) {
- memdelete(rc);
- } else if (remove_script_instance) {
- rc->set_script_instance(nullptr);
- }
- }
- return;
- }
- }
-
- // Unsafe refcount decrement. The managed instance also counts as a reference.
- // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
- CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc);
- if (rc->unreference()) {
- memdelete(rc);
- } else {
- void *data = CSharpLanguage::get_existing_instance_binding(rc);
-
- if (data) {
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
- if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(nullptr, gchandle);
- script_binding.inited = false;
- }
- }
- }
- }
-}
-
-void godot_icall_Object_ConnectEventSignal(Object *p_ptr, const StringName *p_event_signal) {
- CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
- if (csharp_instance) {
- csharp_instance->connect_event_signal(*p_event_signal);
- }
-}
-
-int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
- StringName signal = p_signal ? *p_signal : StringName();
- return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
-}
-
-void godot_register_object_icalls() {
- 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_ConnectEventSignal", godot_icall_Object_ConnectEventSignal);
- GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
-}
diff --git a/modules/mono/glue/placeholder_glue.cpp b/modules/mono/glue/placeholder_glue.cpp
deleted file mode 100644
index 0dd904373e..0000000000
--- a/modules/mono/glue/placeholder_glue.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*************************************************************************/
-/* placeholder_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GLUE_HEADER_H
-#define GLUE_HEADER_H
-
-#include "core/object/object.h"
-
-#include "../csharp_script.h"
-#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-GCHandleIntPtr unmanaged_get_script_instance_managed(Object *p_unmanaged, bool *r_has_cs_script_instance) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_unmanaged);
- CRASH_COND(!r_has_cs_script_instance);
-#endif
-
- if (p_unmanaged->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
-
- if (cs_instance) {
- *r_has_cs_script_instance = true;
- return cs_instance->get_gchandle_intptr();
- }
- }
-
- *r_has_cs_script_instance = false;
- return GCHandleIntPtr();
-}
-
-GCHandleIntPtr unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_unmanaged);
-#endif
-
- void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
- ERR_FAIL_NULL_V(data, GCHandleIntPtr());
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
-
- return script_binding.gchandle.get_intptr();
-}
-
-GCHandleIntPtr unmanaged_instance_binding_create_managed(Object *p_unmanaged, GCHandleIntPtr p_old_gchandle) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_unmanaged);
-#endif
-
- void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
- ERR_FAIL_NULL_V(data, GCHandleIntPtr());
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
-
- MonoGCHandleData &gchandle = script_binding.gchandle;
-
- // TODO: Possible data race?
- CRASH_COND(gchandle.get_intptr().value != p_old_gchandle.value);
-
- CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- script_binding.inited = false;
-
- // Create a new one
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(script_binding.type_name == StringName());
-#endif
-
- bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
- ERR_FAIL_COND_V_MSG(!parent_is_object_class, GCHandleIntPtr(),
- "Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
-
- MonoException *exc = nullptr;
- GCHandleIntPtr strong_gchandle =
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding
- .invoke(&script_binding.type_name, p_unmanaged, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return GCHandleIntPtr();
- }
-
- ERR_FAIL_NULL_V(strong_gchandle.value, GCHandleIntPtr());
-
- gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
- script_binding.inited = true;
-
- // Tie managed to unmanaged
- RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
-
- if (rc) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
- rc->reference();
- CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
- }
-
- return gchandle.get_intptr();
-}
-
-void godot_icall_InteropUtils_tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
- CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
-}
-
-void godot_icall_InteropUtils_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
- CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
-}
-
-void godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
- CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
-}
-
-CSharpScript *godot_icall_InteropUtils_internal_new_csharp_script() {
- CSharpScript *script = memnew(CSharpScript);
- CRASH_COND(!script);
- return script;
-}
-
-void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
- memnew_placement(r_output, Array);
-
- for (int i = 0; i < p_input->size(); ++i) {
- if (ClassDB::is_parent_class(((Object *)(*p_input)[i])->get_class(), *p_native_name)) {
- r_output->push_back(p_input[i]);
- }
- }
-}
-
-void godotsharp_array_filter_godot_objects_by_non_native(const Array *p_input, Array *r_output) {
- memnew_placement(r_output, Array);
-
- for (int i = 0; i < p_input->size(); ++i) {
- CSharpInstance *si = CAST_CSHARP_INSTANCE(((Object *)(*p_input)[i])->get_script_instance());
-
- if (si != nullptr) {
- r_output->push_back(p_input[i]);
- }
- }
-}
-
-void godot_register_placeholder_icalls() {
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::unmanaged_get_script_instance_managed",
- unmanaged_get_script_instance_managed);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::unmanaged_get_instance_binding_managed",
- unmanaged_get_instance_binding_managed);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::unmanaged_instance_binding_create_managed",
- unmanaged_instance_binding_create_managed);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_tie_native_managed_to_unmanaged",
- godot_icall_InteropUtils_tie_native_managed_to_unmanaged);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_tie_user_managed_to_unmanaged",
- godot_icall_InteropUtils_tie_user_managed_to_unmanaged);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged_with_pre_setup",
- godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_new_csharp_script",
- godot_icall_InteropUtils_internal_new_csharp_script);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_native",
- godotsharp_array_filter_godot_objects_by_native);
- GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_non_native",
- godotsharp_array_filter_godot_objects_by_non_native);
-}
-
-#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 29d373e885..14e638d163 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,7 +37,9 @@
#include "../interop_types.h"
+#include "modules/mono/csharp_script.h"
#include "modules/mono/managed_callable.h"
+#include "modules/mono/mono_gd/gd_mono_cache.h"
#include "modules/mono/signal_awaiter_utils.h"
#ifdef __cplusplus
@@ -75,14 +77,225 @@ GD_PINVOKE_EXPORT godotsharp_class_creation_func godotsharp_get_class_constructo
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_internal_object_disposed(Object *p_ptr) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+#endif
+
+ if (p_ptr->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ cs_instance->mono_object_disposed();
+ p_ptr->set_script_instance(nullptr);
+ }
+ return;
+ }
+ }
+
+ void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ if (!gchandle.is_released()) {
+ CSharpLanguage::release_script_gchandle(nullptr, gchandle);
+ script_binding.inited = false;
+ }
+ }
+ }
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, bool p_is_finalizer) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+ // This is only called with RefCounted derived classes
+ CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
+#endif
+
+ RefCounted *rc = static_cast<RefCounted *>(p_ptr);
+
+ if (rc->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ bool delete_owner;
+ bool remove_script_instance;
+
+ cs_instance->mono_object_disposed_baseref(p_is_finalizer, delete_owner, remove_script_instance);
+
+ if (delete_owner) {
+ memdelete(rc);
+ } else if (remove_script_instance) {
+ rc->set_script_instance(nullptr);
+ }
+ }
+ return;
+ }
+ }
+
+ // Unsafe refcount decrement. The managed instance also counts as a reference.
+ // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
+ CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc);
+ if (rc->unreference()) {
+ memdelete(rc);
+ } else {
+ void *data = CSharpLanguage::get_existing_instance_binding(rc);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ if (!gchandle.is_released()) {
+ CSharpLanguage::release_script_gchandle(nullptr, gchandle);
+ script_binding.inited = false;
+ }
+ }
+ }
+ }
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_object_connect_event_signal(Object *p_ptr, const StringName *p_event_signal) {
+ CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (csharp_instance) {
+ csharp_instance->connect_event_signal(*p_event_signal);
+ }
+}
+
+GD_PINVOKE_EXPORT int32_t godotsharp_internal_signal_awaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
+ StringName signal = p_signal ? *p_signal : StringName();
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
+}
+
+GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_get_script_instance_managed(Object *p_unmanaged, bool *r_has_cs_script_instance) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+ CRASH_COND(!r_has_cs_script_instance);
+#endif
+
+ if (p_unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ *r_has_cs_script_instance = true;
+ return cs_instance->get_gchandle_intptr();
+ }
+ }
+
+ *r_has_cs_script_instance = false;
+ return GCHandleIntPtr();
+}
+
+GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ return script_binding.gchandle.get_intptr();
+}
+
+GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(Object *p_unmanaged, GCHandleIntPtr p_old_gchandle) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+
+ // TODO: Possible data race?
+ CRASH_COND(gchandle.get_intptr().value != p_old_gchandle.value);
+
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ script_binding.inited = false;
+
+ // Create a new one
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(script_binding.type_name == StringName());
+#endif
+
+ bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, GCHandleIntPtr(),
+ "Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
+
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding(
+ &script_binding.type_name, p_unmanaged);
+
+ ERR_FAIL_NULL_V(strong_gchandle.value, GCHandleIntPtr());
+
+ gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
+ script_binding.inited = true;
+
+ // Tie managed to unmanaged
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
+
+ if (rc) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
+ }
+
+ return gchandle.get_intptr();
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
+ CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
+}
+
+GD_PINVOKE_EXPORT void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
+}
+
+GD_PINVOKE_EXPORT CSharpScript *godotsharp_internal_new_csharp_script() {
+ CSharpScript *script = memnew(CSharpScript);
+ CRASH_COND(!script);
+ return script;
+}
+
+GD_PINVOKE_EXPORT void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ if (ClassDB::is_parent_class(((Object *)(*p_input)[i])->get_class(), *p_native_name)) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
+GD_PINVOKE_EXPORT void godotsharp_array_filter_godot_objects_by_non_native(const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ CSharpInstance *si = CAST_CSHARP_INSTANCE(((Object *)(*p_input)[i])->get_script_instance());
+
+ if (si != nullptr) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
GD_PINVOKE_EXPORT void godotsharp_ref_destroy(Ref<RefCounted> *p_instance) {
p_instance->~Ref();
}
@@ -1003,8 +1216,8 @@ GD_PINVOKE_EXPORT void godotsharp_convert(const godot_variant *p_what, int32_t p
if (ce.error != Callable::CallError::CALL_OK) {
memnew_placement(r_ret, Variant);
ERR_FAIL_MSG("Unable to convert parameter from '" +
- Variant::get_type_name(reinterpret_cast<const Variant *>(p_what)->get_type()) +
- "' to '" + Variant::get_type_name(Variant::Type(p_type)) + "'.");
+ Variant::get_type_name(reinterpret_cast<const Variant *>(p_what)->get_type()) +
+ "' to '" + Variant::get_type_name(Variant::Type(p_type)) + "'.");
}
memnew_placement(r_ret, Variant(ret));
}
@@ -1028,11 +1241,23 @@ GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string *
#endif
// We need this to prevent the functions from being stripped.
-void *godotsharp_pinvoke_funcs[164] = {
+void *godotsharp_pinvoke_funcs[176] = {
(void *)godotsharp_method_bind_get_method,
(void *)godotsharp_get_class_constructor,
- (void *)godotsharp_invoke_class_constructor,
(void *)godotsharp_engine_get_singleton,
+ (void *)godotsharp_internal_object_disposed,
+ (void *)godotsharp_internal_refcounted_disposed,
+ (void *)godotsharp_internal_object_connect_event_signal,
+ (void *)godotsharp_internal_signal_awaiter_connect,
+ (void *)godotsharp_internal_unmanaged_get_script_instance_managed,
+ (void *)godotsharp_internal_unmanaged_get_instance_binding_managed,
+ (void *)godotsharp_internal_unmanaged_instance_binding_create_managed,
+ (void *)godotsharp_internal_tie_native_managed_to_unmanaged,
+ (void *)godotsharp_internal_tie_user_managed_to_unmanaged,
+ (void *)godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup,
+ (void *)godotsharp_internal_new_csharp_script,
+ (void *)godotsharp_array_filter_godot_objects_by_native,
+ (void *)godotsharp_array_filter_godot_objects_by_non_native,
(void *)godotsharp_ref_destroy,
(void *)godotsharp_string_name_new_from_string,
(void *)godotsharp_node_path_new_from_string,
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index e01d0c6e18..a1f94aa590 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -32,7 +32,6 @@
#include "csharp_script.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_utils.h"
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable>::List ManagedCallable::instances;
@@ -52,12 +51,8 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus
}
// Call Delegate's 'Equals'
- MonoException *exc = nullptr;
- MonoBoolean res = GDMonoCache::cached_data.methodthunk_DelegateUtils_DelegateEquals
- .invoke(a->delegate_handle,
- b->delegate_handle, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
+ return GDMonoCache::managed_callbacks.DelegateUtils_DelegateEquals(
+ a->delegate_handle, b->delegate_handle);
}
bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -92,27 +87,15 @@ 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();
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_DelegateUtils_InvokeWithVariantArgs
- .invoke(delegate_handle, p_arguments,
- p_argcount, &r_return_value, &exc);
+ GDMonoCache::managed_callbacks.DelegateUtils_InvokeWithVariantArgs(
+ delegate_handle, p_arguments, p_argcount, &r_return_value);
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- } else {
- r_call_error.error = Callable::CallError::CALL_OK;
- }
+ r_call_error.error = Callable::CallError::CALL_OK;
}
void ManagedCallable::release_delegate_handle() {
if (delegate_handle.value) {
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.invoke(delegate_handle, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- }
-
+ GDMonoCache::managed_callbacks.GCHandleBridge_FreeGCHandle(delegate_handle);
delegate_handle = GCHandleIntPtr();
}
}
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index d0f6362d42..aa3344f4d5 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -31,8 +31,6 @@
#ifndef MANAGED_CALLABLE_H
#define MANAGED_CALLABLE_H
-#include <mono/metadata/object.h>
-
#include "core/os/mutex.h"
#include "core/templates/self_list.h"
#include "core/variant/callable.h"
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index f0a48483f6..9cf0a641b9 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -38,17 +38,13 @@ void MonoGCHandleData::release() {
CRASH_COND(handle.value && GDMono::get_singleton() == nullptr);
#endif
- if (handle.value && !GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.is_null() &&
+ if (handle.value && GDMonoCache::godot_api_cache_updated &&
GDMono::get_singleton()->is_runtime_initialized()) {
free_gchandle(handle);
handle.value = nullptr;
}
}
void MonoGCHandleData::free_gchandle(GCHandleIntPtr p_gchandle) {
- CRASH_COND(GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.is_null());
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.invoke(p_gchandle, &exc);
- if (exc) {
- GDMonoUtils::debug_unhandled_exception(exc);
- }
+ CRASH_COND(!GDMonoCache::godot_api_cache_updated);
+ GDMonoCache::managed_callbacks.GCHandleBridge_FreeGCHandle(p_gchandle);
}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index 96553cf4f4..a921b24103 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,9 +42,11 @@ enum class GCHandleType : char {
};
}
+extern "C" {
struct GCHandleIntPtr {
void *value = nullptr;
};
+}
static_assert(sizeof(GCHandleIntPtr) == sizeof(void *));
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index ce4fc0c5a0..dcda799f32 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -30,13 +30,6 @@
#include "gd_mono.h"
-#include <mono/metadata/environment.h>
-#include <mono/metadata/exception.h>
-#include <mono/metadata/mono-config.h>
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-gc.h>
-#include <mono/metadata/profiler.h>
-
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/dir_access.h"
@@ -48,61 +41,28 @@
#include "../godotsharp_dirs.h"
#include "../utils/path_utils.h"
#include "gd_mono_cache.h"
-#include "gd_mono_utils.h"
+#include <nethost.h>
+
+#include <coreclr_delegates.h>
+#include <hostfxr.h>
+
+#warning TODO mobile
+#if 0
#ifdef ANDROID_ENABLED
#include "android_mono_config.h"
#include "support/android_support.h"
#elif defined(IOS_ENABLED)
#include "support/ios_support.h"
#endif
-
-#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN)
-// This will no longer be the case if we replace appdomains with AssemblyLoadContext
-#error "Editor build requires support for multiple appdomains"
-#endif
-
-#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN)
-#error "Hot reloading requires multiple appdomains"
#endif
-// TODO:
-// This has turned into a gigantic mess. There's too much going on here. Too much #ifdef as well.
-// It's just painful to read... It needs to be re-structured. Please, clean this up, future me.
-
GDMono *GDMono::singleton = nullptr;
namespace {
-#if defined(JAVASCRIPT_ENABLED)
-extern "C" {
-void mono_wasm_load_runtime(const char *managed_path, int enable_debugging);
-}
-#endif
-
-#if !defined(JAVASCRIPT_ENABLED)
-
-void gd_mono_setup_runtime_main_args() {
- CharString execpath = OS::get_singleton()->get_executable_path().utf8();
-
- List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
-
- List<CharString> cmdline_args_utf8;
- Vector<char *> main_args;
- main_args.resize(cmdline_args.size() + 1);
-
- main_args.write[0] = execpath.ptrw();
-
- int i = 1;
- for (const String &E : cmdline_args) {
- CharString &stored = cmdline_args_utf8.push_back(E.utf8())->get();
- main_args.write[i] = stored.ptrw();
- i++;
- }
-
- mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
-}
-
+#warning "TODO .NET debugging and profiling. What's needed?"
+#if 0
void gd_mono_profiler_init() {
String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
@@ -165,258 +125,193 @@ void gd_mono_debug_init() {
};
mono_jit_parse_options(2, (char **)options);
}
-
-#endif // !defined(JAVASCRIPT_ENABLED)
-
-#if defined(JAVASCRIPT_ENABLED)
-MonoDomain *gd_initialize_mono_runtime() {
- const char *vfs_prefix = "managed";
- int enable_debugging = 0;
-
- // TODO: Provide a way to enable debugging on WASM release builds.
-#ifdef DEBUG_ENABLED
- enable_debugging = 1;
#endif
+} // namespace
- mono_wasm_load_runtime(vfs_prefix, enable_debugging);
-
- return mono_get_root_domain();
-}
+namespace {
+hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr;
+hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr;
+hostfxr_close_fn hostfxr_close = nullptr;
+
+#ifdef _WIN32
+static_assert(sizeof(char_t) == sizeof(char16_t));
+using HostFxrCharString = Char16String;
+#define HOSTFXR_STR(m_str) L##m_str
#else
-MonoDomain *gd_initialize_mono_runtime() {
- gd_mono_debug_init();
+static_assert(sizeof(char_t) == sizeof(char));
+using HostFxrCharString = CharString;
+#define HOSTFXR_STR(m_str) m_str
+#endif
-#if defined(IOS_ENABLED) || defined(ANDROID_ENABLED)
- // I don't know whether this actually matters or not
- const char *runtime_version = "mobile";
+HostFxrCharString str_to_hostfxr(const String &p_str) {
+#ifdef _WIN32
+ return p_str.utf16();
#else
- const char *runtime_version = "v4.0.30319";
+ return p_str.utf8();
#endif
-
- return mono_jit_init_version("GodotEngine.RootDomain", runtime_version);
}
-#endif
-} // namespace
-void GDMono::add_mono_shared_libs_dir_to_path() {
- // TODO: Replace this with a mono_dl_fallback
+String str_from_hostfxr(const char_t *p_buffer) {
+#ifdef _WIN32
+ return String::utf16((const char16_t *)p_buffer);
+#else
+ return String::utf8((const char *)p_buffer);
+#endif
+}
- // By default Mono seems to search shared libraries in the following directories:
- // Current working directory, @executable_path@ and PATH
- // The parent directory of the image file (assembly where the dllimport method is declared)
- // @executable_path@/../lib
- // @executable_path@/../Libraries (__MACH__ only)
+const char_t *get_data(const HostFxrCharString &p_char_str) {
+ return (const char_t *)p_char_str.get_data();
+}
- // This does not work when embedding Mono unless we use the same directory structure.
- // To fix this we append the directory containing our shared libraries to PATH.
+String find_hostfxr() {
+ const int HostApiBufferTooSmall = 0x80008098;
-#if defined(WINDOWS_ENABLED) || defined(UNIX_ENABLED)
- String path_var("PATH");
- String path_value = OS::get_singleton()->get_environment(path_var);
+ size_t buffer_size = 0;
+ int rc = get_hostfxr_path(nullptr, &buffer_size, nullptr);
-#ifdef WINDOWS_ENABLED
- path_value += ';';
+ if (rc == HostApiBufferTooSmall) {
+ // Pre-allocate a large buffer for the path to hostfxr
+ Vector<char_t> buffer;
+ buffer.resize(buffer_size);
- String bundled_bin_dir = GodotSharpDirs::get_data_mono_bin_dir();
-#ifdef TOOLS_ENABLED
- if (DirAccess::exists(bundled_bin_dir)) {
- path_value += bundled_bin_dir;
- } else {
- path_value += mono_reg_info.bin_dir;
- }
-#else
- if (DirAccess::exists(bundled_bin_dir)) {
- path_value += bundled_bin_dir;
- }
-#endif // TOOLS_ENABLED
+ rc = get_hostfxr_path(buffer.ptrw(), &buffer_size, nullptr);
-#else
- path_value += ':';
+ if (rc != 0) {
+ return String();
+ }
- String bundled_lib_dir = GodotSharpDirs::get_data_mono_lib_dir();
- if (DirAccess::exists(bundled_lib_dir)) {
- path_value += bundled_lib_dir;
- } else {
- // TODO: Do we need to add the lib dir when using the system installed Mono on Unix platforms?
+ return str_from_hostfxr(buffer.ptr());
}
-#endif // WINDOWS_ENABLED
- OS::get_singleton()->set_environment(path_var, path_value);
-#endif // WINDOWS_ENABLED || UNIX_ENABLED
+ return String();
}
-void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir) {
- String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir();
- String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir();
-
-#ifdef TOOLS_ENABLED
-
-#if defined(WINDOWS_ENABLED)
- mono_reg_info = MonoRegUtils::find_mono();
+// Forward declarations
+bool load_hostfxr() {
+ String hostfxr_path = find_hostfxr();
- if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
- r_assembly_rootdir = mono_reg_info.assembly_dir;
+ if (hostfxr_path.is_empty()) {
+ return false;
}
- if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
- r_config_dir = mono_reg_info.config_dir;
- }
-#elif defined(MACOS_ENABLED)
- const char *c_assembly_rootdir = mono_assembly_getrootdir();
- const char *c_config_dir = mono_get_config_dir();
-
- if (!c_assembly_rootdir || !c_config_dir || !DirAccess::exists(c_assembly_rootdir) || !DirAccess::exists(c_config_dir)) {
- Vector<const char *> locations;
- locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/");
- locations.push_back("/usr/local/var/homebrew/linked/mono/");
-
- for (int i = 0; i < locations.size(); i++) {
- String hint_assembly_rootdir = path::join(locations[i], "lib");
- String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
- String hint_config_dir = path::join(locations[i], "etc");
-
- if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
- r_assembly_rootdir = hint_assembly_rootdir;
- r_config_dir = hint_config_dir;
- break;
- }
- }
- }
-#endif
+ print_verbose("Found hostfxr: " + hostfxr_path);
- if (DirAccess::exists(bundled_assembly_rootdir)) {
- r_assembly_rootdir = bundled_assembly_rootdir;
- }
+ void *lib = nullptr;
+ Error err = OS::get_singleton()->open_dynamic_library(hostfxr_path, lib);
+ // TODO: Clean up lib handle when shutting down
- if (DirAccess::exists(bundled_config_dir)) {
- r_config_dir = bundled_config_dir;
+ if (err != OK) {
+ return false;
}
-#ifdef WINDOWS_ENABLED
- if (r_assembly_rootdir.is_empty() || r_config_dir.is_empty()) {
- ERR_PRINT("Cannot find Mono in the registry.");
- // Assertion: if they are not set, then they weren't found in the registry
- CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
- }
-#endif // WINDOWS_ENABLED
+ void *symbol = nullptr;
-#else
- // Export templates always use the bundled directories
- r_assembly_rootdir = bundled_assembly_rootdir;
- r_config_dir = bundled_config_dir;
-#endif
-}
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_initialize_for_runtime_config", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)symbol;
-void GDMono::initialize() {
- ERR_FAIL_NULL(Engine::get_singleton());
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_get_runtime_delegate", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)symbol;
- print_verbose("Mono: Initializing module...");
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_close", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_close = (hostfxr_close_fn)symbol;
- char *runtime_build_info = mono_get_runtime_build_info();
- print_verbose("Mono JIT compiler version " + String(runtime_build_info));
- mono_free(runtime_build_info);
+ return (hostfxr_initialize_for_runtime_config &&
+ hostfxr_get_runtime_delegate &&
+ hostfxr_close);
+}
- _init_godot_api_hashes();
- _init_exception_policy();
+load_assembly_and_get_function_pointer_fn initialize_hostfxr(const char_t *p_config_path) {
+ hostfxr_handle cxt = nullptr;
+ int rc = hostfxr_initialize_for_runtime_config(p_config_path, nullptr, &cxt);
+ if (rc != 0 || cxt == nullptr) {
+ hostfxr_close(cxt);
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_initialize_for_runtime_config failed");
+ }
- GDMonoLog::get_singleton()->initialize();
+ void *load_assembly_and_get_function_pointer = nullptr;
-#if !defined(JAVASCRIPT_ENABLED)
- String assembly_rootdir;
- String config_dir;
- determine_mono_dirs(assembly_rootdir, config_dir);
+ rc = hostfxr_get_runtime_delegate(cxt,
+ hdt_load_assembly_and_get_function_pointer, &load_assembly_and_get_function_pointer);
+ if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) {
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_get_runtime_delegate failed");
+ }
- // Leak if we call mono_set_dirs more than once
- mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : nullptr,
- config_dir.length() ? config_dir.utf8().get_data() : nullptr);
+ hostfxr_close(cxt);
- add_mono_shared_libs_dir_to_path();
-#endif
+ return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
+}
+} // namespace
-#ifdef ANDROID_ENABLED
- mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
-#else
- mono_config_parse(nullptr);
-#endif
+static bool _on_core_api_assembly_loaded() {
+ if (!GDMonoCache::godot_api_cache_updated) {
+ return false;
+ }
-#if defined(ANDROID_ENABLED)
- gdmono::android::support::initialize();
-#elif defined(IOS_ENABLED)
- gdmono::ios::support::initialize();
+ GDMonoCache::managed_callbacks.Dispatcher_InitializeDefaultGodotTaskScheduler();
+
+#ifdef DEBUG_ENABLED
+ // Install the trace listener now before the project assembly is loaded
+ GDMonoCache::managed_callbacks.DebuggingUtils_InstallTraceListener();
#endif
- GDMonoAssembly::initialize();
+ return true;
+}
-#if !defined(JAVASCRIPT_ENABLED)
- gd_mono_profiler_init();
-#endif
+void GDMono::initialize() {
+ ERR_FAIL_NULL(Engine::get_singleton());
- mono_install_unhandled_exception_hook(&unhandled_exception_hook, nullptr);
+ print_verbose(".NET: Initializing module...");
-#ifndef TOOLS_ENABLED
- // Exported games that don't use C# must still work. They likely don't ship with mscorlib.
- // We only initialize the Mono runtime if we can find mscorlib. Otherwise it would crash.
- if (GDMonoAssembly::find_assembly("mscorlib.dll").is_empty()) {
- print_verbose("Mono: Skipping runtime initialization because 'mscorlib.dll' could not be found");
- return;
- }
-#endif
+ _init_godot_api_hashes();
-#if !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND)
- // FIXME: Temporary workaround. See: https://github.com/godotengine/godot/issues/29812
- if (!OS::get_singleton()->has_environment("MONO_THREADS_SUSPEND")) {
- OS::get_singleton()->set_environment("MONO_THREADS_SUSPEND", "preemptive");
+ if (!load_hostfxr()) {
+ ERR_FAIL_MSG(".NET: Failed to load hostfxr");
}
-#endif
- // NOTE: Internal calls must be registered after the Mono runtime initialization.
- // Otherwise registration fails with the error: 'assertion 'hash != nullptr' failed'.
+ auto config_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
+ .plus_file("GodotPlugins.runtimeconfig.json"));
- root_domain = gd_initialize_mono_runtime();
- ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
+ load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
+ initialize_hostfxr(get_data(config_path));
+ ERR_FAIL_NULL(load_assembly_and_get_function_pointer);
- GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
+ runtime_initialized = true;
-#if !defined(JAVASCRIPT_ENABLED)
- gd_mono_setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs
-#endif
+ print_verbose(".NET: hostfxr initialized");
- runtime_initialized = true;
+ auto godot_plugins_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
+ .plus_file("GodotPlugins.dll"));
- print_verbose("Mono: Runtime initialized");
+ using godot_plugins_initialize_fn = bool (*)(bool, PluginCallbacks *, GDMonoCache::ManagedCallbacks *);
+ godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
-#if defined(ANDROID_ENABLED)
- gdmono::android::support::register_internal_calls();
-#endif
+ int rc = load_assembly_and_get_function_pointer(get_data(godot_plugins_path),
+ HOSTFXR_STR("GodotPlugins.Main, GodotPlugins"),
+ HOSTFXR_STR("Initialize"),
+ UNMANAGEDCALLERSONLY_METHOD,
+ nullptr,
+ (void **)&godot_plugins_initialize);
+ ERR_FAIL_COND_MSG(rc != 0, ".NET: Failed to get Godot.Plugins Initialize function pointer");
- // mscorlib assembly MUST be present at initialization
- bool corlib_loaded = _load_corlib_assembly();
- ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly.");
+ PluginCallbacks aux_plugin_callbacks;
+ GDMonoCache::ManagedCallbacks managed_callbacks;
+ bool init_ok = godot_plugins_initialize(Engine::get_singleton()->is_editor_hint(),
+ &aux_plugin_callbacks, &managed_callbacks);
+ ERR_FAIL_COND_MSG(!init_ok, ".NET: Call to Godot.Plugins Initialize failed");
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- Error domain_load_err = _load_scripts_domain();
- ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
-#else
- scripts_domain = root_domain;
-#endif
+ GDMonoCache::update_godot_api_cache(managed_callbacks);
+ plugin_callbacks = aux_plugin_callbacks;
- _register_internal_calls();
+ print_verbose(".NET: GodotPlugins initialized");
- print_verbose("Mono: INITIALIZED");
+ _on_core_api_assembly_loaded();
}
void GDMono::initialize_load_assemblies() {
- // Load assemblies. The API and tools assemblies are required,
- // the application is aborted if these assemblies cannot be loaded.
-
- if (!_try_load_api_assemblies()) {
- CRASH_NOW_MSG("Failed to load one of the API assemblies.");
- }
-
#if defined(TOOLS_ENABLED)
- bool tool_assemblies_loaded = _load_tools_assemblies();
- CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
-
if (Engine::get_singleton()->is_project_manager_hint()) {
return;
}
@@ -427,20 +322,11 @@ void GDMono::initialize_load_assemblies() {
// we're running in the editor, it may just happen to be it wasn't built yet.
if (!_load_project_assembly()) {
if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load project assembly");
+ print_error(".NET: Failed to load project assembly");
}
}
}
-void godot_register_object_icalls();
-void godot_register_placeholder_icalls();
-
-void GDMono::_register_internal_calls() {
- // Registers internal calls that were not generated.
- godot_register_object_icalls();
- godot_register_placeholder_icalls();
-}
-
void GDMono::_init_godot_api_hashes() {
#ifdef DEBUG_METHODS_ENABLED
get_api_core_hash();
@@ -451,216 +337,22 @@ void GDMono::_init_godot_api_hashes() {
#endif // DEBUG_METHODS_ENABLED
}
-void GDMono::_init_exception_policy() {
- PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/runtime/unhandled_exception_policy", PROPERTY_HINT_ENUM,
- vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR));
- unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP);
- ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop);
-
- if (Engine::get_singleton()->is_editor_hint()) {
- // Unhandled exceptions should not terminate the editor
- unhandled_exception_policy = POLICY_LOG_ERROR;
- }
-}
-
-void GDMono::add_assembly(int32_t p_domain_id, GDMonoAssembly *p_assembly) {
- assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
-}
-
-GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) {
- if (p_name == "mscorlib" && corlib_assembly) {
- return corlib_assembly;
- }
-
- MonoDomain *domain = mono_domain_get();
- int32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
- GDMonoAssembly **result = assemblies[domain_id].getptr(p_name);
- return result ? *result : nullptr;
-}
-
-bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
-#endif
-
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- bool result = load_assembly(p_name, aname, r_assembly);
- mono_assembly_name_free(aname);
- mono_free(aname);
-
- return result;
-}
-
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
-#endif
-
- return load_assembly(p_name, p_aname, r_assembly, GDMonoAssembly::get_default_search_dirs());
-}
-
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, const Vector<String> &p_search_dirs) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
-#endif
-
- print_verbose("Mono: Loading assembly " + p_name + "...");
-
- GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, /* refonly: */ false, p_search_dirs);
-
- if (!assembly) {
- return false;
- }
-
- *r_assembly = assembly;
-
- print_verbose("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path());
-
- return true;
-}
-
-bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly) {
- CRASH_COND(!r_assembly);
-
- print_verbose("Mono: Loading assembly " + p_name + "...");
-
- GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, /* refonly: */ false);
-
- if (!assembly) {
- return false;
- }
-
- *r_assembly = assembly;
-
- print_verbose("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path());
-
- return true;
-}
-
-bool GDMono::_load_corlib_assembly() {
- if (corlib_assembly) {
- return true;
- }
-
- return load_assembly("mscorlib", &corlib_assembly);
-}
-
-bool GDMono::_load_core_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config) {
- if (*r_loaded_api_assembly) {
- return true;
- }
-
- return load_assembly(CORE_API_ASSEMBLY_NAME, r_loaded_api_assembly);
-}
-
-#ifdef TOOLS_ENABLED
-bool GDMono::_load_editor_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config) {
- if (*r_loaded_api_assembly) {
- return true;
- }
-
- return load_assembly(EDITOR_API_ASSEMBLY_NAME, r_loaded_api_assembly);
-}
-#endif
-
-bool GDMono::_try_load_api_assemblies() {
- String config = get_expected_api_build_config();
-
- if (!_load_core_api_assembly(&core_api_assembly, config)) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load Core API assembly");
- }
- return false;
- }
-
-#ifdef TOOLS_ENABLED
- if (!_load_editor_api_assembly(&editor_api_assembly, config)) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load Editor API assembly");
- }
- return false;
- }
-#endif
-
- return _on_core_api_assembly_loaded();
-}
-
-bool GDMono::_on_core_api_assembly_loaded() {
- GDMonoCache::update_godot_api_cache();
-
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
- return false;
- }
-
- get_singleton()->_install_trace_listener();
-
- return true;
-}
-
-#ifdef TOOLS_ENABLED
-bool GDMono::_load_tools_assemblies() {
- if (tools_assembly && tools_project_editor_assembly) {
- return true;
- }
-
- return load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
- load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
-}
-#endif
-
bool GDMono::_load_project_assembly() {
- if (project_assembly) {
- return true;
- }
-
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
if (appname_safe.is_empty()) {
appname_safe = "UnnamedProject";
}
- bool success = load_assembly(appname_safe, &project_assembly);
+ String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
+ .plus_file(appname_safe + ".dll");
+ assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
- if (success) {
- mono_assembly_set_main(project_assembly->get_assembly());
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_LookupScriptsInAssembly.invoke(
- mono_assembly_get_object(mono_domain_get(), project_assembly->get_assembly()), &exc);
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- }
- }
-
- return success;
-}
-
-void GDMono::_install_trace_listener() {
-#ifdef DEBUG_ENABLED
- // Install the trace listener now before the project assembly is loaded
- MonoException *exc = nullptr;
- GDMonoCache::cached_data.methodthunk_DebuggingUtils_InstallTraceListener.invoke(&exc);
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
- }
-#endif
-}
-
-#ifndef GD_MONO_SINGLE_APPDOMAIN
-Error GDMono::_load_scripts_domain() {
- ERR_FAIL_COND_V(scripts_domain != nullptr, ERR_BUG);
-
- print_verbose("Mono: Loading scripts domain...");
-
- scripts_domain = GDMonoUtils::create_domain("GodotEngine.Domain.Scripts");
-
- ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
-
- mono_domain_set(scripts_domain, true);
-
- return OK;
+ return plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16());
}
+#warning TODO hot-reload
+#if 0
Error GDMono::_unload_scripts_domain() {
ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
@@ -682,10 +374,6 @@ Error GDMono::_unload_scripts_domain() {
mono_gc_collect(mono_gc_max_generation());
- GDMonoCache::clear_godot_api_cache();
-
- _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
-
core_api_assembly = nullptr;
#ifdef TOOLS_ENABLED
editor_api_assembly = nullptr;
@@ -694,7 +382,6 @@ Error GDMono::_unload_scripts_domain() {
project_assembly = nullptr;
#ifdef TOOLS_ENABLED
tools_assembly = nullptr;
- tools_project_editor_assembly = nullptr;
#endif
MonoDomain *domain = scripts_domain;
@@ -713,7 +400,6 @@ Error GDMono::_unload_scripts_domain() {
return OK;
}
-#endif
#ifdef GD_MONO_HOT_RELOAD
Error GDMono::reload_scripts_domain() {
@@ -750,51 +436,10 @@ Error GDMono::reload_scripts_domain() {
return OK;
}
#endif
-
-#ifndef GD_MONO_SINGLE_APPDOMAIN
-Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
- CRASH_COND(p_domain == nullptr);
- CRASH_COND(p_domain == GDMono::get_singleton()->get_scripts_domain()); // Should use _unload_scripts_domain() instead
-
- String domain_name = mono_domain_get_friendly_name(p_domain);
-
- print_verbose("Mono: Unloading domain '" + domain_name + "'...");
-
- if (mono_domain_get() == p_domain) {
- mono_domain_set(root_domain, true);
- }
-
- if (!mono_domain_finalize(p_domain, 2000)) {
- ERR_PRINT("Mono: Domain finalization timeout.");
- }
-
- mono_gc_collect(mono_gc_max_generation());
-
- _domain_assemblies_cleanup(mono_domain_get_id(p_domain));
-
- MonoException *exc = nullptr;
- mono_domain_try_unload(p_domain, (MonoObject **)&exc);
-
- if (exc) {
- ERR_PRINT("Exception thrown when unloading domain '" + domain_name + "'.");
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return FAILED;
- }
-
- return OK;
-}
#endif
-void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- memdelete(E.value);
- }
-
- assemblies.erase(p_domain_id);
-}
-
+#warning TODO Reimplement in C#
+#if 0
void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
// This method will be called by the runtime when a thrown exception is not handled.
// It won't be called when we manually treat a thrown exception as unhandled.
@@ -811,89 +456,37 @@ void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
GD_UNREACHABLE();
}
+#endif
GDMono::GDMono() {
singleton = this;
- gdmono_log = memnew(GDMonoLog);
-
runtime_initialized = false;
finalizing_scripts_domain = false;
- root_domain = nullptr;
- scripts_domain = nullptr;
-
- corlib_assembly = nullptr;
- project_assembly = nullptr;
-#ifdef TOOLS_ENABLED
- tools_assembly = nullptr;
- tools_project_editor_assembly = nullptr;
-#endif
-
api_core_hash = 0;
#ifdef TOOLS_ENABLED
api_editor_hash = 0;
#endif
-
- unhandled_exception_policy = POLICY_TERMINATE_APP;
}
GDMono::~GDMono() {
if (is_runtime_initialized()) {
-#ifndef GD_MONO_SINGLE_APPDOMAIN
+#warning "TODO assembly unloading for cleanup of disposables (including managed RefCounteds)"
+#if 0
if (scripts_domain) {
Error err = _unload_scripts_domain();
if (err != OK) {
ERR_PRINT("Mono: Failed to unload scripts domain.");
}
}
-#else
- CRASH_COND(scripts_domain != root_domain);
-
- print_verbose("Mono: Finalizing scripts domain...");
-
- if (mono_domain_get() != root_domain) {
- mono_domain_set(root_domain, true);
- }
-
- finalizing_scripts_domain = true;
-
- if (!mono_domain_finalize(root_domain, 2000)) {
- ERR_PRINT("Mono: Domain finalization timeout.");
- }
-
- finalizing_scripts_domain = false;
-
- mono_gc_collect(mono_gc_max_generation());
-
- GDMonoCache::clear_godot_api_cache();
-
- _domain_assemblies_cleanup(mono_domain_get_id(root_domain));
-
- core_api_assembly.assembly = nullptr;
-
- project_assembly = nullptr;
-
- root_domain = nullptr;
- scripts_domain = nullptr;
-
- // Leave the rest to 'mono_jit_cleanup'
-#endif
-
- for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) {
- const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value;
-
- for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) {
- memdelete(F.value);
- }
- }
- assemblies.clear();
print_verbose("Mono: Runtime cleanup...");
mono_jit_cleanup(root_domain);
print_verbose("Mono: Finalized");
+#endif
runtime_initialized = false;
}
@@ -902,10 +495,6 @@ GDMono::~GDMono() {
gdmono::android::support::cleanup();
#endif
- if (gdmono_log) {
- memdelete(gdmono_log);
- }
-
singleton = nullptr;
}
@@ -913,62 +502,7 @@ namespace mono_bind {
GodotSharp *GodotSharp::singleton = nullptr;
-void GodotSharp::attach_thread() {
- GDMonoUtils::attach_current_thread();
-}
-
-void GodotSharp::detach_thread() {
- GDMonoUtils::detach_current_thread();
-}
-
-int32_t GodotSharp::get_domain_id() {
- MonoDomain *domain = mono_domain_get();
- ERR_FAIL_NULL_V(domain, -1);
- return mono_domain_get_id(domain);
-}
-
-int32_t GodotSharp::get_scripts_domain_id() {
- ERR_FAIL_NULL_V_MSG(GDMono::get_singleton(),
- -1, "The Mono runtime is not initialized");
- MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain();
- ERR_FAIL_NULL_V(domain, -1);
- return mono_domain_get_id(domain);
-}
-
-bool GodotSharp::is_scripts_domain_loaded() {
- return GDMono::get_singleton() != nullptr &&
- GDMono::get_singleton()->is_runtime_initialized() &&
- GDMono::get_singleton()->get_scripts_domain() != nullptr;
-}
-
-bool GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
- return is_domain_finalizing_for_unload(p_domain_id);
-}
-
-bool GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
- return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
-}
-
-bool GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
- GDMono *gd_mono = GDMono::get_singleton();
-
- ERR_FAIL_COND_V_MSG(!gd_mono || !gd_mono->is_runtime_initialized(),
- false, "The Mono runtime is not initialized");
-
- ERR_FAIL_NULL_V(p_domain, true);
-
- if (p_domain == gd_mono->get_scripts_domain() && gd_mono->is_finalizing_scripts_domain()) {
- return true;
- }
-
- return mono_domain_is_unloading(p_domain);
-}
-
-bool GodotSharp::is_runtime_shutting_down() {
- return mono_runtime_is_shutting_down();
-}
-
-bool GodotSharp::is_runtime_initialized() {
+bool GodotSharp::_is_runtime_initialized() {
return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
}
@@ -984,16 +518,7 @@ void GodotSharp::_reload_assemblies(bool p_soft_reload) {
}
void GodotSharp::_bind_methods() {
- ClassDB::bind_method(D_METHOD("attach_thread"), &GodotSharp::attach_thread);
- ClassDB::bind_method(D_METHOD("detach_thread"), &GodotSharp::detach_thread);
-
- ClassDB::bind_method(D_METHOD("get_domain_id"), &GodotSharp::get_domain_id);
- ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &GodotSharp::get_scripts_domain_id);
- ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &GodotSharp::is_scripts_domain_loaded);
- ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &GodotSharp::_is_domain_finalizing_for_unload);
-
- ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &GodotSharp::is_runtime_shutting_down);
- ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::is_runtime_initialized);
+ ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized);
ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index ac99aecabd..fee1cab9c7 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -34,82 +34,35 @@
#include "core/io/config_file.h"
#include "../godotsharp_defs.h"
-#include "gd_mono_assembly.h"
-#include "gd_mono_log.h"
-
-#ifdef WINDOWS_ENABLED
-#include "../utils/mono_reg_utils.h"
-#endif
class GDMono {
-public:
- enum UnhandledExceptionPolicy {
- POLICY_TERMINATE_APP,
- POLICY_LOG_ERROR
- };
-
-private:
bool runtime_initialized;
bool finalizing_scripts_domain;
- UnhandledExceptionPolicy unhandled_exception_policy;
-
- MonoDomain *root_domain = nullptr;
- MonoDomain *scripts_domain = nullptr;
-
- HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies;
-
- GDMonoAssembly *corlib_assembly = nullptr;
- GDMonoAssembly *project_assembly = nullptr;
-#ifdef TOOLS_ENABLED
- GDMonoAssembly *tools_assembly = nullptr;
- GDMonoAssembly *tools_project_editor_assembly = nullptr;
-#endif
-
- GDMonoAssembly *core_api_assembly;
- GDMonoAssembly *editor_api_assembly;
-
- bool _load_core_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config);
-#ifdef TOOLS_ENABLED
- bool _load_editor_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config);
-#endif
-
- static bool _on_core_api_assembly_loaded();
-
- bool _load_corlib_assembly();
-#ifdef TOOLS_ENABLED
- bool _load_tools_assemblies();
-#endif
bool _load_project_assembly();
bool _try_load_api_assemblies();
- void _install_trace_listener();
-
- void _register_internal_calls();
-
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- Error _load_scripts_domain();
Error _unload_scripts_domain();
-#endif
-
- void _domain_assemblies_cleanup(int32_t p_domain_id);
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
#endif
void _init_godot_api_hashes();
- void _init_exception_policy();
-
- GDMonoLog *gdmono_log = nullptr;
-#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
- MonoRegInfo mono_reg_info;
+ friend class CSharpLanguage;
+#ifdef WIN32
+#define GD_CLR_STDCALL __stdcall
+#else
+#define GD_CLR_STDCALL
#endif
-
- void add_mono_shared_libs_dir_to_path();
- void determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir);
+ struct PluginCallbacks {
+ using FuncLoadProjectAssemblyCallback = bool(GD_CLR_STDCALL *)(const char16_t *);
+ using FuncLoadToolsAssemblyCallback = Object *(GD_CLR_STDCALL *)(const char16_t *);
+ FuncLoadProjectAssemblyCallback LoadProjectAssemblyCallback = nullptr;
+ FuncLoadToolsAssemblyCallback LoadToolsAssemblyCallback = nullptr;
+ } plugin_callbacks;
protected:
static GDMono *singleton;
@@ -146,42 +99,13 @@ public:
static GDMono *get_singleton() { return singleton; }
- [[noreturn]] static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
-
- UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; }
-
- // Do not use these, unless you know what you're doing
- void add_assembly(int32_t p_domain_id, GDMonoAssembly *p_assembly);
- GDMonoAssembly *get_loaded_assembly(const String &p_name);
-
- _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; }
-
+ _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; }
_FORCE_INLINE_ bool is_finalizing_scripts_domain() { return finalizing_scripts_domain; }
- _FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
-
- _FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
-#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
-#endif
-
-#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
- const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; }
-#endif
-
#ifdef GD_MONO_HOT_RELOAD
Error reload_scripts_domain();
#endif
- bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, const Vector<String> &p_search_dirs);
- bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly);
-
- Error finalize_and_unload_domain(MonoDomain *p_domain);
-
void initialize();
void initialize_load_assemblies();
@@ -189,52 +113,6 @@ public:
~GDMono();
};
-namespace gdmono {
-
-class ScopeDomain {
- MonoDomain *prev_domain = nullptr;
-
-public:
- ScopeDomain(MonoDomain *p_domain) {
- prev_domain = mono_domain_get();
- if (prev_domain != p_domain) {
- mono_domain_set(p_domain, false);
- } else {
- prev_domain = nullptr;
- }
- }
-
- ~ScopeDomain() {
- if (prev_domain) {
- mono_domain_set(prev_domain, false);
- }
- }
-};
-
-class ScopeExitDomainUnload {
- MonoDomain *domain = nullptr;
-
-public:
- ScopeExitDomainUnload(MonoDomain *p_domain) :
- domain(p_domain) {
- }
-
- ~ScopeExitDomainUnload() {
- if (domain) {
- GDMono::get_singleton()->finalize_and_unload_domain(domain);
- }
- }
-};
-} // namespace gdmono
-
-#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
- gdmono::ScopeDomain __gdmono__scope__domain__(m_mono_domain); \
- (void)__gdmono__scope__domain__;
-
-#define _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(m_mono_domain) \
- gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \
- (void)__gdmono__scope__exit__domain__unload__;
-
namespace mono_bind {
class GodotSharp : public Object {
@@ -242,9 +120,8 @@ class GodotSharp : public Object {
friend class GDMono;
- bool _is_domain_finalizing_for_unload(int32_t p_domain_id);
-
void _reload_assemblies(bool p_soft_reload);
+ bool _is_runtime_initialized();
protected:
static GodotSharp *singleton;
@@ -253,20 +130,6 @@ protected:
public:
static GodotSharp *get_singleton() { return singleton; }
- void attach_thread();
- void detach_thread();
-
- int32_t get_domain_id();
- int32_t get_scripts_domain_id();
-
- bool is_scripts_domain_loaded();
-
- bool is_domain_finalizing_for_unload(int32_t p_domain_id);
- bool is_domain_finalizing_for_unload(MonoDomain *p_domain);
-
- bool is_runtime_shutting_down();
- bool is_runtime_initialized();
-
GodotSharp();
~GodotSharp();
};
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
deleted file mode 100644
index 605216d331..0000000000
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*************************************************************************/
-/* gd_mono_assembly.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_assembly.h"
-
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/tokentype.h>
-
-#include "core/config/project_settings.h"
-#include "core/io/file_access.h"
-#include "core/io/file_access_pack.h"
-#include "core/os/os.h"
-#include "core/templates/list.h"
-
-#include "../godotsharp_dirs.h"
-#include "gd_mono.h"
-#include "gd_mono_cache.h"
-
-Vector<String> GDMonoAssembly::search_dirs;
-
-void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
- String framework_dir;
-
- if (!p_custom_bcl_dir.is_empty()) {
- framework_dir = p_custom_bcl_dir;
- } else if (mono_assembly_getrootdir()) {
- framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5");
- }
-
- if (!framework_dir.is_empty()) {
- r_search_dirs.push_back(framework_dir);
- r_search_dirs.push_back(framework_dir.plus_file("Facades"));
- }
-
-#if !defined(TOOLS_ENABLED)
- String data_game_assemblies_dir = GodotSharpDirs::get_data_game_assemblies_dir();
- if (!data_game_assemblies_dir.is_empty()) {
- r_search_dirs.push_back(data_game_assemblies_dir);
- }
-#endif
-
- if (p_custom_config.length()) {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config));
- } else {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
- }
-
- if (p_custom_config.is_empty()) {
- r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_dir());
- } else {
- String api_config = p_custom_config == "ExportRelease" ? "Release" : "Debug";
- r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_base_dir().plus_file(api_config));
- }
-
- r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_base_dir());
- r_search_dirs.push_back(OS::get_singleton()->get_resource_dir());
- r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
-
-#ifdef TOOLS_ENABLED
- r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir());
-#endif
-}
-
-// This is how these assembly loading hooks work:
-//
-// - The 'search' hook checks if the assembly has already been loaded, to avoid loading again.
-// - The 'preload' hook does the actual loading and is only called if the
-// 'search' hook didn't find the assembly in the list of loaded assemblies.
-// - The 'load' hook is called after the assembly has been loaded. Its job is to add the
-// assembly to the list of loaded assemblies so that the 'search' hook can look it up.
-
-void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, [[maybe_unused]] void *user_data) {
- String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
-
- MonoImage *image = mono_assembly_get_image(assembly);
-
- GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, image, assembly));
-
-#ifdef GD_MONO_HOT_RELOAD
- String path = String::utf8(mono_image_get_filename(image));
- if (FileAccess::exists(path)) {
- gdassembly->modified_time = FileAccess::get_modified_time(path);
- }
-#endif
-
- MonoDomain *domain = mono_domain_get();
- GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
- return GDMonoAssembly::_search_hook(aname, user_data, false);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) {
- return GDMonoAssembly::_search_hook(aname, user_data, true);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
- return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
- return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true);
-}
-
-MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, [[maybe_unused]] void *user_data, bool refonly) {
- String name = String::utf8(mono_assembly_name_get_name(aname));
- bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
- if (loaded_asm) {
- return loaded_asm->get_assembly();
- }
-
- return nullptr;
-}
-
-MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, [[maybe_unused]] void *user_data, bool refonly) {
- String name = String::utf8(mono_assembly_name_get_name(aname));
- return _load_assembly_search(name, aname, refonly, search_dirs);
-}
-
-MonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
- MonoAssembly *res = nullptr;
- String path;
-
- bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
-
- for (int i = 0; i < p_search_dirs.size(); i++) {
- const String &search_dir = p_search_dirs[i];
-
- if (has_extension) {
- path = search_dir.plus_file(p_name);
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
- } else {
- path = search_dir.plus_file(p_name + ".dll");
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
-
- path = search_dir.plus_file(p_name + ".exe");
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
- }
- }
-
- return nullptr;
-}
-
-String GDMonoAssembly::find_assembly(const String &p_name) {
- String path;
-
- bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
-
- for (int i = 0; i < search_dirs.size(); i++) {
- const String &search_dir = search_dirs[i];
-
- if (has_extension) {
- path = search_dir.plus_file(p_name);
- if (FileAccess::exists(path)) {
- return path;
- }
- } else {
- path = search_dir.plus_file(p_name + ".dll");
- if (FileAccess::exists(path)) {
- return path;
- }
-
- path = search_dir.plus_file(p_name + ".exe");
- if (FileAccess::exists(path)) {
- return path;
- }
- }
- }
-
- return String();
-}
-
-void GDMonoAssembly::initialize() {
- fill_search_dirs(search_dirs);
-
- mono_install_assembly_search_hook(&assembly_search_hook, nullptr);
- mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, nullptr);
- mono_install_assembly_preload_hook(&assembly_preload_hook, nullptr);
- mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, nullptr);
- mono_install_assembly_load_hook(&assembly_load_hook, nullptr);
-}
-
-MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname) {
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
- ERR_FAIL_COND_V_MSG(data.is_empty(), nullptr, "Could read the assembly in the specified location");
-
- String image_filename;
-
-#ifdef ANDROID_ENABLED
- if (p_path.begins_with("res://")) {
- image_filename = p_path.substr(6, p_path.length());
- } else {
- image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
- }
-#else
- // FIXME: globalize_path does not work on exported games
- image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
-#endif
-
- MonoImageOpenStatus status = MONO_IMAGE_OK;
-
- MonoImage *image = mono_image_open_from_data_with_name(
- (char *)&data[0], data.size(),
- true, &status, p_refonly,
- image_filename.utf8());
-
- ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !image, nullptr, "Failed to open assembly image from memory: '" + p_path + "'.");
-
- if (p_aname != nullptr) {
- // Check assembly version
- const MonoTableInfo *table = mono_image_get_table_info(image, MONO_TABLE_ASSEMBLY);
-
- ERR_FAIL_NULL_V(table, nullptr);
-
- if (mono_table_info_get_rows(table)) {
- uint32_t cols[MONO_ASSEMBLY_SIZE];
- mono_metadata_decode_row(table, 0, cols, MONO_ASSEMBLY_SIZE);
-
- // Not sure about .NET's policy. We will only ensure major and minor are equal, and ignore build and revision.
- uint16_t major = cols[MONO_ASSEMBLY_MAJOR_VERSION];
- uint16_t minor = cols[MONO_ASSEMBLY_MINOR_VERSION];
-
- uint16_t required_minor;
- uint16_t required_major = mono_assembly_name_get_version(p_aname, &required_minor, nullptr, nullptr);
-
- if (required_major != 0) {
- if (major != required_major && minor != required_minor) {
- mono_image_close(image);
- return nullptr;
- }
- }
- }
- }
-
-#ifdef DEBUG_ENABLED
- Vector<uint8_t> pdb_data;
- String pdb_path(p_path + ".pdb");
-
- if (!FileAccess::exists(pdb_path)) {
- pdb_path = p_path.get_basename() + ".pdb"; // without .dll
-
- if (!FileAccess::exists(pdb_path)) {
- goto no_pdb;
- }
- }
-
- pdb_data = FileAccess::get_file_as_array(pdb_path);
-
- // mono_debug_close_image doesn't seem to be needed
- mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
-
-no_pdb:
-
-#endif
-
- bool need_manual_load_hook = mono_image_get_assembly(image) != nullptr; // Re-using an existing image with an assembly loaded
-
- status = MONO_IMAGE_OK;
-
- MonoAssembly *assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, p_refonly);
-
- ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !assembly, nullptr, "Failed to load assembly for image");
-
- if (need_manual_load_hook) {
- // For some reason if an assembly survived domain reloading (maybe because it's referenced somewhere else),
- // the mono internal search hook don't detect it, yet mono_image_open_from_data_with_name re-uses the image
- // and assembly, and mono_assembly_load_from_full doesn't call the load hook. We need to call it manually.
- String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
- bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
- if (!loaded_asm) {
- assembly_load_hook(assembly, nullptr);
- }
- }
-
- // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name
- mono_image_close(image);
-
- return assembly;
-}
-
-void GDMonoAssembly::unload() {
- ERR_FAIL_NULL(image); // Should not be called if already unloaded
-
- assembly = nullptr;
- image = nullptr;
-}
-
-String GDMonoAssembly::get_path() const {
- return String::utf8(mono_image_get_filename(image));
-}
-
-GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
- if (GDMono::get_singleton()->get_corlib_assembly() && (p_name == "mscorlib" || p_name == "mscorlib.dll")) {
- return GDMono::get_singleton()->get_corlib_assembly();
- }
-
- // We need to manually call the search hook in this case, as it won't be called in the next step
- MonoAssembly *assembly = mono_assembly_invoke_search_hook(p_aname);
-
- if (!assembly) {
- assembly = _load_assembly_search(p_name, p_aname, p_refonly, p_search_dirs);
- if (!assembly) {
- return nullptr;
- }
- }
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
- ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?");
- ERR_FAIL_COND_V(loaded_asm->get_assembly() != assembly, nullptr);
-
- return loaded_asm;
-}
-
-GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
- if (p_name == "mscorlib" || p_name == "mscorlib.dll") {
- return GDMono::get_singleton()->get_corlib_assembly();
- }
-
- // We need to manually call the search hook in this case, as it won't be called in the next step
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- MonoAssembly *assembly = mono_assembly_invoke_search_hook(aname);
- mono_assembly_name_free(aname);
- mono_free(aname);
-
- if (!assembly) {
- assembly = _real_load_assembly_from(p_path, p_refonly);
- if (!assembly) {
- return nullptr;
- }
- }
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
- ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?");
-
- return loaded_asm;
-}
-
-GDMonoAssembly::~GDMonoAssembly() {
- if (image) {
- unload();
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
deleted file mode 100644
index f67a3e0f25..0000000000
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* gd_mono_assembly.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_ASSEMBLY_H
-#define GD_MONO_ASSEMBLY_H
-
-#include <mono/jit/jit.h>
-#include <mono/metadata/assembly.h>
-
-#include "core/string/ustring.h"
-#include "core/templates/hash_map.h"
-#include "core/templates/rb_map.h"
-#include "gd_mono_utils.h"
-
-class GDMonoAssembly {
- String name;
- MonoImage *image = nullptr;
- MonoAssembly *assembly = nullptr;
-
-#ifdef GD_MONO_HOT_RELOAD
- uint64_t modified_time = 0;
-#endif
-
- static Vector<String> search_dirs;
-
- static void assembly_load_hook(MonoAssembly *assembly, void *user_data);
- static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
- static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
-
- static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly);
- static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
-
- static MonoAssembly *_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname = nullptr);
- static MonoAssembly *_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs);
-
- friend class GDMono;
- static void initialize();
-
-public:
- void unload();
-
- _FORCE_INLINE_ MonoImage *get_image() const { return image; }
- _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
- _FORCE_INLINE_ String get_name() const { return name; }
-
-#ifdef GD_MONO_HOT_RELOAD
- _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
-#endif
-
- String get_path() const;
-
- static String find_assembly(const String &p_name);
-
- static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
- static const Vector<String> &get_default_search_dirs() { return search_dirs; }
-
- static GDMonoAssembly *load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs);
- static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
-
- GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly) :
- name(p_name),
- image(p_image),
- assembly(p_assembly) {
- }
- ~GDMonoAssembly();
-};
-
-#endif // GD_MONO_ASSEMBLY_H
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 37c8e7d021..17addfb49d 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -30,82 +30,47 @@
#include "gd_mono_cache.h"
-#include "gd_mono.h"
-#include "gd_mono_utils.h"
+#include "core/error/error_macros.h"
namespace GDMonoCache {
-CachedData cached_data;
-
-static MonoMethod *get_mono_method(MonoClass *p_mono_class, const char *p_method_name, int p_param_count) {
- ERR_FAIL_NULL_V(p_mono_class, nullptr);
- return mono_class_get_method_from_name(p_mono_class, p_method_name, p_param_count);
-}
-
-static MonoClass *get_mono_class(GDMonoAssembly *p_assembly, const char *p_namespace, const char *p_name) {
- ERR_FAIL_NULL_V(p_assembly->get_image(), nullptr);
- return mono_class_from_name(p_assembly->get_image(), p_namespace, p_name);
-}
-
-void update_godot_api_cache() {
-#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
- { \
- CRASH_COND(!m_var.is_null()); \
- val = m_val; \
- ERR_FAIL_COND_MSG(val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \
- m_var.set_from_method(val); \
- ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
- }
-
-#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val)
-
-#define GODOT_API_CLASS(m_class) (get_mono_class(GDMono::get_singleton()->get_core_api_assembly(), BINDINGS_NAMESPACE, #m_class))
-#define GODOT_API_BRIDGE_CLASS(m_class) (get_mono_class(GDMono::get_singleton()->get_core_api_assembly(), BINDINGS_NAMESPACE_BRIDGE, #m_class))
-
- MonoMethod *val = nullptr;
-
- CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, get_mono_method(GODOT_API_CLASS(SignalAwaiter), "SignalCallback", 4));
-
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, InvokeWithVariantArgs, get_mono_method(GODOT_API_CLASS(DelegateUtils), "InvokeWithVariantArgs", 4));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, DelegateEquals, get_mono_method(GODOT_API_CLASS(DelegateUtils), "DelegateEquals", 2));
-
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, FrameCallback, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "FrameCallback", 0));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, CreateManagedForGodotObjectBinding, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "CreateManagedForGodotObjectBinding", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, CreateManagedForGodotObjectScriptInstance, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "CreateManagedForGodotObjectScriptInstance", 4));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, GetScriptNativeName, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "GetScriptNativeName", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, LookupScriptsInAssembly, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "LookupScriptsInAssembly", 1));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, SetGodotObjectPtr, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "SetGodotObjectPtr", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, RaiseEventSignal, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "RaiseEventSignal", 5));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, GetScriptSignalList, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "GetScriptSignalList", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, HasScriptSignal, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "HasScriptSignal", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, HasMethodUnknownParams, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "HasMethodUnknownParams", 3));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, ScriptIsOrInherits, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "ScriptIsOrInherits", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, AddScriptBridge, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "AddScriptBridge", 2));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, RemoveScriptBridge, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "RemoveScriptBridge", 1));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, UpdateScriptClassInfo, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "UpdateScriptClassInfo", 3));
- CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, SwapGCHandleForType, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "SwapGCHandleForType", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Call, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Call", 6));
- CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Set, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Set", 3));
- CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Get, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Get", 3));
- CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, CallDispose, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "CallDispose", 2));
- CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, CallToString, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "CallToString", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(GCHandleBridge, FreeGCHandle, get_mono_method(GODOT_API_BRIDGE_CLASS(GCHandleBridge), "FreeGCHandle", 1));
-
- CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, InstallTraceListener, get_mono_method(GODOT_API_CLASS(DebuggingUtils), "InstallTraceListener", 0));
-
- MonoException *exc = nullptr;
- MonoMethod *init_default_godot_task_scheduler =
- get_mono_method(GODOT_API_CLASS(Dispatcher), "InitializeDefaultGodotTaskScheduler", 0);
- ERR_FAIL_COND_MSG(init_default_godot_task_scheduler == nullptr,
- "Mono Cache: InitializeDefaultGodotTaskScheduler is null.");
- mono_runtime_invoke(init_default_godot_task_scheduler, nullptr, nullptr, (MonoObject **)&exc);
-
- if (exc) {
- GDMonoUtils::debug_unhandled_exception(exc);
- }
-
- cached_data.godot_api_cache_updated = true;
+ManagedCallbacks managed_callbacks;
+bool godot_api_cache_updated = false;
+
+void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
+#define CHECK_CALLBACK_NOT_NULL_IMPL(m_var, m_class, m_method) ERR_FAIL_COND_MSG(m_var == nullptr, \
+ "Mono Cache: Managed callback for '" #m_class "_" #m_method "' is null.")
+
+#define CHECK_CALLBACK_NOT_NULL(m_class, m_method) CHECK_CALLBACK_NOT_NULL_IMPL(p_managed_callbacks.m_class##_##m_method, m_class, m_method)
+
+ CHECK_CALLBACK_NOT_NULL(SignalAwaiter, SignalCallback);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, InvokeWithVariantArgs);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateEquals);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, FrameCallback);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectBinding);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectScriptInstance);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptNativeName);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SetGodotObjectPtr);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RaiseEventSignal);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptSignalList);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, HasScriptSignal);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, HasMethodUnknownParams);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, ScriptIsOrInherits);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, AddScriptBridge);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RemoveScriptBridge);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, UpdateScriptClassInfo);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallDispose);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallToString);
+ CHECK_CALLBACK_NOT_NULL(GCHandleBridge, FreeGCHandle);
+ CHECK_CALLBACK_NOT_NULL(DebuggingUtils, InstallTraceListener);
+ CHECK_CALLBACK_NOT_NULL(Dispatcher, InitializeDefaultGodotTaskScheduler);
+
+ managed_callbacks = p_managed_callbacks;
+
+ godot_api_cache_updated = true;
}
} // namespace GDMonoCache
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 5785347938..56bf4cef94 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -31,56 +31,88 @@
#ifndef GD_MONO_CACHE_H
#define GD_MONO_CACHE_H
-#include "gd_mono_method_thunk.h"
+#include <stdint.h>
+
+#include "../csharp_script.h"
+#include "../mono_gc_handle.h"
+#include "core/object/object.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/variant/callable.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
class CSharpScript;
namespace GDMonoCache {
-struct CachedData {
- // Mono method thunks require structs to be boxed, even if passed by ref (out, ref, in).
- // As such we need to use pointers instead for now, instead of by ref parameters.
-
- GDMonoMethodThunk<GCHandleIntPtr, const Variant **, int, bool *> methodthunk_SignalAwaiter_SignalCallback;
-
- GDMonoMethodThunk<GCHandleIntPtr, const Variant **, uint32_t, const Variant *> methodthunk_DelegateUtils_InvokeWithVariantArgs;
- GDMonoMethodThunkR<bool, GCHandleIntPtr, GCHandleIntPtr> methodthunk_DelegateUtils_DelegateEquals;
-
- GDMonoMethodThunk<> methodthunk_ScriptManagerBridge_FrameCallback;
- GDMonoMethodThunkR<GCHandleIntPtr, const StringName *, Object *> methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding;
- GDMonoMethodThunk<const CSharpScript *, Object *, const Variant **, int> methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
- GDMonoMethodThunk<const CSharpScript *, StringName *> methodthunk_ScriptManagerBridge_GetScriptNativeName;
- GDMonoMethodThunk<MonoReflectionAssembly *> methodthunk_ScriptManagerBridge_LookupScriptsInAssembly;
- GDMonoMethodThunk<GCHandleIntPtr, Object *> methodthunk_ScriptManagerBridge_SetGodotObjectPtr;
- GDMonoMethodThunk<GCHandleIntPtr, const StringName *, const Variant **, int, bool *> methodthunk_ScriptManagerBridge_RaiseEventSignal;
- GDMonoMethodThunk<const CSharpScript *, Dictionary *> methodthunk_ScriptManagerBridge_GetScriptSignalList;
- GDMonoMethodThunkR<bool, const CSharpScript *, const String *> methodthunk_ScriptManagerBridge_HasScriptSignal;
- GDMonoMethodThunkR<bool, const CSharpScript *, const String *, bool> methodthunk_ScriptManagerBridge_HasMethodUnknownParams;
- GDMonoMethodThunkR<bool, const CSharpScript *, const CSharpScript *> methodthunk_ScriptManagerBridge_ScriptIsOrInherits;
- GDMonoMethodThunkR<bool, const CSharpScript *, const String *> methodthunk_ScriptManagerBridge_AddScriptBridge;
- GDMonoMethodThunk<const CSharpScript *> methodthunk_ScriptManagerBridge_RemoveScriptBridge;
- GDMonoMethodThunk<const CSharpScript *, bool *, Dictionary *> methodthunk_ScriptManagerBridge_UpdateScriptClassInfo;
- GDMonoMethodThunkR<bool, GCHandleIntPtr, GCHandleIntPtr *, bool> methodthunk_ScriptManagerBridge_SwapGCHandleForType;
-
- GDMonoMethodThunk<GCHandleIntPtr, const StringName *, const Variant **, int, Callable::CallError *, Variant *> methodthunk_CSharpInstanceBridge_Call;
- GDMonoMethodThunkR<bool, GCHandleIntPtr, const StringName *, const Variant *> methodthunk_CSharpInstanceBridge_Set;
- GDMonoMethodThunkR<bool, GCHandleIntPtr, const StringName *, Variant *> methodthunk_CSharpInstanceBridge_Get;
- GDMonoMethodThunk<GCHandleIntPtr, bool> methodthunk_CSharpInstanceBridge_CallDispose;
- GDMonoMethodThunk<GCHandleIntPtr, String *, bool *> methodthunk_CSharpInstanceBridge_CallToString;
-
- GDMonoMethodThunk<GCHandleIntPtr> methodthunk_GCHandleBridge_FreeGCHandle;
-
- GDMonoMethodThunk<> methodthunk_DebuggingUtils_InstallTraceListener;
-
- bool godot_api_cache_updated = false;
+#ifdef WIN32
+#define GD_CLR_STDCALL __stdcall
+#else
+#define GD_CLR_STDCALL
+#endif
+
+struct ManagedCallbacks {
+ using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *);
+ using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, uint32_t, const Variant *);
+ using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr);
+ using FuncScriptManagerBridge_FrameCallback = void(GD_CLR_STDCALL *)();
+ using FuncScriptManagerBridge_CreateManagedForGodotObjectBinding = GCHandleIntPtr(GD_CLR_STDCALL *)(const StringName *, Object *);
+ using FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = bool(GD_CLR_STDCALL *)(const CSharpScript *, Object *, const Variant **, int);
+ using FuncScriptManagerBridge_GetScriptNativeName = void(GD_CLR_STDCALL *)(const CSharpScript *, StringName *);
+ using FuncScriptManagerBridge_SetGodotObjectPtr = void(GD_CLR_STDCALL *)(GCHandleIntPtr, Object *);
+ using FuncScriptManagerBridge_RaiseEventSignal = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int, bool *);
+ using FuncScriptManagerBridge_GetScriptSignalList = void(GD_CLR_STDCALL *)(const CSharpScript *, Dictionary *);
+ using FuncScriptManagerBridge_HasScriptSignal = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
+ using FuncScriptManagerBridge_HasMethodUnknownParams = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *, bool);
+ using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *);
+ using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
+ using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
+ using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Dictionary *);
+ using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
+ using FuncCSharpInstanceBridge_Call = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int, Callable::CallError *, Variant *);
+ using FuncCSharpInstanceBridge_Set = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant *);
+ using FuncCSharpInstanceBridge_Get = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, Variant *);
+ using FuncCSharpInstanceBridge_CallDispose = void(GD_CLR_STDCALL *)(GCHandleIntPtr, bool);
+ using FuncCSharpInstanceBridge_CallToString = void(GD_CLR_STDCALL *)(GCHandleIntPtr, String *, bool *);
+ using FuncGCHandleBridge_FreeGCHandle = void(GD_CLR_STDCALL *)(GCHandleIntPtr);
+ using FuncDebuggingUtils_InstallTraceListener = void(GD_CLR_STDCALL *)();
+ using FuncDispatcher_InitializeDefaultGodotTaskScheduler = void(GD_CLR_STDCALL *)();
+
+ FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback;
+ FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs;
+ FuncDelegateUtils_DelegateEquals DelegateUtils_DelegateEquals;
+ FuncScriptManagerBridge_FrameCallback ScriptManagerBridge_FrameCallback;
+ FuncScriptManagerBridge_CreateManagedForGodotObjectBinding ScriptManagerBridge_CreateManagedForGodotObjectBinding;
+ FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
+ FuncScriptManagerBridge_GetScriptNativeName ScriptManagerBridge_GetScriptNativeName;
+ FuncScriptManagerBridge_SetGodotObjectPtr ScriptManagerBridge_SetGodotObjectPtr;
+ FuncScriptManagerBridge_RaiseEventSignal ScriptManagerBridge_RaiseEventSignal;
+ FuncScriptManagerBridge_GetScriptSignalList ScriptManagerBridge_GetScriptSignalList;
+ FuncScriptManagerBridge_HasScriptSignal ScriptManagerBridge_HasScriptSignal;
+ FuncScriptManagerBridge_HasMethodUnknownParams ScriptManagerBridge_HasMethodUnknownParams;
+ FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits;
+ FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge;
+ FuncScriptManagerBridge_RemoveScriptBridge ScriptManagerBridge_RemoveScriptBridge;
+ FuncScriptManagerBridge_UpdateScriptClassInfo ScriptManagerBridge_UpdateScriptClassInfo;
+ FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType;
+ FuncCSharpInstanceBridge_Call CSharpInstanceBridge_Call;
+ FuncCSharpInstanceBridge_Set CSharpInstanceBridge_Set;
+ FuncCSharpInstanceBridge_Get CSharpInstanceBridge_Get;
+ FuncCSharpInstanceBridge_CallDispose CSharpInstanceBridge_CallDispose;
+ FuncCSharpInstanceBridge_CallToString CSharpInstanceBridge_CallToString;
+ FuncGCHandleBridge_FreeGCHandle GCHandleBridge_FreeGCHandle;
+ FuncDebuggingUtils_InstallTraceListener DebuggingUtils_InstallTraceListener;
+ FuncDispatcher_InitializeDefaultGodotTaskScheduler Dispatcher_InitializeDefaultGodotTaskScheduler;
};
-extern CachedData cached_data;
+extern ManagedCallbacks managed_callbacks;
+extern bool godot_api_cache_updated;
-void update_godot_api_cache();
+void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks);
inline void clear_godot_api_cache() {
- cached_data = CachedData();
+ managed_callbacks = ManagedCallbacks();
}
} // namespace GDMonoCache
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
deleted file mode 100644
index 7b5fdef8a3..0000000000
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* gd_mono_internals.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 "gd_mono_internals.h"
-
-#include "../csharp_script.h"
-#include "../utils/macros.h"
-#include "gd_mono_utils.h"
-
-#include "core/debugger/engine_debugger.h"
-#include "core/debugger/script_debugger.h"
-
-#include <mono/metadata/exception.h>
-
-namespace GDMonoInternals {
-void unhandled_exception(MonoException *p_exc) {
- mono_print_unhandled_exception((MonoObject *)p_exc);
- gd_unhandled_exception_event(p_exc);
-
- if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) {
- // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
- mono_unhandled_exception((MonoObject *)p_exc);
- GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr);
- GD_UNREACHABLE();
- } else {
-#ifdef DEBUG_ENABLED
- GDMonoUtils::debug_send_unhandled_exception_error(p_exc);
- if (EngineDebugger::is_active()) {
- EngineDebugger::get_singleton()->poll_events(false);
- }
-#endif
- }
-}
-
-void gd_unhandled_exception_event(MonoException *p_exc) {
- MonoImage *mono_image = GDMono::get_singleton()->get_core_api_assembly()->get_image();
-
- MonoClass *gd_klass = mono_class_from_name(mono_image, "Godot", "GD");
- MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", 1);
- void *args[1];
- args[0] = p_exc;
- mono_runtime_invoke(unhandled_exception_method, nullptr, (void **)args, nullptr);
-}
-} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
deleted file mode 100644
index 858c395b78..0000000000
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* gd_mono_internals.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_INTERNALS_H
-#define GD_MONO_INTERNALS_H
-
-#include <mono/jit/jit.h>
-
-#include "../utils/macros.h"
-
-#include "core/object/class_db.h"
-
-class CSharpScript;
-
-namespace GDMonoInternals {
-/**
- * Do not call this function directly.
- * Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
- */
-void unhandled_exception(MonoException *p_exc);
-
-void gd_unhandled_exception_event(MonoException *p_exc);
-} // namespace GDMonoInternals
-
-#endif // GD_MONO_INTERNALS_H
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
deleted file mode 100644
index 6ea3c5539e..0000000000
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*************************************************************************/
-/* gd_mono_log.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_log.h"
-
-#include <stdlib.h> // abort
-
-#include "core/io/dir_access.h"
-#include "core/os/os.h"
-
-#include "../godotsharp_dirs.h"
-#include "../utils/string_utils.h"
-
-static CharString get_default_log_level() {
-#ifdef DEBUG_ENABLED
- return String("info").utf8();
-#else
- return String("warning").utf8();
-#endif
-}
-
-GDMonoLog *GDMonoLog::singleton = nullptr;
-
-#ifdef GD_MONO_LOG_ENABLED
-
-static int get_log_level_id(const char *p_log_level) {
- const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", nullptr };
-
- int i = 0;
- while (valid_log_levels[i]) {
- if (!strcmp(valid_log_levels[i], p_log_level)) {
- return i;
- }
- i++;
- }
-
- return -1;
-}
-
-static String make_text(const char *log_domain, const char *log_level, const char *message) {
- String text(message);
- text += " (in domain ";
- text += log_domain;
- if (log_level) {
- text += ", ";
- text += log_level;
- }
- text += ")";
- return text;
-}
-
-void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
- String text = make_text(log_domain, log_level, message);
- text += "\n";
-
- GDMonoLog::get_singleton()->log_file->seek_end();
- GDMonoLog::get_singleton()->log_file->store_string(text);
- }
-
- if (fatal) {
- String text = make_text(log_domain, log_level, message);
- ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
- // Make sure to flush before aborting
- GDMonoLog::get_singleton()->log_file->flush();
- GDMonoLog::get_singleton()->log_file.unref();
-
- abort();
- }
-}
-
-bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
- if (!DirAccess::exists(p_logs_dir)) {
- Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(diraccess.is_null(), false);
- Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
- ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory.");
- }
-
- return true;
-}
-
-void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
- static const uint64_t MAX_SECS = 5 * 86400; // 5 days
-
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND(da.is_null());
-
- Error err = da->change_dir(p_logs_dir);
- ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'.");
-
- ERR_FAIL_COND(da->list_dir_begin() != OK);
-
- String current = da->get_next();
- while (!current.is_empty()) {
- if (da->current_is_dir() || !current.ends_with(".txt")) {
- current = da->get_next();
- continue;
- }
-
- uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current));
-
- if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) {
- da->remove(current);
- }
- current = da->get_next();
- }
-
- da->list_dir_end();
-}
-
-void GDMonoLog::initialize() {
- CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
-
- if (log_level.length() != 0 && get_log_level_id(log_level.get_data()) == -1) {
- ERR_PRINT(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'.");
- log_level = CharString();
- }
-
- if (log_level.length() == 0) {
- log_level = get_default_log_level();
- }
-
- String logs_dir = GodotSharpDirs::get_mono_logs_dir();
-
- if (_try_create_logs_dir(logs_dir)) {
- _delete_old_log_files(logs_dir);
-
- OS::Date date_now = OS::get_singleton()->get_date();
- OS::Time time_now = OS::get_singleton()->get_time();
-
- String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d",
- (int)date_now.year, (int)date_now.month, (int)date_now.day,
- (int)time_now.hour, (int)time_now.minute, (int)time_now.second);
-
- log_file_name += str_format("_%d", OS::get_singleton()->get_process_id());
-
- log_file_name += ".log";
-
- log_file_path = logs_dir.plus_file(log_file_name);
-
- log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
- if (log_file.is_null()) {
- ERR_PRINT("Mono: Cannot create log file at: " + log_file_path);
- }
- }
-
- mono_trace_set_level_string(log_level.get_data());
- log_level_id = get_log_level_id(log_level.get_data());
-
- if (log_file.is_valid()) {
- OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data());
- mono_trace_set_log_handler(mono_log_callback, this);
- } else {
- OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
- }
-}
-
-GDMonoLog::GDMonoLog() {
- singleton = this;
-}
-
-GDMonoLog::~GDMonoLog() {
- singleton = nullptr;
-}
-
-#else
-
-void GDMonoLog::initialize() {
- CharString log_level = get_default_log_level();
- mono_trace_set_level_string(log_level.get_data());
-}
-
-GDMonoLog::GDMonoLog() {
- singleton = this;
-}
-
-GDMonoLog::~GDMonoLog() {
- singleton = nullptr;
-}
-
-#endif // !defined(JAVASCRIPT_ENABLED)
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
deleted file mode 100644
index 93ba6a410e..0000000000
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* gd_mono_log.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_LOG_H
-#define GD_MONO_LOG_H
-
-#include <mono/utils/mono-logger.h>
-
-#include "core/typedefs.h"
-
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
-// We have custom mono log callbacks for WASM and iOS
-#define GD_MONO_LOG_ENABLED
-#endif
-
-#ifdef GD_MONO_LOG_ENABLED
-#include "core/io/file_access.h"
-#endif
-
-class GDMonoLog {
-#ifdef GD_MONO_LOG_ENABLED
- int log_level_id = -1;
-
- Ref<FileAccess> log_file;
- String log_file_path;
-
- bool _try_create_logs_dir(const String &p_logs_dir);
- void _delete_old_log_files(const String &p_logs_dir);
-
- static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);
-#endif
-
- static GDMonoLog *singleton;
-
-public:
- _FORCE_INLINE_ static GDMonoLog *get_singleton() { return singleton; }
-
- void initialize();
-
- GDMonoLog();
- ~GDMonoLog();
-};
-
-#endif // GD_MONO_LOG_H
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
deleted file mode 100644
index aa84a7f2d0..0000000000
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method_thunk.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_METHOD_THUNK_H
-#define GD_MONO_METHOD_THUNK_H
-
-#include <mono/jit/jit.h>
-#include <mono/metadata/attrdefs.h>
-#include <type_traits>
-
-#include "core/error/error_macros.h"
-#include "gd_mono_utils.h"
-
-#ifdef WIN32
-#define GD_MONO_STDCALL __stdcall
-#else
-#define GD_MONO_STDCALL
-#endif
-
-template <class... ParamTypes>
-struct GDMonoMethodThunk {
- typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
-
- M mono_method_thunk = nullptr;
-
-public:
- _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_method_thunk(p_args..., r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- }
-
- bool is_null() {
- return mono_method_thunk == nullptr;
- }
-
- void set_from_method(MonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
-
- MonoMethodSignature *method_sig = mono_method_signature(p_mono_method);
- MonoType *ret_type = mono_signature_get_return_type(method_sig);
- int ret_type_encoding = ret_type ? mono_type_get_type(ret_type) : MONO_TYPE_VOID;
-
- CRASH_COND(ret_type_encoding != MONO_TYPE_VOID);
-
- bool is_static = mono_method_get_flags(p_mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
- CRASH_COND(!is_static);
-
- uint32_t parameters_count = mono_signature_get_param_count(method_sig);
- CRASH_COND(parameters_count != sizeof...(ParamTypes));
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method);
- }
-
- GDMonoMethodThunk() {}
-};
-
-template <class R, class... ParamTypes>
-struct GDMonoMethodThunkR {
- typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
-
- M mono_method_thunk = nullptr;
-
-public:
- _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- R r = mono_method_thunk(p_args..., r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return r;
- }
-
- bool is_null() {
- return mono_method_thunk == nullptr;
- }
-
- void set_from_method(MonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
-
- MonoMethodSignature *method_sig = mono_method_signature(p_mono_method);
- MonoType *ret_type = mono_signature_get_return_type(method_sig);
- int ret_type_encoding = ret_type ? mono_type_get_type(ret_type) : MONO_TYPE_VOID;
-
- CRASH_COND(ret_type_encoding == MONO_TYPE_VOID);
-
- bool is_static = mono_method_get_flags(p_mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
- CRASH_COND(!is_static);
-
- uint32_t parameters_count = mono_signature_get_param_count(method_sig);
- CRASH_COND(parameters_count != sizeof...(ParamTypes));
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method);
- }
-
- GDMonoMethodThunkR() {}
-};
-
-#endif // GD_MONO_METHOD_THUNK_H
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
deleted file mode 100644
index 3e2f4b05d5..0000000000
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*************************************************************************/
-/* gd_mono_utils.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 "gd_mono_utils.h"
-
-#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/exception.h>
-
-#include "core/debugger/engine_debugger.h"
-#include "core/debugger/script_debugger.h"
-#include "core/io/dir_access.h"
-#include "core/object/ref_counted.h"
-#include "core/os/mutex.h"
-#include "core/os/os.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/debugger/editor_debugger_node.h"
-#endif
-
-#include "../csharp_script.h"
-#include "../utils/macros.h"
-#include "gd_mono.h"
-#include "gd_mono_cache.h"
-
-namespace GDMonoUtils {
-
-void set_main_thread(MonoThread *p_thread) {
- mono_thread_set_main(p_thread);
-}
-
-MonoThread *attach_current_thread() {
- ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), nullptr);
- MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain();
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain());
-#else
- // The scripts domain is the root domain
- MonoThread *mono_thread = mono_thread_attach(scripts_domain);
-#endif
- ERR_FAIL_NULL_V(mono_thread, nullptr);
- return mono_thread;
-}
-
-void detach_current_thread() {
- ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- MonoThread *mono_thread = mono_thread_current();
- ERR_FAIL_NULL(mono_thread);
- mono_thread_detach(mono_thread);
-}
-
-void detach_current_thread(MonoThread *p_mono_thread) {
- ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- ERR_FAIL_NULL(p_mono_thread);
- mono_thread_detach(p_mono_thread);
-}
-
-MonoThread *get_current_thread() {
- return mono_thread_current();
-}
-
-bool is_thread_attached() {
- return mono_domain_get() != nullptr;
-}
-
-MonoDomain *create_domain(const String &p_friendly_name) {
- print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
-
- MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), nullptr);
-
- if (domain) {
- // Workaround to avoid this exception:
- // System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system.
- // ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null.
- mono_domain_set_config(domain, ".", "");
- }
-
- return domain;
-}
-
-// TODO:
-// Implement all of the disabled exception logging below. Once we move to .NET 6.
-// It will have to be done from C# as UnmanagedCallersOnly doesn't allow throwing.
-
-#warning TODO
-#if 0
-String get_exception_name_and_message(MonoException *p_exc) {
- String res;
-
- MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
- MonoType *type = mono_class_get_type(klass);
-
- char *full_name = mono_type_full_name(type);
- res += full_name;
- mono_free(full_name);
-
- res += ": ";
-
- MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
- MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, nullptr, nullptr);
- res += GDMonoMarshal::mono_string_to_godot(msg);
-
- return res;
-}
-#endif
-
-void debug_print_unhandled_exception(MonoException *p_exc) {
- print_unhandled_exception(p_exc);
- debug_send_unhandled_exception_error(p_exc);
-}
-
-void debug_send_unhandled_exception_error(MonoException *p_exc) {
-#ifdef DEBUG_ENABLED
- if (!EngineDebugger::is_active()) {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
-#warning TODO
-#if 0
- ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_exc));
-#endif
- }
-#endif
- return;
- }
-
- static thread_local bool _recursion_flag_ = false;
- if (_recursion_flag_) {
- return;
- }
- _recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
-
- ScriptLanguage::StackInfo separator;
- separator.file = String();
- separator.func = "--- " + RTR("End of inner exception stack trace") + " ---";
- separator.line = 0;
-
- Vector<ScriptLanguage::StackInfo> si;
- String exc_msg;
-
-#warning TODO
-#if 0
- while (p_exc != nullptr) {
- GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
- MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
-
- MonoBoolean need_file_info = true;
- void *ctor_args[2] = { p_exc, &need_file_info };
-
- MonoException *unexpected_exc = nullptr;
- CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
-
- if (unexpected_exc) {
- GDMonoInternals::unhandled_exception(unexpected_exc);
- return;
- }
-
- Vector<ScriptLanguage::StackInfo> _si;
- if (stack_trace != nullptr) {
- _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
- for (int i = _si.size() - 1; i >= 0; i--) {
- si.insert(0, _si[i]);
- }
- }
-
- exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc);
-
- GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class());
- GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException");
- CRASH_COND(inner_exc_prop == nullptr);
-
- MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc);
- if (inner_exc != nullptr) {
- si.insert(0, separator);
- }
-
- p_exc = (MonoException *)inner_exc;
- }
-#endif
-
- String file = si.size() ? si[0].file : __FILE__;
- String func = si.size() ? si[0].func : FUNCTION_STR;
- int line = si.size() ? si[0].line : __LINE__;
- String error_msg = "Unhandled exception";
-
- EngineDebugger::get_script_debugger()->send_error(func, file, line, error_msg, exc_msg, true, ERR_HANDLER_ERROR, si);
-#endif
-}
-
-void debug_unhandled_exception(MonoException *p_exc) {
- GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
-}
-
-void print_unhandled_exception(MonoException *p_exc) {
- mono_print_unhandled_exception((MonoObject *)p_exc);
-}
-
-void set_pending_exception(MonoException *p_exc) {
-#ifdef NO_PENDING_EXCEPTIONS
- debug_unhandled_exception(p_exc);
-#else
- if (get_runtime_invoke_count() == 0) {
- debug_unhandled_exception(p_exc);
- return;
- }
-
- if (!mono_runtime_set_pending_exception(p_exc, false)) {
- ERR_PRINT("Exception thrown from managed code, but it could not be set as pending:");
- GDMonoUtils::debug_print_unhandled_exception(p_exc);
- }
-#endif
-}
-
-thread_local int current_invoke_count = 0;
-
-ScopeThreadAttach::ScopeThreadAttach() {
- if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
- mono_thread = GDMonoUtils::attach_current_thread();
- }
-}
-
-ScopeThreadAttach::~ScopeThreadAttach() {
- if (unlikely(mono_thread)) {
- GDMonoUtils::detach_current_thread(mono_thread);
- }
-}
-} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
deleted file mode 100644
index 16fc3cc757..0000000000
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*************************************************************************/
-/* gd_mono_utils.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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_UTILS_H
-#define GD_MONO_UTILS_H
-
-#include <mono/metadata/threads.h>
-
-#include "../mono_gc_handle.h"
-#include "../utils/macros.h"
-#ifdef JAVASCRIPT_ENABLED
-#include "gd_mono_wasm_m2n.h"
-#endif
-
-#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
-
-#define UNHANDLED_EXCEPTION(m_exc) \
- if (unlikely(m_exc != nullptr)) { \
- GDMonoUtils::debug_unhandled_exception(m_exc); \
- GD_UNREACHABLE(); \
- } else \
- ((void)0)
-
-namespace GDMonoUtils {
-
-namespace Marshal {
-bool type_has_flags_attribute(MonoReflectionType *p_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);
-}
-
-void set_main_thread(MonoThread *p_thread);
-MonoThread *attach_current_thread();
-void detach_current_thread();
-void detach_current_thread(MonoThread *p_mono_thread);
-MonoThread *get_current_thread();
-bool is_thread_attached();
-
-MonoDomain *create_domain(const String &p_friendly_name);
-
-String get_exception_name_and_message(MonoException *p_exc);
-
-void debug_print_unhandled_exception(MonoException *p_exc);
-void debug_send_unhandled_exception_error(MonoException *p_exc);
-void debug_unhandled_exception(MonoException *p_exc);
-void print_unhandled_exception(MonoException *p_exc);
-
-/**
- * Sets the exception as pending. The exception will be thrown when returning to managed code.
- * If no managed method is being invoked by the runtime, the exception will be treated as
- * an unhandled exception and the method will not return.
- */
-void set_pending_exception(MonoException *p_exc);
-
-extern thread_local int current_invoke_count;
-
-_FORCE_INLINE_ int get_runtime_invoke_count() {
- return current_invoke_count;
-}
-
-_FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
- return current_invoke_count;
-}
-
-uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);
-
-struct ScopeThreadAttach {
- ScopeThreadAttach();
- ~ScopeThreadAttach();
-
-private:
- MonoThread *mono_thread = nullptr;
-};
-
-template <typename... P>
-void add_internal_call(const char *p_name, void (*p_func)(P...)) {
-#ifdef JAVASCRIPT_ENABLED
- GDMonoWasmM2n::ICallTrampolines<P...>::add();
-#endif
- mono_add_internal_call(p_name, (void *)p_func);
-}
-
-template <typename R, typename... P>
-void add_internal_call(const char *p_name, R (*p_func)(P...)) {
-#ifdef JAVASCRIPT_ENABLED
- GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add();
-#endif
- mono_add_internal_call(p_name, (void *)p_func);
-}
-} // namespace GDMonoUtils
-
-#define GD_MONO_BEGIN_RUNTIME_INVOKE \
- int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
- _runtime_invoke_count_ref += 1; \
- ((void)0)
-
-#define GD_MONO_END_RUNTIME_INVOKE \
- _runtime_invoke_count_ref -= 1; \
- ((void)0)
-
-#define GD_MONO_SCOPE_THREAD_ATTACH \
- GDMonoUtils::ScopeThreadAttach __gdmono__scope__thread__attach__; \
- (void)__gdmono__scope__thread__attach__; \
- ((void)0)
-
-#ifdef DEBUG_ENABLED
-#define GD_MONO_ASSERT_THREAD_ATTACHED \
- CRASH_COND(!GDMonoUtils::is_thread_attached()); \
- ((void)0)
-#else
-#define GD_MONO_ASSERT_THREAD_ATTACHED ((void)0)
-#endif
-
-#endif // GD_MONO_UTILS_H
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
deleted file mode 100644
index dbfca2dc0c..0000000000
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*************************************************************************/
-/* gd_mono_wasm_m2n.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_wasm_m2n.h"
-
-#ifdef JAVASCRIPT_ENABLED
-
-#include "core/templates/oa_hash_map.h"
-
-typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs);
-
-// This extern function is implemented in our patched version of Mono
-MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook);
-
-namespace GDMonoWasmM2n {
-
-struct HashMapCookieComparator {
- static bool compare(const char *p_lhs, const char *p_rhs) {
- return strcmp(p_lhs, p_rhs) == 0;
- }
-};
-
-// The default hasher supports 'const char *' C Strings, but we need a custom comparator
-OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines;
-
-void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) {
- trampolines.set(cookies, trampoline_func);
-}
-
-mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) {
- TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie);
-
- if (!trampoline_func) {
- return false;
- }
-
- (*trampoline_func)(target_func, margs);
- return true;
-}
-
-bool initialized = false;
-
-void lazy_initialize() {
- // Doesn't need to be thread safe
- if (!initialized) {
- initialized = true;
- godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook);
- }
-}
-} // namespace GDMonoWasmM2n
-
-#endif
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
deleted file mode 100644
index 83e2750e5a..0000000000
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*************************************************************************/
-/* gd_mono_wasm_m2n.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_WASM_M2N_H
-#define GD_MONO_WASM_M2N_H
-
-#ifdef JAVASCRIPT_ENABLED
-
-#include "core/string/ustring.h"
-#include "core/typedefs.h"
-
-#include <mono/metadata/loader.h>
-#include <mono/utils/mono-publib.h>
-#include <stdexcept>
-#include <type_traits>
-
-extern "C" {
-
-struct Mono_InterpMethodArguments {
- size_t ilen;
- void **iargs;
- size_t flen;
- double *fargs = nullptr;
- void **retval;
- size_t is_float_ret;
- //#ifdef TARGET_WASM
- void *sig = nullptr;
- //#endif
-};
-} // extern "C"
-
-namespace GDMonoWasmM2n {
-
-template <typename T, size_t Size>
-struct array {
- T elems[Size];
-};
-
-template <typename T>
-constexpr char get_m2n_cookie_impl() {
-#define M2N_REG_COOKIE(m_type, m_cookie) \
- if constexpr (std::is_same_v<m_type, T>) { \
- return m_cookie; \
- }
-
- M2N_REG_COOKIE(MonoBoolean, 'I');
- M2N_REG_COOKIE(int8_t, 'I');
- M2N_REG_COOKIE(uint8_t, 'I');
- M2N_REG_COOKIE(int16_t, 'I');
- M2N_REG_COOKIE(uint16_t, 'I');
- M2N_REG_COOKIE(int32_t, 'I');
- M2N_REG_COOKIE(uint32_t, 'I');
- M2N_REG_COOKIE(int64_t, 'L');
- M2N_REG_COOKIE(uint64_t, 'L');
- M2N_REG_COOKIE(float, 'F');
- M2N_REG_COOKIE(double, 'D');
-
- if constexpr (std::is_pointer_v<T>) {
- if constexpr (sizeof(void *) == 4) {
- return 'I';
- } else {
- return 'L';
- }
- }
-
- if constexpr (std::is_void_v<T>) {
- return 'V';
- }
-
- return 'X';
-
-#undef M2N_REG_COOKIE
-}
-
-template <typename T>
-constexpr char get_m2n_cookie() {
- constexpr char cookie = get_m2n_cookie_impl<T>();
- static_assert(cookie != 'X', "Type not supported in internal call signature.");
- return cookie;
-}
-
-template <typename... T>
-constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() {
- return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' };
-}
-
-template <typename R, typename... T>
-constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() {
- return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' };
-}
-
-template <typename T>
-constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) {
- constexpr char cookie = get_m2n_cookie<T>();
-
- static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
-
- if constexpr (cookie == 'I' || cookie == 'L') {
- size_t ret = r_int_idx;
- r_int_idx += cookie == 'I' ? 1 : 2;
- return ret;
- } else {
- size_t ret = r_float_idx;
- r_float_idx += cookie == 'F' ? 1 : 2;
- return ret;
- }
-}
-
-template <typename... P>
-constexpr array<size_t, sizeof...(P)> get_indices_for_type() {
- size_t int_idx = 0;
- size_t float_idx = 0;
- return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... };
-}
-
-constexpr size_t fidx(size_t p_x) {
- if constexpr (sizeof(void *) == 4) {
- return p_x * 2;
- } else {
- return p_x;
- }
-}
-
-template <typename T>
-T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
- constexpr char cookie = get_m2n_cookie<T>();
-
- static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
-
- if constexpr (cookie == 'I') {
- return (T)(size_t)p_margs->iargs[p_idx];
- } else if constexpr (cookie == 'L') {
- static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> ||
- (sizeof(void *) == 8 && std::is_pointer_v<T>),
- "Invalid type for cookie 'L'.");
-
- union {
- T l;
- struct {
- int32_t lo;
- int32_t hi;
- } pair;
- } p;
-
- p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx];
- p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1];
-
- return p.l;
- } else if constexpr (cookie == 'F') {
- return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
- } else if constexpr (cookie == 'D') {
- return (T)p_margs->fargs[p_idx];
- }
-}
-
-template <typename... P, size_t... Is>
-void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
- constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
- typedef void (*Func)(P...);
- Func func = (Func)p_target_func;
- func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
-}
-
-template <typename R, typename... P, size_t... Is>
-void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
- constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
- typedef R (*Func)(P...);
- Func func = (Func)p_target_func;
- R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
- *reinterpret_cast<R *>(p_margs->retval) = res;
-}
-
-inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- typedef void (*Func)();
- Func func = (Func)p_target_func;
- func();
-}
-
-template <typename R>
-void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- typedef R (*Func)();
- Func func = (Func)p_target_func;
- R res = func();
- *reinterpret_cast<R *>(p_margs->retval) = res;
-}
-
-template <typename... P>
-void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- if constexpr (sizeof...(P) == 0) {
- m2n_trampoline_with_idx_seq_0(p_target_func, p_margs);
- } else {
- m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
- }
-}
-
-template <typename R, typename... P>
-void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- if constexpr (sizeof...(P) == 0) {
- m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs);
- } else {
- m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
- }
-}
-
-typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs);
-
-void set_trampoline(const char *cookies, TrampolineFunc trampoline_func);
-
-void lazy_initialize();
-
-template <typename... P>
-struct ICallTrampolines {
- static constexpr auto cookies = get_m2n_cookies<P...>();
-
- static void add() {
- lazy_initialize();
- set_trampoline(cookies.elems, &m2n_trampoline<P...>);
- }
-};
-
-template <typename R, typename... P>
-struct ICallTrampolinesR {
- static constexpr auto cookies = get_m2n_cookies_r<R, P...>();
-
- static void add() {
- lazy_initialize();
- set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>);
- }
-};
-
-void initialize();
-} // namespace GDMonoWasmM2n
-
-#endif
-
-#endif // GD_MONO_WASM_M2N_H
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index b71e5f392b..55d2138674 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -32,7 +32,6 @@
#include "csharp_script.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_utils.h"
Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
@@ -104,14 +103,8 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va
"Resumed after await, but class instance is gone.");
#endif
- MonoException *exc = nullptr;
bool awaiter_is_null = false;
- GDMonoCache::cached_data.methodthunk_SignalAwaiter_SignalCallback.invoke(awaiter_handle.get_intptr(), p_arguments, p_argcount, &awaiter_is_null, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- }
+ GDMonoCache::managed_callbacks.SignalAwaiter_SignalCallback(awaiter_handle.get_intptr(), p_arguments, p_argcount, &awaiter_is_null);
if (awaiter_is_null) {
r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
@@ -192,16 +185,10 @@ void EventSignalCallable::call(const Variant **p_arguments, int p_argcount, Vari
GCHandleIntPtr owner_gchandle_intptr = csharp_instance->get_gchandle_intptr();
- MonoException *exc = nullptr;
bool awaiter_is_null = false;
- GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_RaiseEventSignal.invoke(
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_RaiseEventSignal(
owner_gchandle_intptr, &event_signal_name,
- p_arguments, p_argcount, &awaiter_is_null, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- }
+ p_arguments, p_argcount, &awaiter_is_null);
if (awaiter_is_null) {
r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
deleted file mode 100644
index 8e37e6943c..0000000000
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*************************************************************************/
-/* mono_reg_utils.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "mono_reg_utils.h"
-#include "core/io/dir_access.h"
-
-#ifdef WINDOWS_ENABLED
-
-#include "core/os/os.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-namespace MonoRegUtils {
-
-template <int>
-REGSAM bitness_sam_impl();
-
-template <>
-REGSAM bitness_sam_impl<4>() {
- return KEY_WOW64_64KEY;
-}
-
-template <>
-REGSAM bitness_sam_impl<8>() {
- return KEY_WOW64_32KEY;
-}
-
-REGSAM _get_bitness_sam() {
- return bitness_sam_impl<sizeof(size_t)>();
-}
-
-LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) {
- LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult);
-
- if (res != ERROR_SUCCESS) {
- res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult);
- }
-
- return res;
-}
-
-LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value) {
- Vector<WCHAR> buffer;
- buffer.resize(512);
- DWORD dwBufferSize = buffer.size();
-
- LONG res = RegQueryValueExW(hKey, (LPCWSTR)(p_value_name.utf16().get_data()), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
-
- if (res == ERROR_MORE_DATA) {
- // dwBufferSize now contains the actual size
- buffer.resize(dwBufferSize);
- res = RegQueryValueExW(hKey, (LPCWSTR)(p_value_name.utf16().get_data()), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
- }
-
- if (res == ERROR_SUCCESS) {
- r_value = String(buffer.ptr(), buffer.size());
- } else {
- r_value = String();
- }
-
- return res;
-}
-
-LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_reg = false) {
- HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- if (!p_old_reg) {
- res = _RegKeyQueryString(hKey, "Version", r_info.version);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
- }
-
- res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- if (r_info.install_root_dir.ends_with("\\")) {
- r_info.bin_dir = r_info.install_root_dir + "bin";
- } else {
- r_info.bin_dir = r_info.install_root_dir + "\\bin";
- }
-
-cleanup:
- RegCloseKey(hKey);
- return res;
-}
-
-LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
- String default_clr;
-
- HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr);
-
- if (res == ERROR_SUCCESS && default_clr.length()) {
- r_info.version = default_clr;
- res = _find_mono_in_reg(p_subkey + "\\" + default_clr, r_info, true);
- }
-
-cleanup:
- RegCloseKey(hKey);
- return res;
-}
-
-MonoRegInfo find_mono() {
- MonoRegInfo info;
-
- if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS) {
- return info;
- }
-
- if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS) {
- return info;
- }
-
- return MonoRegInfo();
-}
-
-String find_msbuild_tools_path() {
- String msbuild_tools_path;
-
- // Try to find 15.0 with vswhere
-
- String vswhere_path = OS::get_singleton()->get_environment(sizeof(size_t) == 8 ? "ProgramFiles(x86)" : "ProgramFiles");
- vswhere_path += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
-
- List<String> vswhere_args;
- vswhere_args.push_back("-latest");
- vswhere_args.push_back("-products");
- vswhere_args.push_back("*");
- vswhere_args.push_back("-requires");
- vswhere_args.push_back("Microsoft.Component.MSBuild");
-
- String output;
- int exit_code;
- OS::get_singleton()->execute(vswhere_path, vswhere_args, &output, &exit_code);
-
- if (exit_code == 0) {
- Vector<String> lines = output.split("\n");
-
- for (int i = 0; i < lines.size(); i++) {
- const String &line = lines[i];
- int sep_idx = line.find(":");
-
- if (sep_idx > 0) {
- String key = line.substr(0, sep_idx); // No need to trim
-
- if (key == "installationPath") {
- String val = line.substr(sep_idx + 1, line.length()).strip_edges();
-
- ERR_BREAK(val.is_empty());
-
- if (!val.ends_with("\\")) {
- val += "\\";
- }
-
- // Since VS2019, the directory is simply named "Current"
- String msbuild_dir = val + "MSBuild\\Current\\Bin";
- if (DirAccess::exists(msbuild_dir)) {
- return msbuild_dir;
- }
-
- // Directory name "15.0" is used in VS 2017
- return val + "MSBuild\\15.0\\Bin";
- }
- }
- }
- }
-
- // Try to find 14.0 in the Registry
-
- HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
-cleanup:
- RegCloseKey(hKey);
-
- return msbuild_tools_path;
-}
-} // namespace MonoRegUtils
-
-#endif // WINDOWS_ENABLED
diff --git a/modules/mono/utils/mono_reg_utils.h b/modules/mono/utils/mono_reg_utils.h
deleted file mode 100644
index 5be60d4930..0000000000
--- a/modules/mono/utils/mono_reg_utils.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************************************/
-/* mono_reg_utils.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef MONO_REG_UTILS_H
-#define MONO_REG_UTILS_H
-
-#ifdef WINDOWS_ENABLED
-
-#include "core/string/ustring.h"
-
-struct MonoRegInfo {
- String version;
- String install_root_dir;
- String assembly_dir;
- String config_dir;
- String bin_dir;
-};
-
-namespace MonoRegUtils {
-
-MonoRegInfo find_mono();
-String find_msbuild_tools_path();
-} // namespace MonoRegUtils
-
-#endif // WINDOWS_ENABLED
-
-#endif // MONO_REG_UTILS_H