summaryrefslogtreecommitdiff
path: root/modules/mono
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono')
-rw-r--r--modules/mono/SCsub5
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py2
-rw-r--r--modules/mono/build_scripts/mono_configure.py16
-rw-r--r--modules/mono/class_db_api_json.cpp46
-rw-r--r--modules/mono/config.py54
-rw-r--r--modules/mono/csharp_script.cpp214
-rw-r--r--modules/mono/csharp_script.h58
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs11
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs7
-rw-r--r--modules/mono/editor/bindings_generator.cpp722
-rw-r--r--modules/mono/editor/bindings_generator.h39
-rw-r--r--modules/mono/editor/code_completion.cpp12
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp18
-rw-r--r--modules/mono/editor/editor_internal_calls.h6
-rw-r--r--modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs (renamed from modules/mono/editor_templates/CharacterBody2D/basic_movement.cs)12
-rw-r--r--modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs (renamed from modules/mono/editor_templates/CharacterBody3D/basic_movement.cs)16
-rw-r--r--modules/mono/editor/script_templates/EditorPlugin/plugin.cs (renamed from modules/mono/editor_templates/EditorPlugin/plugin.cs)1
-rw-r--r--modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs16
-rw-r--r--modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs15
-rw-r--r--modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs (renamed from modules/mono/editor_templates/EditorScript/basic_editor_script.cs)3
-rw-r--r--modules/mono/editor/script_templates/Node/default.cs (renamed from modules/mono/editor_templates/Node/default.cs)2
-rw-r--r--modules/mono/editor/script_templates/Object/empty.cs (renamed from modules/mono/editor_templates/Object/empty.cs)1
-rw-r--r--modules/mono/editor/script_templates/SCsub (renamed from modules/mono/editor_templates/SCsub)0
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs (renamed from modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs)0
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs43
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs32
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs65
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs820
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs65
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs64
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs79
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs832
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs702
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj5
-rw-r--r--modules/mono/glue/arguments_vector.h2
-rw-r--r--modules/mono/glue/base_object_glue.cpp8
-rw-r--r--modules/mono/glue/callable_glue.cpp4
-rw-r--r--modules/mono/glue/gd_glue.cpp22
-rw-r--r--modules/mono/glue/glue_header.h5
-rw-r--r--modules/mono/glue/nodepath_glue.cpp5
-rw-r--r--modules/mono/godotsharp_dirs.cpp8
-rw-r--r--modules/mono/managed_callable.cpp5
-rw-r--r--modules/mono/managed_callable.h4
-rw-r--r--modules/mono/mono_gc_handle.h6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp47
-rw-r--r--modules/mono/mono_gd/gd_mono.h18
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h151
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp41
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h14
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp30
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h12
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp28
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp23
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h93
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h7
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h4
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp89
-rw-r--r--modules/mono/mono_gd/support/ios_support.h4
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm7
-rw-r--r--modules/mono/register_types.cpp12
-rw-r--r--modules/mono/register_types.h6
-rw-r--r--modules/mono/signal_awaiter_utils.cpp6
-rw-r--r--modules/mono/signal_awaiter_utils.h2
-rw-r--r--modules/mono/utils/macos_utils.cpp (renamed from modules/mono/utils/osx_utils.cpp)12
-rw-r--r--modules/mono/utils/macos_utils.h (renamed from modules/mono/utils/osx_utils.h)12
-rw-r--r--modules/mono/utils/macros.h6
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp38
-rw-r--r--modules/mono/utils/path_utils.cpp21
-rw-r--r--modules/mono/utils/path_utils.h6
-rw-r--r--modules/mono/utils/string_utils.cpp8
-rw-r--r--modules/mono/utils/string_utils.h6
115 files changed, 4154 insertions, 981 deletions
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index db35e804aa..d10ebc7b47 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -55,7 +55,7 @@ env_mono.add_source_files(env.modules_sources, "utils/*.cpp")
env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.cpp")
-if env["platform"] in ["osx", "iphone"]:
+if env["platform"] in ["macos", "ios"]:
env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.mm")
env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.m")
elif env["platform"] == "android":
@@ -63,5 +63,4 @@ elif env["platform"] == "android":
if env["tools"]:
env_mono.add_source_files(env.modules_sources, "editor/*.cpp")
-
-SConscript("editor_templates/SCsub")
+ SConscript("editor/script_templates/SCsub")
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
index 1920ef1c1a..3459244bc2 100644
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ b/modules/mono/build_scripts/make_android_mono_config.py
@@ -43,7 +43,7 @@ String get_godot_android_mono_config() {
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())) {
+ if (s.parse_utf8((const char *)w, data.size()) != OK) {
ERR_FAIL_V(String());
}
return s;
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 8e441e7e07..e69904c54b 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -63,15 +63,15 @@ def copy_file(src_dir, dst_dir, src_name, dst_name=""):
def is_desktop(platform):
- return platform in ["windows", "osx", "linuxbsd", "server", "uwp", "haiku"]
+ return platform in ["windows", "macos", "linuxbsd", "server", "uwp", "haiku"]
def is_unix_like(platform):
- return platform in ["osx", "linuxbsd", "server", "android", "haiku", "iphone"]
+ return platform in ["macos", "linuxbsd", "server", "android", "haiku", "ios"]
def module_supports_tools_on(platform):
- return platform not in ["android", "javascript", "iphone"]
+ return platform not in ["android", "javascript", "ios"]
def find_wasm_src_dir(mono_root):
@@ -89,7 +89,7 @@ def configure(env, env_mono):
bits = env["bits"]
is_android = env["platform"] == "android"
is_javascript = env["platform"] == "javascript"
- is_ios = env["platform"] == "iphone"
+ is_ios = env["platform"] == "ios"
is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
tools_enabled = env["tools"]
@@ -206,7 +206,7 @@ def configure(env, env_mono):
copy_file(mono_bin_path, "#bin", mono_dll_file)
else:
- is_apple = env["platform"] in ["osx", "iphone"]
+ is_apple = env["platform"] in ["macos", "ios"]
is_macos = is_apple and not is_ios
sharedlib_ext = ".dylib" if is_apple else ".so"
@@ -221,7 +221,7 @@ def configure(env, env_mono):
)
if not mono_root and is_macos:
- # Try with some known directories under OSX
+ # 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):
@@ -270,7 +270,7 @@ def configure(env, env_mono):
def copy_mono_lib(libname_wo_ext):
copy_file(
- mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.iphone.%s.a" % (libname_wo_ext, arch)
+ 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
@@ -539,7 +539,7 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
os.makedirs(target_mono_lib_dir)
lib_file_names = []
- if platform == "osx":
+ if platform == "macos":
lib_file_names = [
lib_name + ".dylib"
for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"]
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index 5884a24454..c4547b4323 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -40,17 +40,12 @@
void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
Dictionary classes_dict;
- List<StringName> names;
+ List<StringName> class_list;
+ ClassDB::get_class_list(&class_list);
+ // Must be alphabetically sorted for hash to compute.
+ class_list.sort_custom<StringName::AlphCompare>();
- const StringName *k = nullptr;
-
- while ((k = ClassDB::classes.next(k))) {
- names.push_back(*k);
- }
- //must be alphabetically sorted for hash to compute
- names.sort_custom<StringName::AlphCompare>();
-
- for (const StringName &E : names) {
+ for (const StringName &E : class_list) {
ClassDB::ClassInfo *t = ClassDB::classes.getptr(E);
ERR_FAIL_COND(!t);
if (t->api != p_api || !t->exposed) {
@@ -66,10 +61,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->method_map.next(k))) {
- String name = k->operator String();
+ for (const KeyValue<StringName, MethodBind *> &F : t->method_map) {
+ String name = F.key.operator String();
ERR_CONTINUE(name.is_empty());
@@ -77,7 +70,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
continue; // Ignore non-virtual methods that start with an underscore
}
- snames.push_back(*k);
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -131,10 +124,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->constant_map.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, int64_t> &F : t->constant_map) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -158,10 +149,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->signal_map.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -193,10 +182,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->property_setget.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, ClassDB::PropertySetGet> &F : t->property_setget) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -238,11 +225,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
}
}
- FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE);
- ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE);
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'.");
JSON json;
f->store_string(json.stringify(classes_dict, "\t"));
- f->close();
print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file));
}
diff --git a/modules/mono/config.py b/modules/mono/config.py
index df02d9a309..d895d2d92d 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,56 +1,48 @@
-supported_platforms = ["windows", "osx", "linuxbsd", "server", "android", "haiku", "javascript", "iphone"]
+supported_platforms = ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"]
def can_build(env, platform):
return not env["arch"].startswith("rv")
-def configure(env):
- platform = env["platform"]
-
- if platform not in supported_platforms:
- raise RuntimeError("This module does not currently support building for this platform")
+def get_opts(platform):
+ from SCons.Variables import BoolVariable, PathVariable
- env.add_module_version_string("mono")
-
- from SCons.Script import BoolVariable, PathVariable, Variables, Help
-
- default_mono_static = platform in ["iphone", "javascript"]
+ default_mono_static = platform in ["ios", "javascript"]
default_mono_bundles_zlib = platform in ["javascript"]
- envvars = Variables()
- envvars.Add(
+ return [
PathVariable(
"mono_prefix",
"Path to the Mono installation directory for the target platform and architecture",
"",
PathVariable.PathAccept,
- )
- )
- envvars.Add(
+ ),
PathVariable(
"mono_bcl",
"Path to a custom Mono BCL (Base Class Library) directory for the target platform",
"",
PathVariable.PathAccept,
- )
- )
- envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static))
- envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True))
- envvars.Add(BoolVariable("build_cil", "Build C# solutions", True))
- envvars.Add(
- BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True)
- )
-
- # TODO: It would be great if this could be detected automatically instead
- envvars.Add(
+ ),
+ BoolVariable("mono_static", "Statically link Mono", default_mono_static),
+ BoolVariable("mono_glue", "Build with the Mono glue sources", True),
+ BoolVariable("build_cil", "Build C# solutions", True),
+ BoolVariable(
+ "copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True
+ ),
BoolVariable(
"mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib
- )
- )
+ ),
+ ]
+
+
+def configure(env):
+ platform = env["platform"]
- envvars.Update(env)
- Help(envvars.GenerateHelpText(env))
+ if platform not in supported_platforms:
+ raise RuntimeError("This module does not currently support building for this platform")
+
+ 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.
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 085ab9a467..475b483d6c 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -45,17 +45,17 @@
#ifdef TOOLS_ENABLED
#include "core/os/keyboard.h"
#include "editor/bindings_generator.h"
+#include "editor/editor_internal_calls.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/node_dock.h"
+#include "editor/script_templates/templates.gen.h"
#endif
#ifdef DEBUG_METHODS_ENABLED
#include "class_db_api_json.h"
#endif
-#include "editor/editor_internal_calls.h"
-#include "editor_templates/templates.gen.h"
#include "godotsharp_dirs.h"
#include "mono_gd/gd_mono_cache.h"
#include "mono_gd/gd_mono_class.h"
@@ -373,11 +373,13 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String
Vector<ScriptLanguage::ScriptTemplate> CSharpLanguage::get_built_in_templates(StringName p_object) {
Vector<ScriptLanguage::ScriptTemplate> templates;
+#ifdef TOOLS_ENABLED
for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
if (TEMPLATES[i].inherit == p_object) {
templates.append(TEMPLATES[i]);
}
}
+#endif
return templates;
}
@@ -386,7 +388,7 @@ String CSharpLanguage::validate_path(const String &p_path) const {
List<String> keywords;
get_reserved_words(&keywords);
if (keywords.find(class_name)) {
- return TTR("Class name can't be a reserved keyword");
+ return RTR("Class name can't be a reserved keyword");
}
return "";
}
@@ -479,11 +481,14 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
Variant::VECTOR3,
Variant::VECTOR3I,
Variant::TRANSFORM2D,
+ Variant::VECTOR4,
+ Variant::VECTOR4I,
Variant::PLANE,
Variant::QUATERNION,
Variant::AABB,
Variant::BASIS,
Variant::TRANSFORM3D,
+ Variant::PROJECTION,
Variant::COLOR,
Variant::STRING_NAME,
Variant::NODE_PATH,
@@ -527,10 +532,10 @@ String CSharpLanguage::make_function(const String &, const String &, const Packe
String CSharpLanguage::_get_indentation() const {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bool use_space_indentation = EDITOR_DEF("text_editor/behavior/indent/type", 0);
+ bool use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type");
if (use_space_indentation) {
- int indent_size = EDITOR_DEF("text_editor/behavior/indent/size", 4);
+ int indent_size = EDITOR_GET("text_editor/behavior/indent/size");
String space_indent = "";
for (int i = 0; i < indent_size; i++) {
@@ -684,10 +689,10 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
#ifdef DEBUG_ENABLED
MutexLock lock(unsafe_object_references_lock);
ObjectID id = p_obj->get_instance_id();
- Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id);
+ HashMap<ObjectID, int>::Iterator elem = unsafe_object_references.find(id);
ERR_FAIL_NULL(elem);
- if (--elem->value() == 0) {
- unsafe_object_references.erase(elem);
+ if (--elem->value == 0) {
+ unsafe_object_references.remove(elem);
}
#endif
}
@@ -873,7 +878,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// Script::instances are deleted during managed object disposal, which happens on domain finalize.
// Only placeholders are kept. Therefore we need to keep a copy before that happens.
- for (Object *&obj : script->instances) {
+ for (Object *obj : script->instances) {
script->pending_reload_instances.insert(obj->get_instance_id());
RefCounted *rc = Object::cast_to<RefCounted>(obj);
@@ -883,7 +888,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#ifdef TOOLS_ENABLED
- for (PlaceHolderScriptInstance *&script_instance : script->placeholders) {
+ for (PlaceHolderScriptInstance *script_instance : script->placeholders) {
Object *obj = script_instance->get_owner();
script->pending_reload_instances.insert(obj->get_instance_id());
@@ -895,9 +900,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#endif
// Save state and remove script from instances
- Map<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
+ RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
- for (Object *&obj : script->instances) {
+ for (Object *obj : script->instances) {
ERR_CONTINUE(!obj->get_script_instance());
CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance());
@@ -920,9 +925,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// After the state of all instances is saved, clear scripts and script instances
for (Ref<CSharpScript> &script : scripts) {
- while (script->instances.front()) {
- Object *obj = script->instances.front()->get();
- obj->set_script(REF()); // Remove script and existing script instances (placeholder are not removed before domain reload)
+ while (script->instances.begin()) {
+ Object *obj = *script->instances.begin();
+ obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
script->_clear();
@@ -1097,14 +1102,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
const StringName &name = G.first;
const Array &serialized_data = G.second;
- Map<StringName, CSharpScript::EventSignal>::Element *match = script->event_signals.find(name);
+ HashMap<StringName, CSharpScript::EventSignal>::Iterator match = script->event_signals.find(name);
if (!match) {
// The event or its signal attribute were removed
continue;
}
- const CSharpScript::EventSignal &event_signal = match->value();
+ const CSharpScript::EventSignal &event_signal = match->value;
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoDelegate *delegate = nullptr;
@@ -1426,7 +1431,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
return true;
}
-Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
+RBMap<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
return script_bindings.insert(p_object, p_script_binding);
}
@@ -1435,7 +1440,7 @@ void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance
MutexLock lock(csharp_lang->language_bind_mutex);
- Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
+ RBMap<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
if (match) {
return (void *)match;
}
@@ -1465,7 +1470,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
{
MutexLock lock(csharp_lang->language_bind_mutex);
- Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding;
+ RBMap<Object *, CSharpScriptBinding>::Element *data = (RBMap<Object *, CSharpScriptBinding>::Element *)p_binding;
CSharpScriptBinding &script_binding = data->value();
@@ -1486,7 +1491,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) {
CRASH_COND(!p_binding);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner);
@@ -1556,7 +1561,7 @@ void *CSharpLanguage::get_instance_binding(Object *p_object) {
// `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that.
if (binding) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)binding)->value();
if (!script_binding.inited) {
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
@@ -1796,9 +1801,7 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
List<PropertyInfo> props;
- for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) {
- props.push_front(E.value());
- }
+ script->get_script_property_list(&props);
// Call _get_property_list
@@ -1893,7 +1896,7 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
return false;
}
-Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+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;
@@ -2136,8 +2139,8 @@ bool CSharpInstance::refcount_decremented() {
return ref_dying;
}
-const Vector<Multiplayer::RPCConfig> CSharpInstance::get_rpc_methods() const {
- return script->get_rpc_methods();
+const Variant CSharpInstance::get_rpc_config() const {
+ return script->get_rpc_config();
}
void CSharpInstance::notification(int p_notification) {
@@ -2299,7 +2302,7 @@ CSharpInstance::~CSharpInstance() {
void *data = CSharpLanguage::get_instance_binding(owner);
CRASH_COND(data == nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
CRASH_COND(!script_binding.inited);
#ifdef DEBUG_ENABLED
@@ -2313,9 +2316,9 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// CSharpInstance must not be created unless it's going to be added to the list for sure
- Set<Object *>::Element *match = script->instances.find(owner);
+ HashSet<Object *>::Iterator match = script->instances.find(owner);
CRASH_COND(!match);
- script->instances.erase(match);
+ script->instances.remove(match);
#else
script->instances.erase(owner);
#endif
@@ -2329,11 +2332,7 @@ void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
#endif
#ifdef TOOLS_ENABLED
-void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
- if (base_cache.is_valid()) {
- base_cache->_update_exports_values(values, propnames);
- }
-
+void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
for (const KeyValue<StringName, Variant> &E : exported_members_defval_cache) {
values[E.key] = E.value;
}
@@ -2341,6 +2340,10 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
for (const PropertyInfo &prop_info : exported_members_cache) {
propnames.push_back(prop_info);
}
+
+ if (base_cache.is_valid()) {
+ base_cache->_update_exports_values(values, propnames);
+ }
}
void CSharpScript::_update_member_info_no_exports() {
@@ -2352,6 +2355,7 @@ void CSharpScript::_update_member_info_no_exports() {
member_info.clear();
GDMonoClass *top = script_class;
+ List<PropertyInfo> props;
while (top && top != native) {
PropertyInfo prop_info;
@@ -2366,7 +2370,7 @@ void CSharpScript::_update_member_info_no_exports() {
StringName member_name = field->get_name();
member_info[member_name] = prop_info;
- exported_members_cache.push_front(prop_info);
+ props.push_front(prop_info);
exported_members_defval_cache[member_name] = Variant();
}
}
@@ -2380,11 +2384,18 @@ void CSharpScript::_update_member_info_no_exports() {
StringName member_name = property->get_name();
member_info[member_name] = prop_info;
- exported_members_cache.push_front(prop_info);
+ props.push_front(prop_info);
exported_members_defval_cache[member_name] = Variant();
}
}
+ exported_members_cache.push_back(PropertyInfo(Variant::NIL, top->get_name(), PROPERTY_HINT_NONE, get_path(), PROPERTY_USAGE_CATEGORY));
+ for (const PropertyInfo &E : props) {
+ exported_members_cache.push_back(E);
+ }
+
+ props.clear();
+
top = top->get_parent_class();
}
}
@@ -2459,6 +2470,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
#endif
GDMonoClass *top = script_class;
+ List<PropertyInfo> props;
while (top && top != native) {
PropertyInfo prop_info;
@@ -2477,7 +2489,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if (exported) {
#ifdef TOOLS_ENABLED
if (is_editor) {
- exported_members_cache.push_front(prop_info);
+ props.push_front(prop_info);
if (tmp_object) {
exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
@@ -2505,7 +2517,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if (exported) {
#ifdef TOOLS_ENABLED
if (is_editor) {
- exported_members_cache.push_front(prop_info);
+ props.push_front(prop_info);
if (tmp_object) {
MonoException *exc = nullptr;
MonoObject *ret = property->get_value(tmp_object, &exc);
@@ -2526,6 +2538,16 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
}
}
+#ifdef TOOLS_ENABLED
+ exported_members_cache.push_back(PropertyInfo(Variant::NIL, top->get_name(), PROPERTY_HINT_NONE, get_path(), PROPERTY_USAGE_CATEGORY));
+
+ for (const PropertyInfo &E : props) {
+ exported_members_cache.push_back(E);
+ }
+
+ props.clear();
+#endif // TOOLS_ENABLED
+
top = top->get_parent_class();
}
@@ -2565,12 +2587,12 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if ((changed || p_instance_to_update) && placeholders.size()) {
// Update placeholders if any
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
if (changed) {
- for (PlaceHolderScriptInstance *&script_instance : placeholders) {
+ for (PlaceHolderScriptInstance *script_instance : placeholders) {
script_instance->update(propnames, values);
}
} else {
@@ -2805,7 +2827,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
GD_MONO_ASSERT_THREAD_ATTACHED;
if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
- r_hint = PROPERTY_HINT_ENUM;
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
+ r_hint = GDMonoUtils::Marshal::type_has_flags_attribute(reftype) ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
@@ -2842,7 +2865,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value.");
- if (val != (unsigned int)i) {
+ unsigned int expected_val = r_hint == PROPERTY_HINT_FLAGS ? 1 << i : i;
+ if (val != expected_val) {
uses_default_values = false;
}
@@ -2862,6 +2886,12 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
r_hint = PROPERTY_HINT_RESOURCE_TYPE;
r_hint_string = String(NATIVE_GDMONOCLASS_NAME(field_native_class));
+ } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(Node)->is_assignable_from(p_type.type_class)) {
+ GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
+ CRASH_COND(field_native_class == nullptr);
+
+ r_hint = PROPERTY_HINT_NODE_TYPE;
+ r_hint_string = String(NATIVE_GDMONOCLASS_NAME(field_native_class));
} else if (p_allow_generics && p_variant_type == Variant::ARRAY) {
// Nested arrays are not supported in the inspector
@@ -2908,7 +2938,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
}
#endif
-Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (unlikely(GDMono::get_singleton() == nullptr)) {
// Probably not the best error but eh.
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
@@ -2936,7 +2966,7 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i
}
// No static method found. Try regular instance calls
- return Script::call(p_method, p_args, p_argcount, r_error);
+ return Script::callp(p_method, p_args, p_argcount, r_error);
}
void CSharpScript::_resource_path_changed() {
@@ -3047,7 +3077,7 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
- p_script->rpc_functions.clear();
+ p_script->rpc_config.clear();
GDMonoClass *top = p_script->script_class;
while (top && top != p_script->native) {
@@ -3059,17 +3089,9 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
Vector<GDMonoMethod *> methods = top->get_all_methods();
for (int i = 0; i < methods.size(); i++) {
if (!methods[i]->is_static()) {
- Multiplayer::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]);
- if (Multiplayer::RPC_MODE_DISABLED != mode) {
- Multiplayer::RPCConfig nd;
- nd.name = methods[i]->get_name();
- nd.rpc_mode = mode;
- // TODO Transfer mode, channel
- nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
- nd.channel = 0;
- if (-1 == p_script->rpc_functions.find(nd)) {
- p_script->rpc_functions.push_back(nd);
- }
+ const Variant rpc_config = p_script->_member_get_rpc_config(methods[i]);
+ if (rpc_config.get_type() != Variant::NIL) {
+ p_script->rpc_config[methods[i]->get_name()] = rpc_config;
}
}
}
@@ -3078,9 +3100,6 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
top = top->get_parent_class();
}
- // Sort so we are 100% that they are always the same.
- p_script->rpc_functions.sort_custom<Multiplayer::SortRPCConfig>();
-
p_script->load_script_signals(p_script->script_class, p_script->native);
}
@@ -3142,7 +3161,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
void *data = CSharpLanguage::get_existing_instance_binding(p_owner);
CRASH_COND(data == nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited && !script_binding.gchandle.is_released()) {
MonoObject *mono_object = script_binding.gchandle.get_target();
if (mono_object) {
@@ -3219,10 +3238,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native));
- REF ref;
+ Ref<RefCounted> ref;
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -3399,9 +3418,9 @@ ScriptLanguage *CSharpScript::get_language() const {
bool CSharpScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
#ifdef TOOLS_ENABLED
- const Map<StringName, Variant>::Element *E = exported_members_defval_cache.find(p_property);
+ HashMap<StringName, Variant>::ConstIterator E = exported_members_defval_cache.find(p_property);
if (E) {
- r_value = E->get();
+ r_value = E->value;
return true;
}
@@ -3489,9 +3508,15 @@ Ref<Script> CSharpScript::get_base_script() const {
void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
List<PropertyInfo> props;
- for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) {
- props.push_front(E.value());
+#ifdef TOOLS_ENABLED
+ for (const PropertyInfo &E : exported_members_cache) {
+ props.push_back(E);
}
+#else
+ for (const KeyValue<StringName, PropertyInfo> &E : member_info) {
+ props.push_front(E.value);
+ }
+#endif // TOOLS_ENABLED
for (const PropertyInfo &prop : props) {
r_list->push_back(prop);
@@ -3503,19 +3528,24 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
-Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const {
- if (p_member->has_attribute(CACHED_CLASS(AnyPeerAttribute))) {
- return Multiplayer::RPC_MODE_ANY_PEER;
- }
- if (p_member->has_attribute(CACHED_CLASS(AuthorityAttribute))) {
- return Multiplayer::RPC_MODE_AUTHORITY;
+Variant CSharpScript::_member_get_rpc_config(IMonoClassMember *p_member) const {
+ Variant out;
+
+ MonoObject *rpc_attribute = p_member->get_attribute(CACHED_CLASS(RPCAttribute));
+ if (rpc_attribute != nullptr) {
+ Dictionary rpc_config;
+ rpc_config["rpc_mode"] = CACHED_PROPERTY(RPCAttribute, Mode)->get_int_value(rpc_attribute);
+ rpc_config["call_local"] = CACHED_PROPERTY(RPCAttribute, CallLocal)->get_bool_value(rpc_attribute);
+ rpc_config["transfer_mode"] = CACHED_PROPERTY(RPCAttribute, TransferMode)->get_int_value(rpc_attribute);
+ rpc_config["channel"] = CACHED_PROPERTY(RPCAttribute, TransferChannel)->get_int_value(rpc_attribute);
+ out = rpc_config;
}
- return Multiplayer::RPC_MODE_DISABLED;
+ return out;
}
-const Vector<Multiplayer::RPCConfig> CSharpScript::get_rpc_methods() const {
- return rpc_functions;
+const Variant CSharpScript::get_rpc_config() const {
+ return rpc_config;
}
Error CSharpScript::load_source_code(const String &p_path) {
@@ -3572,7 +3602,7 @@ CSharpScript::~CSharpScript() {
#endif
}
-void CSharpScript::get_members(Set<StringName> *p_members) {
+void CSharpScript::get_members(HashSet<StringName> *p_members) {
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
if (p_members) {
for (const StringName &member_name : exported_members_names) {
@@ -3584,7 +3614,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -3597,7 +3627,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
Error err = script->load_source_code(p_path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load C# script file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'.");
#endif
script->set_path(p_original_path);
@@ -3623,7 +3653,7 @@ String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path)
return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : "";
}
-Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverCSharpScript::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<CSharpScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
@@ -3639,20 +3669,18 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
}
#endif
- Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
- file->store_string(source);
+ file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
-
#ifdef TOOLS_ENABLED
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false);
@@ -3662,13 +3690,13 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
return OK;
}
-void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverCSharpScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<CSharpScript>(p_resource.ptr())) {
p_extensions->push_back("cs");
}
}
-bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<CSharpScript>(p_resource.ptr()) != nullptr;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 2de923c125..48129e69cb 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -53,8 +53,9 @@ class CSharpLanguage;
#ifdef NO_SAFE_CAST
template <typename TScriptInstance, typename TScriptLanguage>
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
- if (!p_inst)
+ if (!p_inst) {
return nullptr;
+ }
return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : nullptr;
}
#else
@@ -109,7 +110,7 @@ private:
Ref<CSharpScript> base_cache; // TODO what's this for?
- Set<Object *> instances;
+ HashSet<Object *> instances;
#ifdef GD_MONO_HOT_RELOAD
struct StateBackup {
@@ -120,8 +121,8 @@ private:
List<Pair<StringName, Array>> event_signals;
};
- Set<ObjectID> pending_reload_instances;
- Map<ObjectID, StateBackup> pending_reload_state;
+ HashSet<ObjectID> pending_reload_instances;
+ RBMap<ObjectID, StateBackup> pending_reload_state;
StringName tied_class_name_for_reload;
StringName tied_class_namespace_for_reload;
#endif
@@ -131,29 +132,29 @@ private:
SelfList<CSharpScript> script_list = this;
- Map<StringName, Vector<SignalParameter>> _signals;
- Map<StringName, EventSignal> event_signals;
+ HashMap<StringName, Vector<SignalParameter>> _signals;
+ HashMap<StringName, EventSignal> event_signals;
bool signals_invalidated = true;
- Vector<Multiplayer::RPCConfig> rpc_functions;
+ Dictionary rpc_config;
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
- Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
- Set<PlaceHolderScriptInstance *> placeholders;
+ HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
+ HashSet<PlaceHolderScriptInstance *> placeholders;
bool source_changed_cache = false;
bool placeholder_fallback_enabled = false;
bool exports_invalidated = true;
- void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames);
void _update_member_info_no_exports();
void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
- Set<StringName> exported_members_names;
+ HashSet<StringName> exported_members_names;
#endif
- OrderedHashMap<StringName, PropertyInfo> member_info;
+ HashMap<StringName, PropertyInfo> member_info;
void _clear();
@@ -178,12 +179,12 @@ private:
static void update_script_class_info(Ref<CSharpScript> p_script);
static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
- Multiplayer::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const;
+ Variant _member_get_rpc_config(IMonoClassMember *p_member) const;
protected:
static void _bind_methods();
- Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
+ Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
void _resource_path_changed() override;
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
@@ -201,9 +202,9 @@ public:
void set_source_code(const String &p_code) override;
#ifdef TOOLS_ENABLED
- virtual const Vector<DocData::ClassDoc> &get_documentation() const override {
+ virtual Vector<DocData::ClassDoc> get_documentation() const override {
// TODO
- static Vector<DocData::ClassDoc> docs;
+ Vector<DocData::ClassDoc> docs;
return docs;
}
#endif // TOOLS_ENABLED
@@ -217,7 +218,7 @@ public:
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
- void get_members(Set<StringName> *p_members) override;
+ void get_members(HashSet<StringName> *p_members) override;
bool is_tool() const override { return tool; }
bool is_valid() const override { return valid; }
@@ -233,7 +234,7 @@ public:
int get_member_line(const StringName &p_member) const override;
- const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override;
+ const Variant get_rpc_config() const override;
#ifdef TOOLS_ENABLED
bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
@@ -294,7 +295,7 @@ public:
void get_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
- Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
+ Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
void mono_object_disposed(MonoObject *p_obj);
@@ -310,7 +311,7 @@ public:
void refcount_incremented() override;
bool refcount_decremented() override;
- const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override;
+ const Variant get_rpc_config() const override;
void notification(int p_notification) override;
void _call_notification(int p_notification);
@@ -355,11 +356,11 @@ class CSharpLanguage : public ScriptLanguage {
Mutex script_gchandle_release_mutex;
Mutex language_bind_mutex;
- Map<Object *, CSharpScriptBinding> script_bindings;
+ RBMap<Object *, CSharpScriptBinding> script_bindings;
#ifdef DEBUG_ENABLED
// List of unsafe object references
- Map<ObjectID, int> unsafe_object_references;
+ HashMap<ObjectID, int> unsafe_object_references;
Mutex unsafe_object_references_lock;
#endif
@@ -466,7 +467,7 @@ public:
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
/* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions,
- List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override {
+ List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override {
return true;
}
String validate_path(const String &p_path) const override;
@@ -501,6 +502,7 @@ public:
/* TODO? */ void get_public_functions(List<MethodInfo> *p_functions) const override {}
/* TODO? */ void get_public_constants(List<Pair<String, Variant>> *p_constants) const override {}
+ /* TODO? */ void get_public_annotations(List<MethodInfo> *p_annotations) const override {}
void reload_all_scripts() override;
void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override;
@@ -517,7 +519,7 @@ public:
void thread_enter() override;
void thread_exit() override;
- Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
+ 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);
#ifdef DEBUG_ENABLED
@@ -533,7 +535,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
void get_recognized_extensions(List<String> *p_extensions) const override;
bool handles_type(const String &p_type) const override;
String get_resource_type(const String &p_path) const override;
@@ -541,9 +543,9 @@ public:
class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
public:
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override;
- void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override;
- bool recognize(const RES &p_resource) const override;
+ Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
+ void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
+ bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // CSHARP_SCRIPT_H
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index 14c62b4bb0..f8293fb107 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSharpScript" inherits="Script" version="4.0">
+<class name="CSharpScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A script implemented in the C# programming language (Mono-enabled builds only).
</brief_description>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index a148072245..b981542801 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" version="4.0">
+<class name="GodotSharp" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Bridge between Godot and the Mono runtime (Mono-enabled builds only).
</brief_description>
@@ -38,7 +38,7 @@
</method>
<method name="is_domain_finalizing_for_unload">
<return type="bool" />
- <argument index="0" name="domain_id" type="int" />
+ <param index="0" name="domain_id" type="int" />
<description>
Returns [code]true[/code] if the domain is being finalized, [code]false[/code] otherwise.
</description>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 0128f5c706..5a499742e9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -57,7 +57,7 @@
<PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(FreeBSD))' ">linuxbsd</GodotTargetPlatform>
- <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">osx</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">macos</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Windows))' ">windows</GodotTargetPlatform>
</PropertyGroup>
@@ -76,12 +76,12 @@
-->
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants>
- <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'osx' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants>
+ <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'server' ">GODOT_SERVER;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants>
- <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'iphone' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
+ <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'javascript' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants>
<GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants)</GodotDefineConstants>
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 ae78da27bc..303ca3a293 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
@@ -12,6 +12,6 @@
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj
index dad6b9ae7a..02f1764f32 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj
@@ -19,6 +19,6 @@ A client using this library is only compatible with servers of the same major ve
</Description>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index 56fca6b5cb..ebdaca0ce8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -334,8 +334,13 @@ namespace GodotTools.Build
}
}
- private void IssuesListRmbSelected(int index, Vector2 atPosition)
+ private void IssuesListClicked(int index, Vector2 atPosition, int mouseButtonIndex)
{
+ if (mouseButtonIndex != (int)MouseButton.Right)
+ {
+ return;
+ }
+
_ = index; // Unused
_issuesListContextMenu.Clear();
@@ -350,7 +355,7 @@ namespace GodotTools.Build
if (_issuesListContextMenu.ItemCount > 0)
{
- _issuesListContextMenu.Position = (Vector2i)(_issuesList.RectGlobalPosition + atPosition);
+ _issuesListContextMenu.Position = (Vector2i)(_issuesList.GlobalPosition + atPosition);
_issuesListContextMenu.Popup();
}
}
@@ -375,7 +380,7 @@ namespace GodotTools.Build
};
_issuesList.ItemActivated += IssueActivated;
_issuesList.AllowRmbSelect = true;
- _issuesList.ItemRmbSelected += IssuesListRmbSelected;
+ _issuesList.ItemClicked += IssuesListClicked;
hsc.AddChild(_issuesList);
_issuesListContextMenu = new PopupMenu();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index bac7a2e6db..02e9d98647 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -63,6 +63,7 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
+ startInfo.CreateNoWindow = true;
if (UsingMonoMsBuildOnWindows)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 2dbc78ab77..3c020a2589 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -126,7 +126,7 @@ namespace GodotTools.Build
{
base._Ready();
- RectMinSize = new Vector2(0, 228) * EditorScale;
+ CustomMinimumSize = new Vector2(0, 228) * EditorScale;
SizeFlagsVertical = (int)SizeFlags.ExpandFill;
var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill };
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index 16dd1c8c6b..63b97e981e 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -99,7 +99,7 @@ namespace GodotTools.Build
if (Utils.OS.IsWindows)
{
// %APPDATA% for both
- return new[] {Path.Combine(applicationData, "NuGet", "NuGet.Config")};
+ return new[] { Path.Combine(applicationData, "NuGet", "NuGet.Config") };
}
var paths = new string[2];
@@ -156,6 +156,7 @@ namespace GodotTools.Build
</packageSources>
</configuration>
";
+ System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index ed758cc137..e9718cc82c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -107,7 +107,7 @@ namespace GodotTools.Export
ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
// The Godot exporter expects us to pass the abi in the tags parameter
- exporter.AddSharedObject(soFilePath, tags: new[] { abi });
+ exporter.AddSharedObject(soFilePath, tags: new[] { abi }, "");
}
}
}
@@ -134,7 +134,7 @@ namespace GodotTools.Export
if (platform == OS.Platforms.MacOS)
{
- exporter.AddSharedObject(tempOutputFilePath, tags: null);
+ exporter.AddSharedObject(tempOutputFilePath, tags: null, "");
}
else
{
@@ -336,10 +336,10 @@ MONO_AOT_MODE_LAST = 1000,
// Add the required Mono libraries to the Xcode project
- string MonoLibFile(string libFileName) => libFileName + ".iphone.fat.a";
+ string MonoLibFile(string libFileName) => libFileName + ".ios.fat.a";
string MonoLibFromTemplate(string libFileName) =>
- Path.Combine(Internal.FullTemplatesDir, "iphone-mono-libs", MonoLibFile(libFileName));
+ Path.Combine(Internal.FullExportTemplatesDir, "ios-mono-libs", MonoLibFile(libFileName));
exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmonosgen-2.0"));
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 3e46a89b7c..cca18a2a1f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -337,7 +337,7 @@ namespace GodotTools.Export
string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}";
- string templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName());
+ string templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName());
bool validTemplatePathFound = true;
if (!Directory.Exists(templateDirPath))
@@ -347,7 +347,7 @@ namespace GodotTools.Export
if (isDebug)
{
target = "debug"; // Support both 'release_debug' and 'debug' for the template data directory name
- templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName());
+ templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName());
validTemplatePathFound = true;
if (!Directory.Exists(templateDirPath))
@@ -380,7 +380,7 @@ namespace GodotTools.Export
private static bool PlatformHasTemplateDir(string platform)
{
- // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
+ // macOS export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform);
}
@@ -398,13 +398,13 @@ namespace GodotTools.Export
private static string GetBclProfileDir(string profile)
{
- string templatesDir = Internal.FullTemplatesDir;
+ string templatesDir = Internal.FullExportTemplatesDir;
return Path.Combine(templatesDir, "bcl", profile);
}
private static string DeterminePlatformBclDir(string platform)
{
- string templatesDir = Internal.FullTemplatesDir;
+ string templatesDir = Internal.FullExportTemplatesDir;
string platformBclDir = Path.Combine(templatesDir, "bcl", platform);
if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll")))
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 69960bdbeb..b39c3d1c0d 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -263,16 +263,16 @@ namespace GodotTools
var args = new List<string>();
- bool osxAppBundleInstalled = false;
+ bool macOSAppBundleInstalled = false;
if (OS.IsMacOS)
{
// The package path is '/Applications/Visual Studio Code.app'
const string vscodeBundleId = "com.microsoft.VSCode";
- osxAppBundleInstalled = Internal.IsOsxAppBundleInstalled(vscodeBundleId);
+ macOSAppBundleInstalled = Internal.IsMacOSAppBundleInstalled(vscodeBundleId);
- if (osxAppBundleInstalled)
+ if (macOSAppBundleInstalled)
{
args.Add("-b");
args.Add(vscodeBundleId);
@@ -307,13 +307,13 @@ namespace GodotTools
if (OS.IsMacOS)
{
- if (!osxAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath))
+ if (!macOSAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath))
{
GD.PushError("Cannot find code editor: VSCode");
return Error.FileNotFound;
}
- command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath;
+ command = macOSAppBundleInstalled ? "/usr/bin/open" : _vsCodePath;
}
else
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index b9aa760f4d..f1d45463c5 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -19,7 +19,7 @@
<ItemGroup>
<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="12.0.3" />
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<Reference Include="GodotSharp">
<HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath>
<Private>False</Private>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs
index 3f1d5ac3ca..7a0983a8cb 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs
@@ -30,7 +30,7 @@ namespace GodotTools.Ides.MonoDevelop
{
string bundleId = BundleIds[_editorId];
- if (Internal.IsOsxAppBundleInstalled(bundleId))
+ if (Internal.IsMacOSAppBundleInstalled(bundleId))
{
command = "open";
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index ac29efb716..3440eb701c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -66,6 +66,9 @@ namespace GodotTools.Ides.Rider
if (string.IsNullOrEmpty(path))
return false;
+ if (path.IndexOfAny(Path.GetInvalidPathChars()) != -1)
+ return false;
+
var fileInfo = new FileInfo(path);
string filename = fileInfo.Name.ToLowerInvariant();
return filename.StartsWith("rider", StringComparison.Ordinal);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 77370090ec..12c90178c9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -12,12 +12,12 @@ namespace GodotTools.Internals
public static string UpdateApiAssembliesFromPrebuilt(string config) =>
internal_UpdateApiAssembliesFromPrebuilt(config);
- public static string FullTemplatesDir =>
- internal_FullTemplatesDir();
+ public static string FullExportTemplatesDir =>
+ internal_FullExportTemplatesDir();
public static string SimplifyGodotPath(this string path) => internal_SimplifyGodotPath(path);
- public static bool IsOsxAppBundleInstalled(string bundleId) => internal_IsOsxAppBundleInstalled(bundleId);
+ public static bool IsMacOSAppBundleInstalled(string bundleId) => internal_IsMacOSAppBundleInstalled(bundleId);
public static bool GodotIs32Bits() => internal_GodotIs32Bits();
@@ -57,13 +57,13 @@ namespace GodotTools.Internals
private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_FullTemplatesDir();
+ private static extern string internal_FullExportTemplatesDir();
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string internal_SimplifyGodotPath(this string path);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsOsxAppBundleInstalled(string bundleId);
+ private static extern bool internal_IsMacOSAppBundleInstalled(string bundleId);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool internal_GodotIs32Bits();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 93a1360cb6..5cef6e5c3c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -37,13 +37,13 @@ namespace GodotTools.Utils
public static class Platforms
{
public const string Windows = "windows";
- public const string MacOS = "osx";
+ public const string MacOS = "macos";
public const string LinuxBSD = "linuxbsd";
public const string Server = "server";
public const string UWP = "uwp";
public const string Haiku = "haiku";
public const string Android = "android";
- public const string iOS = "iphone";
+ public const string iOS = "ios";
public const string HTML5 = "javascript";
}
@@ -184,7 +184,8 @@ namespace GodotTools.Utils
{
RedirectStandardOutput = true,
RedirectStandardError = true,
- UseShellExecute = false
+ UseShellExecute = false,
+ CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index f345dff333..2e628cb576 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -100,6 +100,9 @@
#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
+// Types that will be ignored by the generator and won't be available in C#.
+const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
+
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
static String fix_doc_description(const String &p_bbcode) {
@@ -278,12 +281,12 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
} else if (code_tag) {
xml_output.append("[");
pos = brk_pos + 1;
- } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) {
+ } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ")) {
const int tag_end = tag.find(" ");
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
- Vector<String> link_target_parts = link_target.split(".");
+ const Vector<String> link_target_parts = link_target.split(".");
if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) {
ERR_PRINT("Invalid reference format: '" + tag + "'.");
@@ -311,201 +314,18 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
}
if (link_tag == "method") {
- if (!target_itype || !target_itype->is_object_type) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- if (target_itype) {
- OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
- } else {
- OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data());
- }
- }
-
- // TODO Map what we can
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- } else {
- const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname);
-
- if (target_imethod) {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_itype->proxy_name);
- xml_output.append(".");
- xml_output.append(target_imethod->proxy_name);
- xml_output.append("\"/>");
- }
- }
+ _append_xml_method(xml_output, target_itype, target_cname, link_target, link_target_parts);
} else if (link_tag == "member") {
- if (!target_itype || !target_itype->is_object_type) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- if (target_itype) {
- OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
- } else {
- OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data());
- }
- }
-
- // TODO Map what we can
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- } else {
- const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname);
-
- if (target_iprop) {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_itype->proxy_name);
- xml_output.append(".");
- xml_output.append(target_iprop->proxy_name);
- xml_output.append("\"/>");
- }
- }
+ _append_xml_member(xml_output, target_itype, target_cname, link_target, link_target_parts);
} else if (link_tag == "signal") {
- if (!target_itype || !target_itype->is_object_type) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- if (target_itype) {
- OS::get_singleton()->print("Cannot resolve signal reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
- } else {
- OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", link_target.utf8().get_data());
- }
- }
-
- // TODO Map what we can
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- } else {
- const SignalInterface *target_isignal = target_itype->find_signal_by_name(target_cname);
-
- if (target_isignal) {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_itype->proxy_name);
- xml_output.append(".");
- xml_output.append(target_isignal->proxy_name);
- xml_output.append("\"/>");
- } else {
- ERR_PRINT("Cannot resolve signal reference in documentation: '" + link_target + "'.");
-
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- }
- }
+ _append_xml_signal(xml_output, target_itype, target_cname, link_target, link_target_parts);
} else if (link_tag == "enum") {
- const StringName search_cname = !target_itype ? target_cname : StringName(target_itype->name + "." + (String)target_cname);
-
- const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname);
-
- if (!enum_match && search_cname != target_cname) {
- enum_match = enum_types.find(target_cname);
- }
-
- if (enum_match) {
- const TypeInterface &target_enum_itype = enum_match->value();
-
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
- xml_output.append("\"/>");
- } else {
- ERR_PRINT("Cannot resolve enum reference in documentation: '" + link_target + "'.");
-
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- }
+ _append_xml_enum(xml_output, target_itype, target_cname, link_target, link_target_parts);
} else if (link_tag == "constant") {
- if (!target_itype || !target_itype->is_object_type) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- if (target_itype) {
- OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
- } else {
- OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data());
- }
- }
-
- // TODO Map what we can
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) {
- const String target_name = (String)target_cname;
-
- // Try to find as a global constant
- const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants);
-
- if (target_iconst) {
- // Found global constant
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS ".");
- xml_output.append(target_iconst->proxy_name);
- xml_output.append("\"/>");
- } else {
- // Try to find as global enum constant
- const EnumInterface *target_ienum = nullptr;
-
- for (const EnumInterface &ienum : global_enums) {
- target_ienum = &ienum;
- target_iconst = find_constant_by_name(target_name, target_ienum->constants);
- if (target_iconst) {
- break;
- }
- }
-
- if (target_iconst) {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_ienum->cname);
- xml_output.append(".");
- xml_output.append(target_iconst->proxy_name);
- xml_output.append("\"/>");
- } else {
- ERR_PRINT("Cannot resolve global constant reference in documentation: '" + link_target + "'.");
-
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- }
- }
- } else {
- const String target_name = (String)target_cname;
-
- // Try to find the constant in the current class
- const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants);
-
- if (target_iconst) {
- // Found constant in current class
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_itype->proxy_name);
- xml_output.append(".");
- xml_output.append(target_iconst->proxy_name);
- xml_output.append("\"/>");
- } else {
- // Try to find as enum constant in the current class
- const EnumInterface *target_ienum = nullptr;
-
- for (const EnumInterface &ienum : target_itype->enums) {
- target_ienum = &ienum;
- target_iconst = find_constant_by_name(target_name, target_ienum->constants);
- if (target_iconst) {
- break;
- }
- }
-
- if (target_iconst) {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
- xml_output.append(target_itype->proxy_name);
- xml_output.append(".");
- xml_output.append(target_ienum->cname);
- xml_output.append(".");
- xml_output.append(target_iconst->proxy_name);
- xml_output.append("\"/>");
- } else {
- ERR_PRINT("Cannot resolve constant reference in documentation: '" + link_target + "'.");
-
- xml_output.append("<c>");
- xml_output.append(link_target);
- xml_output.append("</c>");
- }
- }
- }
+ _append_xml_constant(xml_output, target_itype, target_cname, link_target, link_target_parts);
+ } else if (link_tag == "theme_item") {
+ // We do not declare theme_items in any way in C#, so there is nothing to reference
+ _append_xml_undeclared(xml_output, link_target);
}
pos = brk_end + 1;
@@ -670,6 +490,240 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
return xml_output.as_string();
}
+void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+
+ // TODO Map what we can
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else {
+ if (p_target_cname == "_init") {
+ // The _init method is not declared in C#, reference the constructor instead
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append("()\"/>");
+ } else {
+ const MethodInterface *target_imethod = p_target_itype->find_method_by_name(p_target_cname);
+
+ if (target_imethod) {
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(target_imethod->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+ }
+ }
+}
+
+void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target.find("/") >= 0) {
+ // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference.
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else {
+ const TypeInterface *current_itype = p_target_itype;
+ const PropertyInterface *target_iprop = nullptr;
+
+ while (target_iprop == nullptr && current_itype != nullptr) {
+ target_iprop = current_itype->find_property_by_name(p_target_cname);
+ if (target_iprop == nullptr) {
+ current_itype = _get_type_or_null(TypeReference(current_itype->base_name));
+ }
+ }
+
+ if (target_iprop) {
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(current_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(target_iprop->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (!p_target_itype || !p_target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve signal reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else {
+ const SignalInterface *target_isignal = p_target_itype->find_signal_by_name(p_target_cname);
+
+ if (target_isignal) {
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(target_isignal->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname);
+
+ HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(search_cname);
+
+ if (!enum_match && search_cname != p_target_cname) {
+ enum_match = enum_types.find(p_target_cname);
+ }
+
+ if (enum_match) {
+ const TypeInterface &target_enum_itype = enum_match->value;
+
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
+ p_xml_output.append("\"/>");
+ } else {
+ ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+}
+
+void BindingsGenerator::_append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
+ if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) {
+ _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target);
+ } else if (!p_target_itype || !p_target_itype->is_object_type) {
+ // Search in @GlobalScope as a last resort if no class was specified
+ if (p_link_target_parts.size() == 1) {
+ _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target);
+ return;
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (p_target_itype) {
+ OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", p_link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ } else {
+ // Try to find the constant in the current class
+ const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, p_target_itype->constants);
+
+ if (target_iconst) {
+ // Found constant in current class
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(target_iconst->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ // Try to find as enum constant in the current class
+ const EnumInterface *target_ienum = nullptr;
+
+ for (const EnumInterface &ienum : p_target_itype->enums) {
+ target_ienum = &ienum;
+ target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants);
+ if (target_iconst) {
+ break;
+ }
+ }
+
+ if (target_iconst) {
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(p_target_itype->proxy_name);
+ p_xml_output.append(".");
+ p_xml_output.append(target_ienum->cname);
+ p_xml_output.append(".");
+ p_xml_output.append(target_iconst->proxy_name);
+ p_xml_output.append("\"/>");
+ } else if (p_link_target_parts.size() == 1) {
+ // Also search in @GlobalScope as a last resort if no class was specified
+ _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target);
+ } else {
+ ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+ }
+ }
+}
+
+void BindingsGenerator::_append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target) {
+ // Try to find as a global constant
+ const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, global_constants);
+
+ if (target_iconst) {
+ // Found global constant
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS ".");
+ p_xml_output.append(target_iconst->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ // Try to find as global enum constant
+ const EnumInterface *target_ienum = nullptr;
+
+ for (const EnumInterface &ienum : global_enums) {
+ target_ienum = &ienum;
+ target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants);
+ if (target_iconst) {
+ break;
+ }
+ }
+
+ if (target_iconst) {
+ p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ p_xml_output.append(target_ienum->cname);
+ p_xml_output.append(".");
+ p_xml_output.append(target_iconst->proxy_name);
+ p_xml_output.append("\"/>");
+ } else {
+ ERR_PRINT("Cannot resolve global constant reference in documentation: '" + p_link_target + "'.");
+ _append_xml_undeclared(p_xml_output, p_link_target);
+ }
+ }
+}
+
+void BindingsGenerator::_append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target) {
+ p_xml_output.append("<c>");
+ p_xml_output.append(p_link_target);
+ p_xml_output.append("</c>");
+}
+
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
CRASH_COND(p_ienum.constants.is_empty());
@@ -748,10 +802,13 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
- String im_sig = "IntPtr " CS_PARAM_METHODBIND ", ";
- String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr,IntPtr";
+ String im_sig = "IntPtr " CS_PARAM_METHODBIND;
+ String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr";
- im_sig += "IntPtr " CS_PARAM_INSTANCE;
+ if (!imethod.is_static) {
+ im_sig += ", IntPtr " CS_PARAM_INSTANCE;
+ im_unique_sig += ",IntPtr";
+ }
// Get arguments information
int i = 0;
@@ -860,6 +917,8 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
ARRAY_ALL(Vector2i);
ARRAY_ALL(Vector3);
ARRAY_ALL(Vector3i);
+ ARRAY_ALL(Vector4);
+ ARRAY_ALL(Vector4i);
#undef ARRAY_ALL
#undef ARRAY_IS_EMPTY
@@ -897,7 +956,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
}
}
- p_output.append(MEMBER_BEGIN "public const int ");
+ p_output.append(MEMBER_BEGIN "public const long ");
p_output.append(iconstant.proxy_name);
p_output.append(" = ");
p_output.append(itos(iconstant.value));
@@ -933,8 +992,13 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n" INDENT1 OPEN_BLOCK);
}
+ if (ienum.is_flags) {
+ p_output.append("\n" INDENT1 "[System.Flags]");
+ }
+
p_output.append("\n" INDENT1 "public enum ");
p_output.append(enum_proxy_name);
+ p_output.append(" : long");
p_output.append("\n" INDENT1 OPEN_BLOCK);
const ConstantInterface &last = ienum.constants.back()->get();
@@ -978,8 +1042,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1021,8 +1085,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- const TypeInterface &itype = E.get();
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ const TypeInterface &itype = E.value;
if (itype.api_type == ClassDB::API_EDITOR) {
continue;
@@ -1113,8 +1177,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1130,8 +1194,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
Vector<String> compile_items;
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- const TypeInterface &itype = E.get();
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ const TypeInterface &itype = E.value;
if (itype.api_type != ClassDB::API_EDITOR) {
continue;
@@ -1223,8 +1287,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
String output_dir = path::abspath(path::realpath(p_output_dir));
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(output_dir)) {
Error err = da->make_dir_recursive(output_dir);
@@ -1360,7 +1424,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
}
- output.append(MEMBER_BEGIN "public const int ");
+ output.append(MEMBER_BEGIN "public const long ");
output.append(iconstant.proxy_name);
output.append(" = ");
output.append(itos(iconstant.value));
@@ -1376,8 +1440,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
for (const EnumInterface &ienum : itype.enums) {
ERR_FAIL_COND_V(ienum.constants.is_empty(), ERR_BUG);
+ if (ienum.is_flags) {
+ output.append(MEMBER_BEGIN "[System.Flags]");
+ }
+
output.append(MEMBER_BEGIN "public enum ");
output.append(ienum.cname.operator String());
+ output.append(" : long");
output.append(MEMBER_BEGIN OPEN_BLOCK);
const ConstantInterface &last = ienum.constants.back()->get();
@@ -1516,9 +1585,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// Search it in base types too
const TypeInterface *current_type = &p_itype;
while (!setter && current_type->base_name != StringName()) {
- OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+ HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
- current_type = &base_match.get();
+ current_type = &base_match->value;
setter = current_type->find_method_by_name(p_iprop.setter);
}
@@ -1527,9 +1596,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// Search it in base types too
current_type = &p_itype;
while (!getter && current_type->base_name != StringName()) {
- OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+ HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
- current_type = &base_match.get();
+ current_type = &base_match->value;
getter = current_type->find_method_by_name(p_iprop.getter);
}
@@ -1595,7 +1664,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append("static ");
}
- p_output.append(prop_itype->cs_type);
+ String prop_cs_type = prop_itype->cs_type + _get_generic_type_parameters(*prop_itype, proptype_name.generic_type_parameters);
+
+ p_output.append(prop_cs_type);
p_output.append(" ");
p_output.append(p_iprop.proxy_name);
p_output.append("\n" INDENT2 OPEN_BLOCK);
@@ -1679,8 +1750,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arguments_sig;
String cs_in_statements;
- String icall_params = method_bind_field + ", ";
- icall_params += sformat(p_itype.cs_in, "this");
+ String icall_params = method_bind_field;
+ if (!p_imethod.is_static) {
+ icall_params += ", " + sformat(p_itype.cs_in, "this");
+ }
StringBuilder default_args_doc;
@@ -1703,6 +1776,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
"Invalid default value for parameter '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
}
+ String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
+
// Add the current arguments to the signature
// If the argument has a default value which is not a constant, we will make it Nullable
{
@@ -1714,7 +1789,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
arguments_sig += "Nullable<";
}
- arguments_sig += arg_type->cs_type;
+ arguments_sig += arg_cs_type;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
arguments_sig += "> ";
@@ -1741,7 +1816,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String arg_in = iarg.name;
arg_in += "_in";
- cs_in_statements += arg_type->cs_type;
+ cs_in_statements += arg_cs_type;
cs_in_statements += " ";
cs_in_statements += arg_in;
cs_in_statements += " = ";
@@ -1761,7 +1836,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_in_statements += " : ";
}
- String cs_type = arg_type->cs_type;
+ String cs_type = arg_cs_type;
if (cs_type.ends_with("[]")) {
cs_type = cs_type.substr(0, cs_type.length() - 2);
}
@@ -1778,7 +1853,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Escape < and > in the attribute default value
String param_def_arg = def_arg.replacen("<", "&lt;").replacen(">", "&gt;");
- default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + param_def_arg + "</param>");
+ default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is <c>" + param_def_arg + "</c>.</param>");
} else {
icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
}
@@ -1838,13 +1913,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(MEMBER_BEGIN);
p_output.append(p_imethod.is_internal ? "internal " : "public ");
- if (p_itype.is_singleton) {
+ if (p_itype.is_singleton || p_imethod.is_static) {
p_output.append("static ");
} else if (p_imethod.is_virtual) {
p_output.append("virtual ");
}
- p_output.append(return_type->cs_type + " ");
+ String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters);
+
+ p_output.append(return_cs_type + " ");
p_output.append(p_imethod.proxy_name + "(");
p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L2);
@@ -1855,7 +1932,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("return;\n" CLOSE_BLOCK_L2);
} else {
p_output.append("return default(");
- p_output.append(return_type->cs_type);
+ p_output.append(return_cs_type);
p_output.append(");\n" CLOSE_BLOCK_L2);
}
@@ -1879,10 +1956,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
return OK; // Won't increment method bind count
}
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
ERR_FAIL_NULL_V(match, ERR_BUG);
- const InternalCall *im_icall = match->value();
+ const InternalCall *im_icall = match->value;
String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
im_call += ".";
@@ -1897,7 +1974,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
} else if (return_type->cs_out.is_empty()) {
p_output.append("return " + im_call + "(" + icall_params + ");\n");
} else {
- p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_type->cs_type, return_type->im_type_out));
+ p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_cs_type, return_type->im_type_out));
p_output.append("\n");
}
@@ -2037,8 +2114,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
generated_icall_funcs.clear();
- for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) {
- const TypeInterface &itype = type_elem.get();
+ for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) {
+ const TypeInterface &itype = type_elem.value;
bool is_derived_type = itype.base_name != StringName();
@@ -2149,8 +2226,9 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
}
output.append("#ifdef TOOLS_ENABLED\n");
- for (const InternalCall &internal_call : editor_custom_icalls)
+ for (const InternalCall &internal_call : editor_custom_icalls) {
ADD_INTERNAL_CALL_REGISTRATION(internal_call);
+ }
output.append("#endif // TOOLS_ENABLED\n");
for (const InternalCall &internal_call : method_icalls) {
@@ -2195,12 +2273,10 @@ uint32_t BindingsGenerator::get_version() {
}
Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
-
- ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
file->store_string(p_content.as_string());
- file->close();
return OK;
}
@@ -2216,7 +2292,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String argc_str = itos(p_imethod.arguments.size());
- String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND;
+ if (!p_imethod.is_static) {
+ c_func_sig += ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ }
String c_in_statements;
String c_args_var_content;
@@ -2261,10 +2340,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
i++;
}
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
ERR_FAIL_NULL_V(match, ERR_BUG);
- const InternalCall *im_icall = match->value();
+ const InternalCall *im_icall = match->value;
String icall_method = im_icall->name;
if (!generated_icall_funcs.find(im_icall)) {
@@ -2308,17 +2387,21 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()";
- if (return_type->ret_as_byref_arg) {
- p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
- p_output.append(fail_ret);
- p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
- } else {
- p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
- p_output.append(fail_ret);
- p_output.append(");\n");
+ if (!p_imethod.is_static) {
+ if (return_type->ret_as_byref_arg) {
+ p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
+ p_output.append(fail_ret);
+ p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
+ } else {
+ p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
+ p_output.append(fail_ret);
+ p_output.append(");\n");
+ }
}
} else {
- p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ if (!p_imethod.is_static) {
+ p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ }
}
if (p_imethod.arguments.size()) {
@@ -2362,7 +2445,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
}
- p_output.append(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
+ p_output.append(CS_PARAM_METHODBIND "->call(");
+ p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
+ p_output.append(", ");
p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr");
p_output.append(", total_length, vcall_error);\n");
@@ -2373,7 +2458,9 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
}
} else {
- p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
+ p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(");
+ p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
+ p_output.append(", ");
p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, ");
p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n");
}
@@ -2399,29 +2486,29 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(const TypeReference &p_typeref) {
- const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator builtin_type_match = builtin_types.find(p_typeref.cname);
if (builtin_type_match) {
- return &builtin_type_match->get();
+ return &builtin_type_match->value;
}
- const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator obj_type_match = obj_types.find(p_typeref.cname);
if (obj_type_match) {
- return &obj_type_match.get();
+ return &obj_type_match->value;
}
if (p_typeref.is_enum) {
- const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(p_typeref.cname);
if (enum_match) {
- return &enum_match->get();
+ return &enum_match->value;
}
// Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead.
- const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int);
+ HashMap<StringName, TypeInterface>::ConstIterator int_match = builtin_types.find(name_cache.type_int);
ERR_FAIL_NULL_V(int_match, nullptr);
- return &int_match->get();
+ return &int_match->value;
}
return nullptr;
@@ -2436,16 +2523,52 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
ERR_PRINT(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'.");
- const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator match = placeholder_types.find(p_typeref.cname);
if (match) {
- return &match->get();
+ return &match->value;
}
TypeInterface placeholder;
TypeInterface::create_placeholder_type(placeholder, p_typeref.cname);
- return &placeholder_types.insert(placeholder.cname, placeholder)->get();
+ return &placeholder_types.insert(placeholder.cname, placeholder)->value;
+}
+
+const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters) {
+ if (p_generic_type_parameters.is_empty()) {
+ return "";
+ }
+
+ ERR_FAIL_COND_V_MSG(p_itype.type_parameter_count != p_generic_type_parameters.size(), "",
+ "Generic type parameter count mismatch for type '" + p_itype.name + "'." +
+ " Found " + itos(p_generic_type_parameters.size()) + ", but requires " +
+ itos(p_itype.type_parameter_count) + ".");
+
+ int i = 0;
+ String params = "<";
+ for (const TypeReference &param_type : p_generic_type_parameters) {
+ const TypeInterface *param_itype = _get_type_or_placeholder(param_type);
+
+ ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "",
+ "Generic type parameter is a singleton: '" + param_itype->name + "'.");
+
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(param_itype->api_type == ClassDB::API_EDITOR, "",
+ "Generic type parameter '" + param_itype->name + "' has type from the editor API." +
+ " Core API cannot have dependencies on the editor API.");
+ }
+
+ params += param_itype->cs_type;
+ if (i < p_generic_type_parameters.size() - 1) {
+ params += ", ";
+ }
+
+ i++;
+ }
+ params += ">";
+
+ return params;
}
StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
@@ -2593,6 +2716,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
continue;
}
+ if (ignored_types.has(type_cname)) {
+ _log("Ignoring type '%s' because it's in the list of ignored types\n", String(type_cname).utf8().get_data());
+ class_list.pop_front();
+ continue;
+ }
+
if (!ClassDB::is_class_exposed(type_cname)) {
_log("Ignoring type '%s' because it's not exposed\n", String(type_cname).utf8().get_data());
class_list.pop_front();
@@ -2633,7 +2762,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
List<PropertyInfo> property_list;
ClassDB::get_property_list(type_cname, &property_list, true);
- Map<StringName, StringName> accessor_methods;
+ HashMap<StringName, StringName> accessor_methods;
for (const PropertyInfo &property : property_list) {
if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY || (property.type == Variant::NIL && property.usage & PROPERTY_USAGE_ARRAY)) {
@@ -2711,6 +2840,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
imethod.name = method_info.name;
imethod.cname = cname;
+ if (method_info.flags & METHOD_FLAG_STATIC) {
+ imethod.is_static = true;
+ }
+
if (method_info.flags & METHOD_FLAG_VIRTUAL) {
imethod.is_virtual = true;
}
@@ -2742,7 +2875,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
" We only expected Object.free, but found '" +
itype.name + "." + imethod.name + "'.");
}
- } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ } else if (return_info.type == Variant::INT && return_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
imethod.return_type.cname = return_info.class_name;
imethod.return_type.is_enum = true;
} else if (return_info.class_name != StringName()) {
@@ -2753,6 +2886,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ERR_FAIL_COND_V_MSG(bad_reference_hint, false,
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
+ } else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string));
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type.cname = return_info.hint_string;
} else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
@@ -2777,11 +2913,14 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ArgumentInterface iarg;
iarg.name = orig_arg_name;
- if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ if (arginfo.type == Variant::INT && arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
iarg.type.cname = arginfo.class_name;
iarg.type.is_enum = true;
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
+ } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
@@ -2824,9 +2963,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
imethod.proxy_name += "_";
}
- Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname);
+ HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname);
if (accessor) {
- const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value());
+ const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value);
// We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
// we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
@@ -2863,12 +3002,11 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
// Populate signals
const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
- const StringName *k = nullptr;
- while ((k = signal_map.next(k))) {
+ for (const KeyValue<StringName, MethodInfo> &E : signal_map) {
SignalInterface isignal;
- const MethodInfo &method_info = signal_map.get(*k);
+ const MethodInfo &method_info = E.value;
isignal.name = method_info.name;
isignal.cname = method_info.name;
@@ -2883,11 +3021,14 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ArgumentInterface iarg;
iarg.name = orig_arg_name;
- if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ if (arginfo.type == Variant::INT && arginfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
iarg.type.cname = arginfo.class_name;
iarg.type.is_enum = true;
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
+ } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
} else if (arginfo.type == Variant::NIL) {
@@ -2944,11 +3085,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
List<String> constants;
ClassDB::get_integer_constant_list(type_cname, &constants, true);
- const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
- k = nullptr;
+ const HashMap<StringName, ClassDB::ClassInfo::EnumInfo> &enum_map = class_info->enum_map;
- while ((k = enum_map.next(k))) {
- StringName enum_proxy_cname = *k;
+ for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &E : enum_map) {
+ StringName enum_proxy_cname = E.key;
String enum_proxy_name = enum_proxy_cname.operator String();
if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
// We have several conflicts between enums and PascalCase properties,
@@ -2957,10 +3097,11 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
enum_proxy_cname = StringName(enum_proxy_name);
}
EnumInterface ienum(enum_proxy_cname);
- const List<StringName> &enum_constants = enum_map.get(*k);
+ ienum.is_flags = E.value.is_bitfield;
+ const List<StringName> &enum_constants = E.value.constants;
for (const StringName &constant_cname : enum_constants) {
String constant_name = constant_cname.operator String();
- int *value = class_info->constant_map.getptr(constant_cname);
+ int64_t *value = class_info->constant_map.getptr(constant_cname);
ERR_FAIL_NULL_V(value, false);
constants.erase(constant_name);
@@ -2987,7 +3128,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
TypeInterface enum_itype;
enum_itype.is_enum = true;
- enum_itype.name = itype.name + "." + String(*k);
+ enum_itype.name = itype.name + "." + String(E.key);
enum_itype.cname = StringName(enum_itype.name);
enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
TypeInterface::postsetup_enum_type(enum_itype);
@@ -2995,7 +3136,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
for (const String &constant_name : constants) {
- int *value = class_info->constant_map.getptr(StringName(constant_name));
+ int64_t *value = class_info->constant_map.getptr(StringName(constant_name));
ERR_FAIL_NULL_V(value, false);
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
@@ -3083,6 +3224,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "new %s" + r_iarg.default_argument;
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
break;
+ case Variant::VECTOR4:
+ case Variant::VECTOR4I:
+ r_iarg.default_argument = "new %s" + r_iarg.default_argument;
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ break;
case Variant::OBJECT:
ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false,
"Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value.");
@@ -3123,7 +3269,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
if (transform == Transform2D()) {
r_iarg.default_argument = "Transform2D.Identity";
} else {
- r_iarg.default_argument = "new Transform2D(new Vector2" + transform.elements[0].operator String() + ", new Vector2" + transform.elements[1].operator String() + ", new Vector2" + transform.elements[2].operator String() + ")";
+ r_iarg.default_argument = "new Transform2D(new Vector2" + transform.columns[0].operator String() + ", new Vector2" + transform.columns[1].operator String() + ", new Vector2" + transform.columns[2].operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
@@ -3137,6 +3283,15 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
+ case Variant::PROJECTION: {
+ Projection transform = p_val.operator Projection();
+ if (transform == Projection()) {
+ r_iarg.default_argument = "Projection.Identity";
+ } else {
+ r_iarg.default_argument = "new Projection(new Vector4" + transform.matrix[0].operator String() + ", new Vector4" + transform.matrix[1].operator String() + ", new Vector4" + transform.matrix[2].operator String() + ", new Vector4" + transform.matrix[3].operator String() + ")";
+ }
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
case Variant::BASIS: {
Basis basis = p_val.operator Basis();
if (basis == Basis()) {
@@ -3472,13 +3627,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Array";
itype.cname = itype.name;
itype.proxy_name = itype.name;
+ itype.type_parameter_count = 1;
itype.c_out = "\treturn memnew(Array(%1));\n";
itype.c_type = itype.name;
itype.c_type_in = itype.c_type + "*";
itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new " + itype.cs_type + "(%0(%1));";
+ itype.cs_out = "return new %2(%0(%1));";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
builtin_types.insert(itype.cname, itype);
@@ -3488,13 +3644,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Dictionary";
itype.cname = itype.name;
itype.proxy_name = itype.name;
+ itype.type_parameter_count = 2;
itype.c_out = "\treturn memnew(Dictionary(%1));\n";
itype.c_type = itype.name;
itype.c_type_in = itype.c_type + "*";
itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new " + itype.cs_type + "(%0(%1));";
+ itype.cs_out = "return new %2(%0(%1));";
itype.im_type_in = "IntPtr";
itype.im_type_out = "IntPtr";
builtin_types.insert(itype.cname, itype);
@@ -3517,11 +3674,11 @@ void BindingsGenerator::_populate_global_constants() {
int global_constants_count = CoreConstants::get_global_constant_count();
if (global_constants_count > 0) {
- Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
+ HashMap<String, DocData::ClassDoc>::Iterator match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
CRASH_COND_MSG(!match, "Could not find '@GlobalScope' in DocData.");
- const DocData::ClassDoc &global_scope_doc = match->value();
+ const DocData::ClassDoc &global_scope_doc = match->value;
for (int i = 0; i < global_constants_count; i++) {
String constant_name = CoreConstants::get_global_constant_name(i);
@@ -3536,7 +3693,7 @@ void BindingsGenerator::_populate_global_constants() {
}
}
- int constant_value = CoreConstants::get_global_constant_value(i);
+ int64_t constant_value = CoreConstants::get_global_constant_value(i);
StringName enum_name = CoreConstants::get_global_constant_enum(i);
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), constant_value);
@@ -3544,6 +3701,7 @@ void BindingsGenerator::_populate_global_constants() {
if (enum_name != StringName()) {
EnumInterface ienum(enum_name);
+ // TODO: ienum.is_flags is always false for core constants since they don't seem to support bitfield enums
List<EnumInterface>::Element *enum_match = global_enums.find(ienum);
if (enum_match) {
enum_match->get().constants.push_back(iconstant);
@@ -3636,8 +3794,8 @@ void BindingsGenerator::_initialize() {
core_custom_icalls.clear();
editor_custom_icalls.clear();
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- _generate_method_icalls(E.get());
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ _generate_method_icalls(E.value);
}
initialized = true;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 5460f018f0..ee170e4558 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -45,12 +45,12 @@ class BindingsGenerator {
struct ConstantInterface {
String name;
String proxy_name;
- int value = 0;
+ int64_t value = 0;
const DocData::ConstantDoc *const_doc;
ConstantInterface() {}
- ConstantInterface(const String &p_name, const String &p_proxy_name, int p_value) {
+ ConstantInterface(const String &p_name, const String &p_proxy_name, int64_t p_value) {
name = p_name;
proxy_name = p_proxy_name;
value = p_value;
@@ -60,6 +60,7 @@ class BindingsGenerator {
struct EnumInterface {
StringName cname;
List<ConstantInterface> constants;
+ bool is_flags = false;
_FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const {
return p_ienum.cname == cname;
@@ -87,6 +88,8 @@ class BindingsGenerator {
StringName cname;
bool is_enum = false;
+ List<TypeReference> generic_type_parameters;
+
TypeReference() {}
TypeReference(const StringName &p_cname) :
@@ -137,6 +140,11 @@ class BindingsGenerator {
bool is_vararg = false;
/**
+ * Determines if the method is static.
+ */
+ bool is_static = false;
+
+ /**
* Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing,
* but can be overridden by the user to add custom functionality.
* e.g.: _ready, _process, etc.
@@ -201,6 +209,8 @@ class BindingsGenerator {
String name;
StringName cname;
+ int type_parameter_count;
+
/**
* Identifier name of the base class.
*/
@@ -528,24 +538,24 @@ class BindingsGenerator {
bool log_print_enabled = true;
bool initialized = false;
- OrderedHashMap<StringName, TypeInterface> obj_types;
+ HashMap<StringName, TypeInterface> obj_types;
- Map<StringName, TypeInterface> placeholder_types;
- Map<StringName, TypeInterface> builtin_types;
- Map<StringName, TypeInterface> enum_types;
+ HashMap<StringName, TypeInterface> placeholder_types;
+ HashMap<StringName, TypeInterface> builtin_types;
+ HashMap<StringName, TypeInterface> enum_types;
List<EnumInterface> global_enums;
List<ConstantInterface> global_constants;
List<InternalCall> method_icalls;
- Map<const MethodInterface *, const InternalCall *> method_icalls_map;
+ HashMap<const MethodInterface *, const InternalCall *> method_icalls_map;
List<const InternalCall *> generated_icall_funcs;
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
- Map<StringName, List<StringName>> blacklisted_methods;
+ HashMap<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
@@ -580,6 +590,9 @@ class BindingsGenerator {
StringName type_Vector2 = StaticCString::create("Vector2");
StringName type_Rect2 = StaticCString::create("Rect2");
StringName type_Vector3 = StaticCString::create("Vector3");
+ StringName type_Vector3i = StaticCString::create("Vector3i");
+ StringName type_Vector4 = StaticCString::create("Vector4");
+ StringName type_Vector4i = StaticCString::create("Vector4i");
// Object not included as it must be checked for all derived classes
static constexpr int nullable_types_count = 17;
@@ -658,6 +671,14 @@ class BindingsGenerator {
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
+ void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
+ void _append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target);
+ void _append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target);
+
int _determine_enum_prefix(const EnumInterface &p_ienum);
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
@@ -666,6 +687,8 @@ class BindingsGenerator {
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
+ const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters);
+
StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 095fd831a3..7bce6f2c21 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -120,11 +120,11 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
} break;
case CompletionKind::NODE_PATHS: {
{
- // AutoLoads
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ // Autoloads.
+ HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.value();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
suggestions.push_back(quoted("/root/" + String(info.name)));
}
}
@@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::SCENE_PATHS: {
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
@@ -172,7 +172,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::SHADER_PARAMS: {
- print_verbose("Shared params completion for C# not implemented.");
+ print_verbose("Shader uniforms completion for C# is not implemented yet.");
} break;
case CompletionKind::SIGNALS: {
Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path());
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index f7f710f3f1..f830c7ffe1 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -39,7 +39,9 @@
#include "core/version.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "main/main.h"
@@ -47,7 +49,7 @@
#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_marshal.h"
-#include "../utils/osx_utils.h"
+#include "../utils/macos_utils.h"
#include "code_completion.h"
#include "godotsharp_export.h"
@@ -188,8 +190,8 @@ MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_c
return GDMonoMarshal::mono_string_from_godot(error_str);
}
-MonoString *godot_icall_Internal_FullTemplatesDir() {
- String full_templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG);
+MonoString *godot_icall_Internal_FullExportTemplatesDir() {
+ String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
return GDMonoMarshal::mono_string_from_godot(full_templates_dir);
}
@@ -198,10 +200,10 @@ MonoString *godot_icall_Internal_SimplifyGodotPath(MonoString *p_path) {
return GDMonoMarshal::mono_string_from_godot(path.simplify_path());
}
-MonoBoolean godot_icall_Internal_IsOsxAppBundleInstalled(MonoString *p_bundle_id) {
-#ifdef OSX_ENABLED
+MonoBoolean godot_icall_Internal_IsMacOSAppBundleInstalled(MonoString *p_bundle_id) {
+#ifdef MACOS_ENABLED
String bundle_id = GDMonoMarshal::mono_string_to_godot(p_bundle_id);
- return (MonoBoolean)osx_is_app_bundle_installed(bundle_id);
+ return (MonoBoolean)macos_is_app_bundle_installed(bundle_id);
#else
(void)p_bundle_id; // UNUSED
return (MonoBoolean) false;
@@ -364,9 +366,9 @@ void register_editor_internal_calls() {
// Internals
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", godot_icall_Internal_FullTemplatesDir);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullExportTemplatesDir", godot_icall_Internal_FullExportTemplatesDir);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", godot_icall_Internal_IsOsxAppBundleInstalled);
+ 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);
diff --git a/modules/mono/editor/editor_internal_calls.h b/modules/mono/editor/editor_internal_calls.h
index a899634d57..8262ac211a 100644
--- a/modules/mono/editor/editor_internal_calls.h
+++ b/modules/mono/editor/editor_internal_calls.h
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EDITOR_INTERNAL_CALL_H
-#define EDITOR_INTERNAL_CALL_H
+#ifndef EDITOR_INTERNAL_CALLS_H
+#define EDITOR_INTERNAL_CALLS_H
void register_editor_internal_calls();
-#endif // EDITOR_INTERNAL_CALL_H
+#endif // EDITOR_INTERNAL_CALLS_H
diff --git a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
index b0ded3133f..2ca81ab7cd 100644
--- a/modules/mono/editor_templates/CharacterBody2D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
@@ -13,29 +13,29 @@ public partial class _CLASS_ : _BASE_
public override void _PhysicsProcess(float delta)
{
- Vector2 motionVelocity = MotionVelocity;
+ Vector2 velocity = Velocity;
// Add the gravity.
if (!IsOnFloor())
- motionVelocity.y += gravity * delta;
+ velocity.y += gravity * delta;
// Handle Jump.
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
- motionVelocity.y = JumpVelocity;
+ velocity.y = JumpVelocity;
// Get the input direction and handle the movement/deceleration.
// As good practice, you should replace UI actions with custom gameplay actions.
Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
if (direction != Vector2.Zero)
{
- motionVelocity.x = direction.x * Speed;
+ velocity.x = direction.x * Speed;
}
else
{
- motionVelocity.x = Mathf.MoveToward(MotionVelocity.x, 0, Speed);
+ velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed);
}
- MotionVelocity = motionVelocity;
+ Velocity = velocity;
MoveAndSlide();
}
}
diff --git a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
index d8c2f67ac8..a6935fe497 100644
--- a/modules/mono/editor_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
@@ -13,15 +13,15 @@ public partial class _CLASS_ : _BASE_
public override void _PhysicsProcess(float delta)
{
- Vector3 motionVelocity = MotionVelocity;
+ Vector3 velocity = Velocity;
// Add the gravity.
if (!IsOnFloor())
- motionVelocity.y -= gravity * delta;
+ velocity.y -= gravity * delta;
// Handle Jump.
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
- motionVelocity.y = JumpVelocity;
+ velocity.y = JumpVelocity;
// Get the input direction and handle the movement/deceleration.
// As good practice, you should replace UI actions with custom gameplay actions.
@@ -29,16 +29,16 @@ public partial class _CLASS_ : _BASE_
Vector3 direction = Transform.basis.Xform(new Vector3(inputDir.x, 0, inputDir.y)).Normalized();
if (direction != Vector3.Zero)
{
- motionVelocity.x = direction.x * Speed;
- motionVelocity.z = direction.z * Speed;
+ velocity.x = direction.x * Speed;
+ velocity.z = direction.z * Speed;
}
else
{
- motionVelocity.x = Mathf.MoveToward(MotionVelocity.x, 0, Speed);
- motionVelocity.z = Mathf.MoveToward(MotionVelocity.z, 0, Speed);
+ velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed);
+ velocity.z = Mathf.MoveToward(Velocity.z, 0, Speed);
}
- MotionVelocity = motionVelocity;
+ Velocity = velocity;
MoveAndSlide();
}
}
diff --git a/modules/mono/editor_templates/EditorPlugin/plugin.cs b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs
index 6e6a799be6..eba5fd12a4 100644
--- a/modules/mono/editor_templates/EditorPlugin/plugin.cs
+++ b/modules/mono/editor/script_templates/EditorPlugin/plugin.cs
@@ -1,4 +1,5 @@
// meta-description: Basic plugin template
+
#if TOOLS
using _BINDINGS_NAMESPACE_;
using System;
diff --git a/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs b/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs
new file mode 100644
index 0000000000..9e1b7ef580
--- /dev/null
+++ b/modules/mono/editor/script_templates/EditorScenePostImport/basic_import_script.cs
@@ -0,0 +1,16 @@
+// meta-description: Basic import script template
+
+#if TOOLS
+using _BINDINGS_NAMESPACE_;
+using System;
+
+[Tool]
+public partial class _CLASS_ : _BASE_
+{
+ public override Godot.Object _PostImport(Node scene)
+ {
+ // Modify the contents of the scene upon import.
+ return scene; // Return the modified root node when you're done.
+ }
+}
+#endif
diff --git a/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs b/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs
new file mode 100644
index 0000000000..bf2c9434e4
--- /dev/null
+++ b/modules/mono/editor/script_templates/EditorScenePostImport/no_comments.cs
@@ -0,0 +1,15 @@
+// meta-description: Basic import script template (no comments)
+
+#if TOOLS
+using _BINDINGS_NAMESPACE_;
+using System;
+
+[Tool]
+public partial class _CLASS_ : _BASE_
+{
+ public override Godot.Object _PostImport(Node scene)
+ {
+ return scene;
+ }
+}
+#endif
diff --git a/modules/mono/editor_templates/EditorScript/basic_editor_script.cs b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs
index 2088822890..1b347edc1c 100644
--- a/modules/mono/editor_templates/EditorScript/basic_editor_script.cs
+++ b/modules/mono/editor/script_templates/EditorScript/basic_editor_script.cs
@@ -1,4 +1,5 @@
// meta-description: Basic editor script template
+
#if TOOLS
using _BINDINGS_NAMESPACE_;
using System;
@@ -6,9 +7,9 @@ using System;
[Tool]
public partial class _CLASS_ : _BASE_
{
+ // Called when the script is executed (using File -> Run in Script Editor).
public override void _Run()
{
- // Called when the script is executed (using File -> Run in Script Editor).
}
}
#endif
diff --git a/modules/mono/editor_templates/Node/default.cs b/modules/mono/editor/script_templates/Node/default.cs
index 73d69dd993..4c86d1666f 100644
--- a/modules/mono/editor_templates/Node/default.cs
+++ b/modules/mono/editor/script_templates/Node/default.cs
@@ -8,12 +8,10 @@ public partial class _CLASS_ : _BASE_
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
-
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(float delta)
{
-
}
}
diff --git a/modules/mono/editor_templates/Object/empty.cs b/modules/mono/editor/script_templates/Object/empty.cs
index e5bee64fe1..34526d514f 100644
--- a/modules/mono/editor_templates/Object/empty.cs
+++ b/modules/mono/editor/script_templates/Object/empty.cs
@@ -5,5 +5,4 @@ using System;
public partial class _CLASS_ : _BASE_
{
-
}
diff --git a/modules/mono/editor_templates/SCsub b/modules/mono/editor/script_templates/SCsub
index 39f6cb5c01..39f6cb5c01 100644
--- a/modules/mono/editor_templates/SCsub
+++ b/modules/mono/editor/script_templates/SCsub
diff --git a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
index a1b93e7daa..a1b93e7daa 100644
--- a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs
+++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index ef135da51a..2febf37f05 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -2,17 +2,27 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that determines if an assembly has scripts. If so, what types of scripts the assembly has.
+ /// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyHasScriptsAttribute : Attribute
{
private readonly bool requiresLookup;
private readonly System.Type[] scriptTypes;
+ /// <summary>
+ /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// </summary>
public AssemblyHasScriptsAttribute()
{
requiresLookup = true;
}
+ /// <summary>
+ /// Constructs a new AssemblyHasScriptsAttribute instance.
+ /// </summary>
+ /// <param name="scriptTypes">The specified type(s) of scripts.</param>
public AssemblyHasScriptsAttribute(System.Type[] scriptTypes)
{
requiresLookup = false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
index e93bc89811..0b00878e8c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
@@ -2,6 +2,9 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that disables Godot Generators.
+ /// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class DisableGodotGeneratorsAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 6adf044886..46eb128d37 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -2,12 +2,20 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute used to export objects.
+ /// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ExportAttribute : Attribute
{
private PropertyHint hint;
private string hintString;
+ /// <summary>
+ /// Constructs a new ExportAttribute Instance.
+ /// </summary>
+ /// <param name="hint">A hint to the exported object.</param>
+ /// <param name="hintString">A string representing the exported object.</param>
public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
{
this.hint = hint;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
index 55848769d5..8d4ff0fdb7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
@@ -2,6 +2,9 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute for a method.
+ /// </summary>
[AttributeUsage(AttributeTargets.Method)]
internal class GodotMethodAttribute : Attribute
{
@@ -9,6 +12,10 @@ namespace Godot
public string MethodName { get { return methodName; } }
+ /// <summary>
+ /// Constructs a new GodotMethodAttribute instance.
+ /// </summary>
+ /// <param name="methodName">The name of the method.</param>
public GodotMethodAttribute(string methodName)
{
this.methodName = methodName;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
new file mode 100644
index 0000000000..fb37838ffa
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Attribute that changes the RPC mode for the annotated <c>method</c> to the given <see cref="Mode"/>,
+ /// optionally specifying the <see cref="TransferMode"/> and <see cref="TransferChannel"/> (on supported peers).
+ /// See <see cref="MultiplayerAPI.RPCMode"/> and <see cref="MultiplayerPeer.TransferModeEnum"/>.
+ /// By default, methods are not exposed to networking (and RPCs).
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
+ public class RPCAttribute : Attribute
+ {
+ /// <summary>
+ /// RPC mode for the annotated method.
+ /// </summary>
+ public MultiplayerAPI.RPCMode Mode { get; } = MultiplayerAPI.RPCMode.Disabled;
+
+ /// <summary>
+ /// If the method will also be called locally; otherwise, it is only called remotely.
+ /// </summary>
+ public bool CallLocal { get; set; } = false;
+
+ /// <summary>
+ /// Transfer mode for the annotated method.
+ /// </summary>
+ public MultiplayerPeer.TransferModeEnum TransferMode { get; set; } = MultiplayerPeer.TransferModeEnum.Reliable;
+
+ /// <summary>
+ /// Transfer channel for the annotated mode.
+ /// </summary>
+ public int TransferChannel { get; set; } = 0;
+
+ /// <summary>
+ /// Constructs a <see cref="RPCAttribute"/> instance.
+ /// </summary>
+ /// <param name="mode">The RPC mode to use.</param>
+ public RPCAttribute(MultiplayerAPI.RPCMode mode = MultiplayerAPI.RPCMode.Authority)
+ {
+ Mode = mode;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
deleted file mode 100644
index b8b9bc660c..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Godot
-{
- [AttributeUsage(AttributeTargets.Method)]
- public class AnyPeerAttribute : Attribute { }
-
- [AttributeUsage(AttributeTargets.Method)]
- public class AuthorityAttribute : Attribute { }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 12eb1035c3..3ebb6612de 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -2,11 +2,18 @@ using System;
namespace Godot
{
+ /// <summary>
+ /// An attribute that contains the path to the object's script.
+ /// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ScriptPathAttribute : Attribute
{
private string path;
+ /// <summary>
+ /// Constructs a new ScriptPathAttribute instance.
+ /// </summary>
+ /// <param name="path">The file path to the script</param>
public ScriptPathAttribute(string path)
{
this.path = path;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 656796c5c7..437878818c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -526,14 +526,14 @@ namespace Godot
/// <summary>
/// Introduce an additional rotation around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
- public Basis Rotated(Vector3 axis, real_t phi)
+ public Basis Rotated(Vector3 axis, real_t angle)
{
- return new Basis(axis, phi) * this;
+ return new Basis(axis, angle) * this;
}
/// <summary>
@@ -770,19 +770,19 @@ namespace Godot
/// <summary>
/// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
- public Basis(Vector3 axis, real_t phi)
+ /// <param name="angle">The angle to rotate, in radians.</param>
+ public Basis(Vector3 axis, real_t angle)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
- real_t cosine = Mathf.Cos(phi);
+ real_t cosine = Mathf.Cos(angle);
Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
- real_t sine = Mathf.Sin(phi);
+ real_t sine = Mathf.Sin(angle);
real_t t = 1.0f - cosine;
real_t xyzt = axis.x * axis.y * t;
@@ -828,6 +828,22 @@ namespace Godot
}
/// <summary>
+ /// Constructs a pure scale basis matrix with no rotation or shearing.
+ /// The scale values are set as the main diagonal of the matrix,
+ /// and all of the other parts of the matrix are zero.
+ /// </summary>
+ /// <param name="scale">The scale Vector3.</param>
+ /// <returns>A pure scale Basis matrix.</returns>
+ public static Basis FromScale(Vector3 scale)
+ {
+ return new Basis(
+ scale.x, 0, 0,
+ 0, scale.y, 0,
+ 0, 0, scale.z
+ );
+ }
+
+ /// <summary>
/// Composes these two basis matrices by multiplying them
/// together. This has the effect of transforming the second basis
/// (the child) by the first basis (the parent).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index fc9d40ca48..a6324504fc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -916,7 +916,7 @@ namespace Godot
/// <c>new Color(1 - c.r, 1 - c.g, 1 - c.b, 1 - c.a)</c>.
/// </summary>
/// <param name="color">The color to invert.</param>
- /// <returns>The inverted color</returns>
+ /// <returns>The inverted color.</returns>
public static Color operator -(Color color)
{
return Colors.White - color;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
index 072e0f20ff..6475237002 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -4,9 +4,16 @@ namespace Godot
{
public static class Dispatcher
{
+ /// <summary>
+ /// Implements an external instance of GodotTaskScheduler.
+ /// </summary>
+ /// <returns>A GodotTaskScheduler instance.</returns>
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler();
+ /// <summary>
+ /// Initializes the synchronization context as the context of the GodotTaskScheduler.
+ /// </summary>
public static GodotSynchronizationContext SynchronizationContext =>
godot_icall_DefaultGodotTaskScheduler().Context;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 74aa38386f..236d0666bc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -239,6 +239,35 @@ namespace Godot
}
/// <summary>
+ /// Converts one or more arguments of any type to string in the best way possible
+ /// and prints them to the console.
+ /// The following BBCode tags are supported: b, i, u, s, indent, code, url, center,
+ /// right, color, bgcolor, fgcolor.
+ /// Color tags only support named colors such as <c>red</c>, not hexadecimal color codes.
+ /// Unsupported tags will be left as-is in standard output.
+ /// When printing to standard output, the supported subset of BBCode is converted to
+ /// ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes
+ /// is currently only supported on Linux and macOS. Support for ANSI escape codes may vary
+ /// across terminal emulators, especially for italic and strikethrough.
+ ///
+ /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
+ /// to print error and warning messages instead of <see cref="Print(object[])"/> or
+ /// <see cref="PrintRich(object[])"/>.
+ /// This distinguishes them from print messages used for debugging purposes,
+ /// while also displaying a stack trace when an error or warning is printed.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.PrintRich("[b]Hello world![/b]"); // Prints out "Hello world!" in bold.
+ /// </code>
+ /// </example>
+ /// <param name="what">Arguments that will be printed.</param>
+ public static void PrintRich(params object[] what)
+ {
+ godot_icall_GD_print_rich(GetPrintParams(what));
+ }
+
+ /// <summary>
/// Prints the current stack trace information to the console.
/// </summary>
public static void PrintStack()
@@ -562,6 +591,9 @@ namespace Godot
internal static extern void godot_icall_GD_print(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern void godot_icall_GD_print_rich(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void godot_icall_GD_printerr(object[] what);
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
index c01c926e82..1b599beab5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
@@ -14,6 +14,9 @@ namespace Godot
_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
}
+ /// <summary>
+ /// Calls the Key method on each workItem object in the _queue to activate their callbacks.
+ /// </summary>
public void ExecutePendingContinuations()
{
while (_queue.TryTake(out var workItem))
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
index 8eaeea50dc..408bed71b2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
@@ -6,11 +6,25 @@ using System.Threading.Tasks;
namespace Godot
{
+ /// <summary>
+ /// GodotTaskScheduler contains a linked list of tasks to perform as a queue. Methods
+ /// within the class are used to control the queue and perform the contained tasks.
+ /// </summary>
public class GodotTaskScheduler : TaskScheduler
{
+ /// <summary>
+ /// The current synchronization context.
+ /// </summary>
internal GodotSynchronizationContext Context { get; }
+
+ /// <summary>
+ /// The queue of tasks for the task scheduler.
+ /// </summary>
private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+ /// <summary>
+ /// Constructs a new GodotTaskScheduler instance.
+ /// </summary>
public GodotTaskScheduler()
{
Context = new GodotSynchronizationContext();
@@ -53,12 +67,19 @@ namespace Godot
}
}
+ /// <summary>
+ /// Executes all queued tasks and pending tasks from the current context.
+ /// </summary>
public void Activate()
{
ExecuteQueuedTasks();
Context.ExecutePendingContinuations();
}
+ /// <summary>
+ /// Loops through and attempts to execute each task in _tasks.
+ /// </summary>
+ /// <exception cref="InvalidOperationException"></exception>
private void ExecuteQueuedTasks()
{
while (true)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
index 0397957d00..e747e03c1e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
@@ -1,10 +1,17 @@
namespace Godot
{
+ /// <summary>
+ /// An interface that requires a GetAwaiter() method to get a reference to the Awaiter.
+ /// </summary>
public interface IAwaitable
{
IAwaiter GetAwaiter();
}
+ /// <summary>
+ /// A templated interface that requires a GetAwaiter() method to get a reference to the Awaiter.
+ /// </summary>
+ /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam>
public interface IAwaitable<out TResult>
{
IAwaiter<TResult> GetAwaiter();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
index d3be9d781c..dec225eb29 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
@@ -2,6 +2,9 @@ using System.Runtime.CompilerServices;
namespace Godot
{
+ /// <summary>
+ /// An interface that requires a boolean for completion status and a method that gets the result of completion.
+ /// </summary>
public interface IAwaiter : INotifyCompletion
{
bool IsCompleted { get; }
@@ -9,6 +12,10 @@ namespace Godot
void GetResult();
}
+ /// <summary>
+ /// A templated interface that requires a boolean for completion status and a method that gets the result of completion and returns it.
+ /// </summary>
+ /// <typeparam name="TResult">A reference to the result to be passed out.</typeparam>
public interface IAwaiter<out TResult> : INotifyCompletion
{
bool IsCompleted { get; }
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
index c3fa2f3e82..90b4d1b8d3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
@@ -1,5 +1,8 @@
namespace Godot
{
+ /// <summary>
+ /// An interface that requires methods for before and after serialization.
+ /// </summary>
public interface ISerializationListener
{
void OnBeforeSerialize();
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
index ee4d0eed08..50ae2eb112 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
@@ -80,6 +80,11 @@ namespace Godot
private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
/// <summary>
+ /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
+ /// </summary>
+ private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
+
+ /// <summary>
/// Returns the generic type definition of <paramref name="type"/>.
/// </summary>
/// <exception cref="InvalidOperationException">
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index bfe9600084..36b7d0f80f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -180,6 +180,46 @@ namespace Godot
}
/// <summary>
+ /// Cubic interpolates between two values by a normalized value with pre and post values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static real_t CubicInterpolate(real_t from, real_t to, real_t pre, real_t post, real_t weight)
+ {
+ return 0.5f *
+ ((from * 2.0f) +
+ (-pre + to) * weight +
+ (2.0f * pre - 5.0f * from + 4.0f * to - post) * (weight * weight) +
+ (-pre + 3.0f * from - 3.0f * to + post) * (weight * weight * weight));
+ }
+
+ /// <summary>
+ /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by
+ /// the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="start">The start value for the interpolation.</param>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination value for the interpolation.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static real_t BezierInterpolate(real_t start, real_t control1, real_t control2, real_t end, real_t t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ real_t omt = 1 - t;
+ real_t omt2 = omt * omt;
+ real_t omt3 = omt2 * omt;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
+
+ return start * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
+ }
+
+ /// <summary>
/// Converts an angle expressed in degrees to radians.
/// </summary>
/// <param name="deg">An angle expressed in degrees.</param>
@@ -258,10 +298,14 @@ namespace Godot
/// Returns a normalized value considering the given range.
/// This is the opposite of <see cref="Lerp(real_t, real_t, real_t)"/>.
/// </summary>
- /// <param name="from">The interpolated value.</param>
+ /// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
- /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting value of the inverse interpolation.</returns>
+ /// <param name="weight">The interpolated value.</param>
+ /// <returns>
+ /// The resulting value of the inverse interpolation.
+ /// The returned value will be between 0.0 and 1.0 if <paramref name="weight"/> is
+ /// between <paramref name="from"/> and <paramref name="to"/> (inclusive).
+ /// </returns>
public static real_t InverseLerp(real_t from, real_t to, real_t weight)
{
return (weight - from) / (to - from);
@@ -498,6 +542,21 @@ namespace Godot
}
/// <summary>
+ /// Maps a <paramref name="value"/> from [<paramref name="inFrom"/>, <paramref name="inTo"/>]
+ /// to [<paramref name="outFrom"/>, <paramref name="outTo"/>].
+ /// </summary>
+ /// <param name="value">The value to map.</param>
+ /// <param name="inFrom">The start value for the input interpolation.</param>
+ /// <param name="inTo">The destination value for the input interpolation.</param>
+ /// <param name="outFrom">The start value for the output interpolation.</param>
+ /// <param name="outTo">The destination value for the output interpolation.</param>
+ /// <returns>The resulting mapped value mapped.</returns>
+ public static real_t RangeLerp(real_t value, real_t inFrom, real_t inTo, real_t outFrom, real_t outTo)
+ {
+ return Lerp(outFrom, outTo, InverseLerp(inFrom, inTo, value));
+ }
+
+ /// <summary>
/// Rounds <paramref name="s"/> to the nearest whole number,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index 40fb5f8788..9ae01016cb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -170,6 +170,21 @@ namespace Godot
}
/// <summary>
+ /// Returns all names concatenated with a slash character (<c>/</c>).
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var nodepath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path");
+ /// GD.Print(nodepath.GetConcatenatedNames()); // Path2D/PathFollow2D/Sprite2D
+ /// </code>
+ /// </example>
+ /// <returns>The names concatenated with <c>/</c>.</returns>
+ public string GetConcatenatedNames()
+ {
+ return godot_icall_NodePath_get_concatenated_names(GetPtr(this));
+ }
+
+ /// <summary>
/// Returns all subnames concatenated with a colon character (<c>:</c>)
/// as separator, i.e. the right side of the first colon in a node path.
/// </summary>
@@ -269,6 +284,9 @@ namespace Godot
private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string godot_icall_NodePath_get_concatenated_names(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 63af1c5892..fd97a71e47 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -118,15 +118,15 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if point is inside the plane.
- /// Comparison uses a custom minimum epsilon threshold.
+ /// Comparison uses a custom minimum tolerance threshold.
/// </summary>
/// <param name="point">The point to check.</param>
- /// <param name="epsilon">The tolerance threshold.</param>
+ /// <param name="tolerance">The tolerance threshold.</param>
/// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns>
- public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon)
+ public bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon)
{
real_t dist = _normal.Dot(point) - D;
- return Mathf.Abs(dist) <= epsilon;
+ return Mathf.Abs(dist) <= tolerance;
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
new file mode 100644
index 0000000000..d774021131
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -0,0 +1,820 @@
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Projection : IEquatable<Projection>
+ {
+ /// <summary>
+ /// Enumerated index values for the planes.
+ /// </summary>
+ public enum Planes
+ {
+ /// <summary>
+ /// The projection's near plane.
+ /// </summary>
+ Near,
+ /// <summary>
+ /// The projection's far plane.
+ /// </summary>
+ Far,
+ /// <summary>
+ /// The projection's left plane.
+ /// </summary>
+ Left,
+ /// <summary>
+ /// The projection's top plane.
+ /// </summary>
+ Top,
+ /// <summary>
+ /// The projection's right plane.
+ /// </summary>
+ Right,
+ /// <summary>
+ /// The projection's bottom plane.
+ /// </summary>
+ Bottom,
+ }
+
+ /// <summary>
+ /// The projections's X column. Also accessible by using the index position <c>[0]</c>.
+ /// </summary>
+ public Vector4 x;
+
+ /// <summary>
+ /// The projections's Y column. Also accessible by using the index position <c>[1]</c>.
+ /// </summary>
+ public Vector4 y;
+
+ /// <summary>
+ /// The projections's Z column. Also accessible by using the index position <c>[2]</c>.
+ /// </summary>
+ public Vector4 z;
+
+ /// <summary>
+ /// The projections's W column. Also accessible by using the index position <c>[3]</c>.
+ /// </summary>
+ public Vector4 w;
+
+ /// <summary>
+ /// Constructs a projection from 4 vectors (matrix columns).
+ /// </summary>
+ /// <param name="x">The X column, or column index 0.</param>
+ /// <param name="y">The Y column, or column index 1.</param>
+ /// <param name="z">The Z column, or column index 2.</param>
+ /// <param name="w">The W column, or column index 3.</param>
+ public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Projection"/> from an existing <see cref="Projection"/>.
+ /// </summary>
+ /// <param name="proj">The existing <see cref="Projection"/>.</param>
+ public Projection(Projection proj)
+ {
+ x = proj.x;
+ y = proj.y;
+ z = proj.z;
+ w = proj.w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
+ /// </summary>
+ /// <param name="transform">The <see cref="Transform3D"/>.</param>
+ public Projection(Transform3D transform)
+ {
+ x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0);
+ y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0);
+ z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0);
+ w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>.
+ /// </summary>
+ /// <param name="proj">The <see cref="Projection"/>.</param>
+ public static explicit operator Transform3D(Projection proj)
+ {
+ return new Transform3D(
+ new Basis(
+ new Vector3(proj.x.x, proj.x.y, proj.x.z),
+ new Vector3(proj.y.x, proj.y.y, proj.y.z),
+ new Vector3(proj.z.x, proj.z.y, proj.z.z)
+ ),
+ new Vector3(proj.w.x, proj.w.y, proj.w.z)
+ );
+ }
+
+ public static Projection CreateDepthCorrection(bool flipY)
+ {
+ return new Projection(
+ new Vector4(1, 0, 0, 0),
+ new Vector4(0, flipY ? -1 : 1, 0, 0),
+ new Vector4(0, 0, (real_t)0.5, 0),
+ new Vector4(0, 0, (real_t)0.5, 1)
+ );
+ }
+
+ public static Projection CreateFitAabb(AABB aabb)
+ {
+ Vector3 min = aabb.Position;
+ Vector3 max = aabb.Position + aabb.Size;
+
+ return new Projection(
+ new Vector4(2 / (max.x - min.x), 0, 0, 0),
+ new Vector4(0, 2 / (max.y - min.y), 0, 0),
+ new Vector4(0, 0, 2 / (max.z - min.z), 0),
+ new Vector4(-(max.x + min.x) / (max.x - min.x), -(max.y + min.y) / (max.y - min.y), -(max.z + min.z) / (max.z - min.z), 1)
+ );
+ }
+
+ public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar)
+ {
+ real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens;
+ real_t f2 = ((displayWidth - intraocularDist) * (real_t)0.5) / displayToLens;
+ real_t f3 = (displayWidth / (real_t)4.0) / displayToLens;
+
+ real_t add = ((f1 + f2) * (oversample - (real_t)1.0)) / (real_t)2.0;
+ f1 += add;
+ f2 += add;
+ f3 *= oversample;
+
+ f3 /= aspect;
+
+ switch (eye)
+ {
+ case 1:
+ return CreateFrustum(-f2 * zNear, f1 * zNear, -f3 * zNear, f3 * zNear, zNear, zFar);
+ case 2:
+ return CreateFrustum(-f1 * zNear, f2 * zNear, -f3 * zNear, f3 * zNear, zNear, zFar);
+ default:
+ return Zero;
+ }
+ }
+
+ public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far)
+ {
+ if (right <= left)
+ {
+ throw new ArgumentException("right is less or equal to left.");
+ }
+ if (top <= bottom)
+ {
+ throw new ArgumentException("top is less or equal to bottom.");
+ }
+ if (far <= near)
+ {
+ throw new ArgumentException("far is less or equal to near.");
+ }
+
+ real_t x = 2 * near / (right - left);
+ real_t y = 2 * near / (top - bottom);
+
+ real_t a = (right + left) / (right - left);
+ real_t b = (top + bottom) / (top - bottom);
+ real_t c = -(far + near) / (far - near);
+ real_t d = -2 * far * near / (far - near);
+
+ return new Projection(
+ new Vector4(x, 0, 0, 0),
+ new Vector4(0, y, 0, 0),
+ new Vector4(a, b, c, -1),
+ new Vector4(0, 0, d, 0)
+ );
+ }
+
+ public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov)
+ {
+ if (!flipFov)
+ {
+ size *= aspect;
+ }
+ return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far);
+ }
+
+ public static Projection CreateLightAtlasRect(Rect2 rect)
+ {
+ return new Projection(
+ new Vector4(rect.Size.x, 0, 0, 0),
+ new Vector4(0, rect.Size.y, 0, 0),
+ new Vector4(0, 0, 1, 0),
+ new Vector4(rect.Position.x, rect.Position.y, 0, 1)
+ );
+ }
+
+ public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar)
+ {
+ Projection proj = Projection.Identity;
+ proj.x.x = (real_t)2.0 / (right - left);
+ proj.w.x = -((right + left) / (right - left));
+ proj.y.y = (real_t)2.0 / (top - bottom);
+ proj.w.y = -((top + bottom) / (top - bottom));
+ proj.z.z = (real_t)(-2.0) / (zFar - zNear);
+ proj.w.z = -((zFar + zNear) / (zFar - zNear));
+ proj.w.w = (real_t)1.0;
+ return proj;
+ }
+
+ public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
+ {
+ if (!flipFov)
+ {
+ size *= aspect;
+ }
+ return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar);
+ }
+
+ public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
+ {
+ if (flipFov)
+ {
+ fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect);
+ }
+ real_t radians = Mathf.Deg2Rad(fovyDegrees / (real_t)2.0);
+ real_t deltaZ = zFar - zNear;
+ real_t sine = Mathf.Sin(radians);
+
+ if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
+ {
+ return Zero;
+ }
+
+ real_t cotangent = Mathf.Cos(radians) / sine;
+
+ Projection proj = Projection.Identity;
+
+ proj.x.x = cotangent / aspect;
+ proj.y.y = cotangent;
+ proj.z.z = -(zFar + zNear) / deltaZ;
+ proj.z.w = -1;
+ proj.w.z = -2 * zNear * zFar / deltaZ;
+ proj.w.w = 0;
+
+ return proj;
+ }
+
+ public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist)
+ {
+ if (flipFov)
+ {
+ fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect);
+ }
+
+ real_t ymax = zNear * Mathf.Tan(Mathf.Deg2Rad(fovyDegrees / (real_t)2.0));
+ real_t xmax = ymax * aspect;
+ real_t frustumshift = (intraocularDist / (real_t)2.0) * zNear / convergenceDist;
+ real_t left;
+ real_t right;
+ real_t modeltranslation;
+ switch (eye)
+ {
+ case 1:
+ left = -xmax + frustumshift;
+ right = xmax + frustumshift;
+ modeltranslation = intraocularDist / (real_t)2.0;
+ break;
+ case 2:
+ left = -xmax - frustumshift;
+ right = xmax - frustumshift;
+ modeltranslation = -intraocularDist / (real_t)2.0;
+ break;
+ default:
+ left = -xmax;
+ right = xmax;
+ modeltranslation = (real_t)0.0;
+ break;
+ }
+ Projection proj = CreateFrustum(left, right, -ymax, ymax, zNear, zFar);
+ Projection cm = Projection.Identity;
+ cm.w.x = modeltranslation;
+ return proj * cm;
+ }
+
+ public real_t Determinant()
+ {
+ return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x -
+ x.w * y.y * z.z * w.x + x.y * y.w * z.z * w.x +
+ x.z * y.y * z.w * w.x - x.y * y.z * z.w * w.x -
+ x.w * y.z * z.x * w.y + x.z * y.w * z.x * w.y +
+ x.w * y.x * z.z * w.y - x.x * y.w * z.z * w.y -
+ x.z * y.x * z.w * w.y + x.x * y.z * z.w * w.y +
+ x.w * y.y * z.x * w.z - x.y * y.w * z.x * w.z -
+ x.w * y.x * z.y * w.z + x.x * y.w * z.y * w.z +
+ x.y * y.x * z.w * w.z - x.x * y.y * z.w * w.z -
+ x.z * y.y * z.x * w.w + x.y * y.z * z.x * w.w +
+ x.z * y.x * z.y * w.w - x.x * y.z * z.y * w.w -
+ x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w;
+ }
+
+ public real_t GetAspect()
+ {
+ Vector2 vpHe = GetViewportHalfExtents();
+ return vpHe.x / vpHe.y;
+ }
+
+ public real_t GetFov()
+ {
+ Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized();
+ if (z.x == 0 && z.y == 0)
+ {
+ return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))) * (real_t)2.0;
+ }
+ else
+ {
+ Plane leftPlane = new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x).Normalized();
+ return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.x))) + Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x)));
+ }
+ }
+
+ public static real_t GetFovy(real_t fovx, real_t aspect)
+ {
+ return Mathf.Rad2Deg(Mathf.Atan(aspect * Mathf.Tan(Mathf.Deg2Rad(fovx) * (real_t)0.5)) * (real_t)2.0);
+ }
+
+ public real_t GetLodMultiplier()
+ {
+ if (IsOrthogonal())
+ {
+ return GetViewportHalfExtents().x;
+ }
+ else
+ {
+ real_t zn = GetZNear();
+ real_t width = GetViewportHalfExtents().x * (real_t)2.0;
+ return (real_t)1.0 / (zn / width);
+ }
+ }
+
+ public int GetPixelsPerMeter(int forPixelWidth)
+ {
+ Vector3 result = Xform(new Vector3(1, 0, -1));
+
+ return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth);
+ }
+
+ public Plane GetProjectionPlane(Planes plane)
+ {
+ Plane newPlane = plane switch
+ {
+ Planes.Near => new Plane(x.w + x.z, y.w + y.z, z.w + z.z, w.w + w.z),
+ Planes.Far => new Plane(x.w - x.z, y.w - y.z, z.w - z.z, w.w - w.z),
+ Planes.Left => new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x),
+ Planes.Top => new Plane(x.w - x.y, y.w - y.y, z.w - z.y, w.w - w.y),
+ Planes.Right => new Plane(x.w - x.x, y.w - y.x, z.w - z.x, w.w - w.x),
+ Planes.Bottom => new Plane(x.w + x.y, y.w + y.y, z.w + z.y, w.w + w.y),
+ _ => new Plane(),
+ };
+ newPlane.Normal = -newPlane.Normal;
+ return newPlane.Normalized();
+ }
+
+ public Vector2 GetFarPlaneHalfExtents()
+ {
+ var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
+ return new Vector2(res.Value.x, res.Value.y);
+ }
+
+ public Vector2 GetViewportHalfExtents()
+ {
+ var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
+ return new Vector2(res.Value.x, res.Value.y);
+ }
+
+ public real_t GetZFar()
+ {
+ return GetProjectionPlane(Planes.Far).D;
+ }
+
+ public real_t GetZNear()
+ {
+ return -GetProjectionPlane(Planes.Near).D;
+ }
+
+ public Projection FlippedY()
+ {
+ Projection proj = this;
+ proj.y = -proj.y;
+ return proj;
+ }
+
+ public Projection PerspectiveZNearAdjusted(real_t newZNear)
+ {
+ Projection proj = this;
+ real_t zFar = GetZFar();
+ real_t zNear = newZNear;
+ real_t deltaZ = zFar - zNear;
+ proj.z.z = -(zFar + zNear) / deltaZ;
+ proj.w.z = -2 * zNear * zFar / deltaZ;
+ return proj;
+ }
+
+ public Projection JitterOffseted(Vector2 offset)
+ {
+ Projection proj = this;
+ proj.w.x += offset.x;
+ proj.w.y += offset.y;
+ return proj;
+ }
+
+ public Projection Inverse()
+ {
+ Projection proj = this;
+ int i, j, k;
+ int[] pvt_i = new int[4];
+ int[] pvt_j = new int[4]; /* Locations of pivot matrix */
+ real_t pvt_val; /* Value of current pivot element */
+ real_t hold; /* Temporary storage */
+ real_t determinant = 1.0f;
+ for (k = 0; k < 4; k++)
+ {
+ /* Locate k'th pivot element */
+ pvt_val = proj[k][k]; /* Initialize for search */
+ pvt_i[k] = k;
+ pvt_j[k] = k;
+ for (i = k; i < 4; i++)
+ {
+ for (j = k; j < 4; j++)
+ {
+ if (Mathf.Abs(proj[i][j]) > Mathf.Abs(pvt_val))
+ {
+ pvt_i[k] = i;
+ pvt_j[k] = j;
+ pvt_val = proj[i][j];
+ }
+ }
+ }
+
+ /* Product of pivots, gives determinant when finished */
+ determinant *= pvt_val;
+ if (Mathf.IsZeroApprox(determinant))
+ {
+ return Zero;
+ }
+
+ /* "Interchange" rows (with sign change stuff) */
+ i = pvt_i[k];
+ if (i != k)
+ { /* If rows are different */
+ for (j = 0; j < 4; j++)
+ {
+ hold = -proj[k][j];
+ proj[k, j] = proj[i][j];
+ proj[i, j] = hold;
+ }
+ }
+
+ /* "Interchange" columns */
+ j = pvt_j[k];
+ if (j != k)
+ { /* If columns are different */
+ for (i = 0; i < 4; i++)
+ {
+ hold = -proj[i][k];
+ proj[i, k] = proj[i][j];
+ proj[i, j] = hold;
+ }
+ }
+
+ /* Divide column by minus pivot value */
+ for (i = 0; i < 4; i++)
+ {
+ if (i != k)
+ {
+ proj[i, k] /= (-pvt_val);
+ }
+ }
+
+ /* Reduce the matrix */
+ for (i = 0; i < 4; i++)
+ {
+ hold = proj[i][k];
+ for (j = 0; j < 4; j++)
+ {
+ if (i != k && j != k)
+ {
+ proj[i, j] += hold * proj[k][j];
+ }
+ }
+ }
+
+ /* Divide row by pivot */
+ for (j = 0; j < 4; j++)
+ {
+ if (j != k)
+ {
+ proj[k, j] /= pvt_val;
+ }
+ }
+
+ /* Replace pivot by reciprocal (at last we can touch it). */
+ proj[k, k] = (real_t)1.0 / pvt_val;
+ }
+
+ /* That was most of the work, one final pass of row/column interchange */
+ /* to finish */
+ for (k = 4 - 2; k >= 0; k--)
+ { /* Don't need to work with 1 by 1 corner*/
+ i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
+ if (i != k)
+ { /* If rows are different */
+ for (j = 0; j < 4; j++)
+ {
+ hold = proj[k][j];
+ proj[k, j] = -proj[i][j];
+ proj[i, j] = hold;
+ }
+ }
+
+ j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
+ if (j != k)
+ { /* If columns are different */
+ for (i = 0; i < 4; i++)
+ {
+ hold = proj[i][k];
+ proj[i, k] = -proj[i][j];
+ proj[i, j] = hold;
+ }
+ }
+ }
+ return proj;
+ }
+
+ public bool IsOrthogonal()
+ {
+ return w.w == (real_t)1.0;
+ }
+
+ /// <summary>
+ /// Composes these two projections by multiplying them
+ /// together. This has the effect of applying the right
+ /// and then the left projection.
+ /// </summary>
+ /// <param name="left">The parent transform.</param>
+ /// <param name="right">The child transform.</param>
+ /// <returns>The composed projection.</returns>
+ public static Projection operator *(Projection left, Projection right)
+ {
+ return new Projection(
+ new Vector4(
+ left.x.x * right.x.x + left.y.x * right.x.y + left.z.x * right.x.z + left.w.x * right.x.w,
+ left.x.y * right.x.x + left.y.y * right.x.y + left.z.y * right.x.z + left.w.y * right.x.w,
+ left.x.z * right.x.x + left.y.z * right.x.y + left.z.z * right.x.z + left.w.z * right.x.w,
+ left.x.w * right.x.x + left.y.w * right.x.y + left.z.w * right.x.z + left.w.w * right.x.w
+ ), new Vector4(
+ left.x.x * right.y.x + left.y.x * right.y.y + left.z.x * right.y.z + left.w.x * right.y.w,
+ left.x.y * right.y.x + left.y.y * right.y.y + left.z.y * right.y.z + left.w.y * right.y.w,
+ left.x.z * right.y.x + left.y.z * right.y.y + left.z.z * right.y.z + left.w.z * right.y.w,
+ left.x.w * right.y.x + left.y.w * right.y.y + left.z.w * right.y.z + left.w.w * right.y.w
+ ), new Vector4(
+ left.x.x * right.z.x + left.y.x * right.z.y + left.z.x * right.z.z + left.w.x * right.z.w,
+ left.x.y * right.z.x + left.y.y * right.z.y + left.z.y * right.z.z + left.w.y * right.z.w,
+ left.x.z * right.z.x + left.y.z * right.z.y + left.z.z * right.z.z + left.w.z * right.z.w,
+ left.x.w * right.z.x + left.y.w * right.z.y + left.z.w * right.z.z + left.w.w * right.z.w
+ ), new Vector4(
+ left.x.x * right.w.x + left.y.x * right.w.y + left.z.x * right.w.z + left.w.x * right.w.w,
+ left.x.y * right.w.x + left.y.y * right.w.y + left.z.y * right.w.z + left.w.y * right.w.w,
+ left.x.z * right.w.x + left.y.z * right.w.y + left.z.z * right.w.z + left.w.z * right.w.w,
+ left.x.w * right.w.x + left.y.w * right.w.y + left.z.w * right.w.z + left.w.w * right.w.w
+ )
+ );
+ }
+
+ /// <summary>
+ /// Returns a vector transformed (multiplied) by this projection.
+ /// </summary>
+ /// <param name="proj">The projection to apply.</param>
+ /// <param name="v">A vector to transform.</param>
+ /// <returns>The transformed vector.</returns>
+ public static Vector4 operator *(Projection proj, Vector4 v)
+ {
+ return new Vector4(
+ proj.x.x * v.x + proj.y.x * v.y + proj.z.x * v.z + proj.w.x * v.w,
+ proj.x.y * v.x + proj.y.y * v.y + proj.z.y * v.z + proj.w.y * v.w,
+ proj.x.z * v.x + proj.y.z * v.y + proj.z.z * v.z + proj.w.z * v.w,
+ proj.x.w * v.x + proj.y.w * v.y + proj.z.w * v.z + proj.w.w * v.w
+ );
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the projections are exactly equal.
+ /// </summary>
+ /// <param name="left">The left projection.</param>
+ /// <param name="right">The right projection.</param>
+ /// <returns>Whether or not the projections are exactly equal.</returns>
+ public static bool operator ==(Projection left, Projection right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the projections are not exactly equal.
+ /// </summary>
+ /// <param name="left">The left projection.</param>
+ /// <param name="right">The right projection.</param>
+ /// <returns>Whether or not the projections are not exactly equal.</returns>
+ public static bool operator !=(Projection left, Projection right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Access whole columns in the form of <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="column">Which column vector.</param>
+ public Vector4 this[int column]
+ {
+ get
+ {
+ switch (column)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (column)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ case 3:
+ w = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Access single values.
+ /// </summary>
+ /// <param name="column">Which column vector.</param>
+ /// <param name="row">Which row of the column.</param>
+ public real_t this[int column, int row]
+ {
+ get
+ {
+ switch (column)
+ {
+ case 0:
+ return x[row];
+ case 1:
+ return y[row];
+ case 2:
+ return z[row];
+ case 3:
+ return w[row];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (column)
+ {
+ case 0:
+ x[row] = value;
+ return;
+ case 1:
+ y[row] = value;
+ return;
+ case 2:
+ z[row] = value;
+ return;
+ case 3:
+ w[row] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns a vector transformed (multiplied) by this projection.
+ /// </summary>
+ /// <param name="v">A vector to transform.</param>
+ /// <returns>The transformed vector.</returns>
+ private Vector3 Xform(Vector3 v)
+ {
+ Vector3 ret = new Vector3(
+ x.x * v.x + y.x * v.y + z.x * v.z + w.x,
+ x.y * v.x + y.y * v.y + z.y * v.z + w.y,
+ x.z * v.x + y.z * v.y + z.z * v.z + w.z
+ );
+ return ret / (x.w * v.x + y.w * v.y + z.w * v.z + w.w);
+ }
+
+ // Constants
+ private static readonly Projection _zero = new Projection(
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0),
+ new Vector4(0, 0, 0, 0)
+ );
+ private static readonly Projection _identity = new Projection(
+ new Vector4(1, 0, 0, 0),
+ new Vector4(0, 1, 0, 0),
+ new Vector4(0, 0, 1, 0),
+ new Vector4(0, 0, 0, 1)
+ );
+
+ /// <summary>
+ /// Zero projection, a projection with all components set to <c>0</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value>
+ public static Projection Zero { get { return _zero; } }
+
+ /// <summary>
+ /// The identity projection, with no distortion applied.
+ /// This is used as a replacement for <c>Projection()</c> in GDScript.
+ /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero.
+ /// </summary>
+ /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value>
+ public static Projection Identity { get { return _identity; } }
+
+ /// <summary>
+ /// Serves as the hash function for <see cref="Projection"/>.
+ /// </summary>
+ /// <returns>A hash code for this projection.</returns>
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Projection"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this projection.</returns>
+ public override string ToString()
+ {
+ return $"{x.x}, {x.y}, {x.z}, {x.w}\n{y.x}, {y.y}, {y.z}, {y.w}\n{z.x}, {z.y}, {z.z}, {z.w}\n{w.x}, {w.y}, {w.z}, {w.w}\n";
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>.
+ /// </summary>
+ /// <returns>A string representation of this projection.</returns>
+ public string ToString(string format)
+ {
+ return $"{x.x.ToString(format)}, {x.y.ToString(format)}, {x.z.ToString(format)}, {x.w.ToString(format)}\n" +
+ $"{y.x.ToString(format)}, {y.y.ToString(format)}, {y.z.ToString(format)}, {y.w.ToString(format)}\n" +
+ $"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" +
+ $"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n";
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the projection is exactly equal
+ /// to the given object (<see paramref="obj"/>).
+ /// </summary>
+ /// <param name="obj">The object to compare with.</param>
+ /// <returns>Whether or not the vector and the object are equal.</returns>
+ public override bool Equals(object obj)
+ {
+ if (obj is Projection)
+ {
+ return Equals((Projection)obj);
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the projections are exactly equal.
+ /// </summary>
+ /// <param name="other">The other projection.</param>
+ /// <returns>Whether or not the projections are exactly equal.</returns>
+ public bool Equals(Projection other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
index 5680c9d55a..da01300586 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
@@ -18,7 +18,7 @@ namespace Godot
public StringName Name => _signalName;
/// <summary>
- /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/>
+ /// Creates a new <see cref="SignalInfo"/> with the name <paramref name="name"/>
/// in the specified <paramref name="owner"/>.
/// </summary>
/// <param name="owner">Object that contains the signal.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 8e253388bf..68d097eb4e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -297,17 +297,33 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform by <paramref name="phi"/> (in radians), using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians).
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform2D Rotated(real_t phi)
+ public Transform2D Rotated(real_t angle)
{
- return this * new Transform2D(phi, new Vector2());
+ return this * new Transform2D(angle, new Vector2());
}
/// <summary>
- /// Scales the transform by the given scaling factor, using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians).
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="angle">The angle to rotate, in radians.</param>
+ /// <returns>The rotated transformation matrix.</returns>
+ public Transform2D RotatedLocal(real_t angle)
+ {
+ return new Transform2D(angle, new Vector2()) * this;
+ }
+
+ /// <summary>
+ /// Scales the transform by the given scaling factor.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@@ -320,12 +336,19 @@ namespace Godot
return copy;
}
- private void ScaleBasis(Vector2 scale)
+ /// <summary>
+ /// Scales the transform by the given scaling factor.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="scale">The scale to introduce.</param>
+ /// <returns>The scaled transformation matrix.</returns>
+ public Transform2D ScaledLocal(Vector2 scale)
{
- x.x *= scale.x;
- x.y *= scale.y;
- y.x *= scale.x;
- y.y *= scale.y;
+ Transform2D copy = this;
+ copy.x *= scale;
+ copy.y *= scale;
+ return copy;
}
private real_t Tdotx(Vector2 with)
@@ -339,17 +362,29 @@ namespace Godot
}
/// <summary>
- /// Translates the transform by the given <paramref name="offset"/>,
- /// relative to the transform's basis vectors.
- ///
- /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
- /// this does not use matrix multiplication.
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform2D Translated(Vector2 offset)
{
Transform2D copy = this;
+ copy.origin += offset;
+ return copy;
+ }
+
+ /// <summary>
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="offset">The offset to translate by.</param>
+ /// <returns>The translated matrix.</returns>
+ public Transform2D TranslatedLocal(Vector2 offset)
+ {
+ Transform2D copy = this;
copy.origin += copy.BasisXform(offset);
return copy;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 5d9aabdd2f..9eaf4f3252 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -186,19 +186,38 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="phi"/> (in radians),
- /// using matrix multiplication. The axis must be a normalized vector.
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians).
+ /// The axis must be a normalized vector.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform3D Rotated(Vector3 axis, real_t phi)
+ public Transform3D Rotated(Vector3 axis, real_t angle)
{
- return new Transform3D(new Basis(axis, phi), new Vector3()) * this;
+ return new Transform3D(new Basis(axis, angle), new Vector3()) * this;
}
/// <summary>
- /// Scales the transform by the given 3D scaling factor, using matrix multiplication.
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians).
+ /// The axis must be a normalized vector.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="axis">The axis to rotate around. Must be normalized.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
+ /// <returns>The rotated transformation matrix.</returns>
+ public Transform3D RotatedLocal(Vector3 axis, real_t angle)
+ {
+ Basis tmpBasis = new Basis(axis, angle);
+ return new Transform3D(basis * tmpBasis, origin);
+ }
+
+ /// <summary>
+ /// Scales the transform by the given 3D <paramref name="scale"/> factor.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@@ -207,6 +226,19 @@ namespace Godot
return new Transform3D(basis.Scaled(scale), origin * scale);
}
+ /// <summary>
+ /// Scales the transform by the given 3D <paramref name="scale"/> factor.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="scale">The scale to introduce.</param>
+ /// <returns>The scaled transformation matrix.</returns>
+ public Transform3D ScaledLocal(Vector3 scale)
+ {
+ Basis tmpBasis = Basis.FromScale(scale);
+ return new Transform3D(basis * tmpBasis, origin);
+ }
+
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
{
// Make rotation matrix
@@ -231,21 +263,31 @@ namespace Godot
}
/// <summary>
- /// Translates the transform by the given <paramref name="offset"/>,
- /// relative to the transform's basis vectors.
- ///
- /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
- /// this does not use matrix multiplication.
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform3D Translated(Vector3 offset)
{
+ return new Transform3D(basis, origin + offset);
+ }
+
+ /// <summary>
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="offset">The offset to translate by.</param>
+ /// <returns>The translated matrix.</returns>
+ public Transform3D TranslatedLocal(Vector3 offset)
+ {
return new Transform3D(basis, new Vector3
(
- origin[0] += basis.Row0.Dot(offset),
- origin[1] += basis.Row1.Dot(offset),
- origin[2] += basis.Row2.Dot(offset)
+ origin[0] + basis.Row0.Dot(offset),
+ origin[1] + basis.Row1.Dot(offset),
+ origin[2] + basis.Row2.Dot(offset)
));
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index fa7838633c..67f70390dd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -81,6 +81,15 @@ namespace Godot
}
}
+ /// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out real_t x, out real_t y)
+ {
+ x = this.x;
+ y = this.y;
+ }
+
internal void Normalize()
{
real_t lengthsq = LengthSquared();
@@ -204,21 +213,32 @@ namespace Godot
/// <returns>The interpolated vector.</returns>
public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight)
{
- Vector2 p0 = preA;
- Vector2 p1 = this;
- Vector2 p2 = b;
- Vector2 p3 = postB;
+ return new Vector2
+ (
+ Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
+ Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight)
+ );
+ }
- real_t t = weight;
+ /// <summary>
+ /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination vector.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector2 BezierInterpolate(Vector2 control1, Vector2 control2, Vector2 end, real_t t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ real_t omt = 1 - t;
+ real_t omt2 = omt * omt;
+ real_t omt3 = omt2 * omt;
real_t t2 = t * t;
real_t t3 = t2 * t;
- return 0.5f * (
- (p1 * 2.0f) +
- ((-p0 + p2) * t) +
- (((2.0f * p0) - (5.0f * p1) + (4 * p2) - p3) * t2) +
- ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3)
- );
+ return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
}
/// <summary>
@@ -471,14 +491,14 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector by <paramref name="phi"/> radians.
+ /// Rotates this vector by <paramref name="angle"/> radians.
/// </summary>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector2 Rotated(real_t phi)
+ public Vector2 Rotated(real_t angle)
{
- real_t sine = Mathf.Sin(phi);
- real_t cosi = Mathf.Cos(phi);
+ real_t sine = Mathf.Sin(angle);
+ real_t cosi = Mathf.Cos(angle);
return new Vector2(
x * cosi - y * sine,
x * sine + y * cosi);
@@ -512,8 +532,9 @@ namespace Godot
/// Returns the result of the spherical linear interpolation between
/// this vector and <paramref name="to"/> by amount <paramref name="weight"/>.
///
- /// This method also handles interpolating the lengths if the input vectors have different lengths.
- /// For the special case of one or both input vectors having zero length, this method behaves like [method lerp].
+ /// This method also handles interpolating the lengths if the input vectors
+ /// have different lengths. For the special case of one or both input vectors
+ /// having zero length, this method behaves like <see cref="Lerp(Vector2, real_t)"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
@@ -522,9 +543,10 @@ namespace Godot
{
real_t startLengthSquared = LengthSquared();
real_t endLengthSquared = to.LengthSquared();
- if (startLengthSquared == 0.0 || endLengthSquared == 0.0) {
- // Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
- return Lerp(to, weight);
+ if (startLengthSquared == 0.0 || endLengthSquared == 0.0)
+ {
+ // Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
+ return Lerp(to, weight);
}
real_t startLength = Mathf.Sqrt(startLengthSquared);
real_t resultLength = Mathf.Lerp(startLength, Mathf.Sqrt(endLengthSquared), weight);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index 9b51de5c8c..b61954a84c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -82,6 +82,15 @@ namespace Godot
}
/// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out int x, out int y)
+ {
+ x = this.x;
+ y = this.y;
+ }
+
+ /// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
@@ -452,7 +461,7 @@ namespace Godot
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector2i"/>
+ /// Divides each component of the <see cref="Vector2i"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 0faf13f8b7..67a98efc2d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -96,6 +96,16 @@ namespace Godot
}
}
+ /// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out real_t x, out real_t y, out real_t z)
+ {
+ x = this.x;
+ y = this.y;
+ z = this.z;
+ }
+
internal void Normalize()
{
real_t lengthsq = LengthSquared();
@@ -195,20 +205,33 @@ namespace Godot
/// <returns>The interpolated vector.</returns>
public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight)
{
- Vector3 p0 = preA;
- Vector3 p1 = this;
- Vector3 p2 = b;
- Vector3 p3 = postB;
+ return new Vector3
+ (
+ Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
+ Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
+ Mathf.CubicInterpolate(z, b.z, preA.z, postB.z, weight)
+ );
+ }
- real_t t = weight;
+ /// <summary>
+ /// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
+ /// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
+ /// </summary>
+ /// <param name="control1">Control point that defines the bezier curve.</param>
+ /// <param name="control2">Control point that defines the bezier curve.</param>
+ /// <param name="end">The destination vector.</param>
+ /// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector3 BezierInterpolate(Vector3 control1, Vector3 control2, Vector3 end, real_t t)
+ {
+ // Formula from Wikipedia article on Bezier curves
+ real_t omt = 1 - t;
+ real_t omt2 = omt * omt;
+ real_t omt3 = omt2 * omt;
real_t t2 = t * t;
real_t t3 = t2 * t;
- return 0.5f * (
- (p1 * 2.0f) + ((-p0 + p2) * t) +
- (((2.0f * p0) - (5.0f * p1) + (4f * p2) - p3) * t2) +
- ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3)
- );
+ return this * omt3 + control1 * omt2 * t * 3 + control2 * omt * t2 * 3 + end * t3;
}
/// <summary>
@@ -486,13 +509,13 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="phi"/> radians.
+ /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="angle"/> (in radians).
/// The <paramref name="axis"/> vector must be a normalized vector.
/// </summary>
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector3 Rotated(Vector3 axis, real_t phi)
+ public Vector3 Rotated(Vector3 axis, real_t angle)
{
#if DEBUG
if (!axis.IsNormalized())
@@ -500,7 +523,7 @@ namespace Godot
throw new ArgumentException("Argument is not normalized", nameof(axis));
}
#endif
- return new Basis(axis, phi).Xform(this);
+ return new Basis(axis, angle).Xform(this);
}
/// <summary>
@@ -549,8 +572,9 @@ namespace Godot
/// Returns the result of the spherical linear interpolation between
/// this vector and <paramref name="to"/> by amount <paramref name="weight"/>.
///
- /// This method also handles interpolating the lengths if the input vectors have different lengths.
- /// For the special case of one or both input vectors having zero length, this method behaves like [method lerp].
+ /// This method also handles interpolating the lengths if the input vectors
+ /// have different lengths. For the special case of one or both input vectors
+ /// having zero length, this method behaves like <see cref="Lerp(Vector3, real_t)"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
@@ -559,9 +583,10 @@ namespace Godot
{
real_t startLengthSquared = LengthSquared();
real_t endLengthSquared = to.LengthSquared();
- if (startLengthSquared == 0.0 || endLengthSquared == 0.0) {
- // Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
- return Lerp(to, weight);
+ if (startLengthSquared == 0.0 || endLengthSquared == 0.0)
+ {
+ // Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
+ return Lerp(to, weight);
}
real_t startLength = Mathf.Sqrt(startLengthSquared);
real_t resultLength = Mathf.Lerp(startLength, Mathf.Sqrt(endLengthSquared), weight);
@@ -595,22 +620,6 @@ namespace Godot
);
}
- /// <summary>
- /// Returns a diagonal matrix with the vector as main diagonal.
- ///
- /// This is equivalent to a <see cref="Basis"/> with no rotation or shearing and
- /// this vector's components set as the scale.
- /// </summary>
- /// <returns>A <see cref="Basis"/> with the vector as its main diagonal.</returns>
- public Basis ToDiagonalMatrix()
- {
- return new Basis(
- x, 0, 0,
- 0, y, 0,
- 0, 0, z
- );
- }
-
// Constants
private static readonly Vector3 _zero = new Vector3(0, 0, 0);
private static readonly Vector3 _one = new Vector3(1, 1, 1);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
index eb06d2b87e..0d4894f206 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -97,6 +97,16 @@ namespace Godot
}
/// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out int x, out int y, out int z)
+ {
+ x = this.x;
+ y = this.y;
+ z = this.z;
+ }
+
+ /// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
@@ -439,7 +449,7 @@ namespace Godot
}
/// <summary>
- /// Multiplies each component of the <see cref="Vector3i"/>
+ /// Divides each component of the <see cref="Vector3i"/>
/// by the given <see langword="int"/>.
/// </summary>
/// <param name="vec">The dividend vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
new file mode 100644
index 0000000000..4af817455c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -0,0 +1,832 @@
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ /// <summary>
+ /// 4-element structure that can be used to represent positions in 4D space or any other pair of numeric values.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector4 : IEquatable<Vector4>
+ {
+ /// <summary>
+ /// Enumerated index values for the axes.
+ /// Returned by <see cref="MaxAxisIndex"/> and <see cref="MinAxisIndex"/>.
+ /// </summary>
+ public enum Axis
+ {
+ /// <summary>
+ /// The vector's X axis.
+ /// </summary>
+ X = 0,
+ /// <summary>
+ /// The vector's Y axis.
+ /// </summary>
+ Y,
+ /// <summary>
+ /// The vector's Z axis.
+ /// </summary>
+ Z,
+ /// <summary>
+ /// The vector's W axis.
+ /// </summary>
+ W
+ }
+
+ /// <summary>
+ /// The vector's X component. Also accessible by using the index position <c>[0]</c>.
+ /// </summary>
+ public real_t x;
+
+ /// <summary>
+ /// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
+ /// </summary>
+ public real_t y;
+
+ /// <summary>
+ /// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
+ /// </summary>
+ public real_t z;
+
+ /// <summary>
+ /// The vector's W component. Also accessible by using the index position <c>[3]</c>.
+ /// </summary>
+ public real_t w;
+
+ /// <summary>
+ /// Access vector components using their index.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException">
+ /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3.
+ /// </exception>
+ /// <value>
+ /// <c>[0]</c> is equivalent to <see cref="x"/>,
+ /// <c>[1]</c> is equivalent to <see cref="y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="z"/>.
+ /// <c>[3]</c> is equivalent to <see cref="w"/>.
+ /// </value>
+ public real_t this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ case 3:
+ w = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w)
+ {
+ x = this.x;
+ y = this.y;
+ z = this.z;
+ w = this.w;
+ }
+
+ internal void Normalize()
+ {
+ real_t lengthsq = LengthSquared();
+
+ if (lengthsq == 0)
+ {
+ x = y = z = w = 0f;
+ }
+ else
+ {
+ real_t length = Mathf.Sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
+ w /= length;
+ }
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components in absolute values (i.e. positive).
+ /// </summary>
+ /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
+ public Vector4 Abs()
+ {
+ return new Vector4(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w));
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components rounded up (towards positive infinity).
+ /// </summary>
+ /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
+ public Vector4 Ceil()
+ {
+ return new Vector4(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z), Mathf.Ceil(w));
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components clamped between the
+ /// components of <paramref name="min"/> and <paramref name="max"/> using
+ /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>.
+ /// </summary>
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector4 Clamp(Vector4 min, Vector4 max)
+ {
+ return new Vector4
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y),
+ Mathf.Clamp(z, min.z, max.z),
+ Mathf.Clamp(w, min.w, max.w)
+ );
+ }
+
+ /// <summary>
+ /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// </summary>
+ /// <param name="b">The destination vector.</param>
+ /// <param name="preA">A vector before this vector.</param>
+ /// <param name="postB">A vector after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight)
+ {
+ return new Vector4
+ (
+ Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
+ Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
+ Mathf.CubicInterpolate(y, b.z, preA.z, postB.z, weight),
+ Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight)
+ );
+ }
+
+ /// <summary>
+ /// Returns the normalized vector pointing from this vector to <paramref name="to"/>.
+ /// </summary>
+ /// <param name="to">The other vector to point towards.</param>
+ /// <returns>The direction from this vector to <paramref name="to"/>.</returns>
+ public Vector4 DirectionTo(Vector4 to)
+ {
+ Vector4 ret = new Vector4(to.x - x, to.y - y, to.z - z, to.w - w);
+ ret.Normalize();
+ return ret;
+ }
+
+ /// <summary>
+ /// Returns the squared distance between this vector and <paramref name="to"/>.
+ /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
+ /// you need to compare vectors or need the squared distance for some formula.
+ /// </summary>
+ /// <param name="to">The other vector to use.</param>
+ /// <returns>The squared distance between the two vectors.</returns>
+ public real_t DistanceSquaredTo(Vector4 to)
+ {
+ return (to - this).LengthSquared();
+ }
+
+ /// <summary>
+ /// Returns the distance between this vector and <paramref name="to"/>.
+ /// </summary>
+ /// <param name="to">The other vector to use.</param>
+ /// <returns>The distance between the two vectors.</returns>
+ public real_t DistanceTo(Vector4 to)
+ {
+ return (to - this).Length();
+ }
+
+ /// <summary>
+ /// Returns the dot product of this vector and <paramref name="with"/>.
+ /// </summary>
+ /// <param name="with">The other vector to use.</param>
+ /// <returns>The dot product of the two vectors.</returns>
+ public real_t Dot(Vector4 with)
+ {
+ return (x * with.x) + (y * with.y) + (z * with.z) + (w + with.w);
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components rounded down (towards negative infinity).
+ /// </summary>
+ /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
+ public Vector4 Floor()
+ {
+ return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w));
+ }
+
+ /// <summary>
+ /// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.x, 1 / v.y, 1 / v.z, 1 / v.w)</c>.
+ /// </summary>
+ /// <returns>The inverse of this vector.</returns>
+ public Vector4 Inverse()
+ {
+ return new Vector4(1 / x, 1 / y, 1 / z, 1 / w);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
+ /// </summary>
+ /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
+ public bool IsNormalized()
+ {
+ return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ /// <summary>
+ /// Returns the length (magnitude) of this vector.
+ /// </summary>
+ /// <seealso cref="LengthSquared"/>
+ /// <returns>The length of this vector.</returns>
+ public real_t Length()
+ {
+ real_t x2 = x * x;
+ real_t y2 = y * y;
+ real_t z2 = z * z;
+ real_t w2 = w * w;
+
+ return Mathf.Sqrt(x2 + y2 + z2 + w2);
+ }
+
+ /// <summary>
+ /// Returns the squared length (squared magnitude) of this vector.
+ /// This method runs faster than <see cref="Length"/>, so prefer it if
+ /// you need to compare vectors or need the squared length for some formula.
+ /// </summary>
+ /// <returns>The squared length of this vector.</returns>
+ public real_t LengthSquared()
+ {
+ real_t x2 = x * x;
+ real_t y2 = y * y;
+ real_t z2 = z * z;
+ real_t w2 = w * w;
+
+ return x2 + y2 + z2 + w2;
+ }
+
+ /// <summary>
+ /// Returns the result of the linear interpolation between
+ /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>.
+ /// </summary>
+ /// <param name="to">The destination vector for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting vector of the interpolation.</returns>
+ public Vector4 Lerp(Vector4 to, real_t weight)
+ {
+ return new Vector4
+ (
+ Mathf.Lerp(x, to.x, weight),
+ Mathf.Lerp(y, to.y, weight),
+ Mathf.Lerp(z, to.z, weight),
+ Mathf.Lerp(w, to.w, weight)
+ );
+ }
+
+ /// <summary>
+ /// Returns the axis of the vector's highest value. See <see cref="Axis"/>.
+ /// If all components are equal, this method returns <see cref="Axis.X"/>.
+ /// </summary>
+ /// <returns>The index of the highest axis.</returns>
+ public Axis MaxAxisIndex()
+ {
+ int max_index = 0;
+ real_t max_value = x;
+ for (int i = 1; i < 4; i++)
+ {
+ if (this[i] > max_value)
+ {
+ max_index = i;
+ max_value = this[i];
+ }
+ }
+ return (Axis)max_index;
+ }
+
+ /// <summary>
+ /// Returns the axis of the vector's lowest value. See <see cref="Axis"/>.
+ /// If all components are equal, this method returns <see cref="Axis.W"/>.
+ /// </summary>
+ /// <returns>The index of the lowest axis.</returns>
+ public Axis MinAxisIndex()
+ {
+ int min_index = 0;
+ real_t min_value = x;
+ for (int i = 1; i < 4; i++)
+ {
+ if (this[i] <= min_value)
+ {
+ min_index = i;
+ min_value = this[i];
+ }
+ }
+ return (Axis)min_index;
+ }
+
+ /// <summary>
+ /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
+ /// </summary>
+ /// <returns>A normalized version of the vector.</returns>
+ public Vector4 Normalized()
+ {
+ Vector4 v = this;
+ v.Normalize();
+ return v;
+ }
+
+ /// <summary>
+ /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
+ /// and <paramref name="mod"/>.
+ /// </summary>
+ /// <param name="mod">A value representing the divisor of the operation.</param>
+ /// <returns>
+ /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
+ /// </returns>
+ public Vector4 PosMod(real_t mod)
+ {
+ return new Vector4(
+ Mathf.PosMod(x, mod),
+ Mathf.PosMod(y, mod),
+ Mathf.PosMod(z, mod),
+ Mathf.PosMod(w, mod)
+ );
+ }
+
+ /// <summary>
+ /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
+ /// and <paramref name="modv"/>'s components.
+ /// </summary>
+ /// <param name="modv">A vector representing the divisors of the operation.</param>
+ /// <returns>
+ /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
+ /// </returns>
+ public Vector4 PosMod(Vector4 modv)
+ {
+ return new Vector4(
+ Mathf.PosMod(x, modv.x),
+ Mathf.PosMod(y, modv.y),
+ Mathf.PosMod(z, modv.z),
+ Mathf.PosMod(w, modv.w)
+ );
+ }
+
+ /// <summary>
+ /// Returns this vector with all components rounded to the nearest integer,
+ /// with halfway cases rounded towards the nearest multiple of two.
+ /// </summary>
+ /// <returns>The rounded vector.</returns>
+ public Vector4 Round()
+ {
+ return new Vector4(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z), Mathf.Round(w));
+ }
+
+ /// <summary>
+ /// Returns a vector with each component set to one or negative one, depending
+ /// on the signs of this vector's components, or zero if the component is zero,
+ /// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
+ /// </summary>
+ /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
+ public Vector4 Sign()
+ {
+ Vector4 v;
+ v.x = Mathf.Sign(x);
+ v.y = Mathf.Sign(y);
+ v.z = Mathf.Sign(z);
+ v.w = Mathf.Sign(w);
+ return v;
+ }
+
+ /// <summary>
+ /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>.
+ /// This can also be used to round to an arbitrary number of decimals.
+ /// </summary>
+ /// <param name="step">A vector value representing the step size to snap to.</param>
+ public Vector4 Snapped(Vector4 step)
+ {
+ return new Vector4(
+ Mathf.Snapped(x, step.x),
+ Mathf.Snapped(y, step.y),
+ Mathf.Snapped(z, step.z),
+ Mathf.Snapped(w, step.w)
+ );
+ }
+
+ // Constants
+ private static readonly Vector4 _zero = new Vector4(0, 0, 0, 0);
+ private static readonly Vector4 _one = new Vector4(1, 1, 1, 1);
+ private static readonly Vector4 _inf = new Vector4(Mathf.Inf, Mathf.Inf, Mathf.Inf, Mathf.Inf);
+
+ /// <summary>
+ /// Zero vector, a vector with all components set to <c>0</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4(0, 0, 0, 0)</c>.</value>
+ public static Vector4 Zero { get { return _zero; } }
+ /// <summary>
+ /// One vector, a vector with all components set to <c>1</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4(1, 1, 1, 1)</c>.</value>
+ public static Vector4 One { get { return _one; } }
+ /// <summary>
+ /// Infinity vector, a vector with all components set to <see cref="Mathf.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4(Mathf.Inf, Mathf.Inf, Mathf.Inf, Mathf.Inf)</c>.</value>
+ public static Vector4 Inf { get { return _inf; } }
+
+ /// <summary>
+ /// Constructs a new <see cref="Vector4"/> with the given components.
+ /// </summary>
+ /// <param name="x">The vector's X component.</param>
+ /// <param name="y">The vector's Y component.</param>
+ /// <param name="z">The vector's Z component.</param>
+ /// <param name="w">The vector's W component.</param>
+ public Vector4(real_t x, real_t y, real_t z, real_t w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Vector4"/> from an existing <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="v">The existing <see cref="Vector4"/>.</param>
+ public Vector4(Vector4 v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ w = v.w;
+ }
+
+ /// <summary>
+ /// Adds each component of the <see cref="Vector4"/>
+ /// with the components of the given <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The added vector.</returns>
+ public static Vector4 operator +(Vector4 left, Vector4 right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+ left.w += right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Subtracts each component of the <see cref="Vector4"/>
+ /// by the components of the given <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The subtracted vector.</returns>
+ public static Vector4 operator -(Vector4 left, Vector4 right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+ left.w -= right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Returns the negative value of the <see cref="Vector4"/>.
+ /// This is the same as writing <c>new Vector4(-v.x, -v.y, -v.z, -v.w)</c>.
+ /// This operation flips the direction of the vector while
+ /// keeping the same magnitude.
+ /// With floats, the number zero can be either positive or negative.
+ /// </summary>
+ /// <param name="vec">The vector to negate/flip.</param>
+ /// <returns>The negated/flipped vector.</returns>
+ public static Vector4 operator -(Vector4 vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ vec.z = -vec.z;
+ vec.w = -vec.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4"/>
+ /// by the given <see cref="real_t"/>.
+ /// </summary>
+ /// <param name="vec">The vector to multiply.</param>
+ /// <param name="scale">The scale to multiply by.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4 operator *(Vector4 vec, real_t scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ vec.w *= scale;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4"/>
+ /// by the given <see cref="real_t"/>.
+ /// </summary>
+ /// <param name="scale">The scale to multiply by.</param>
+ /// <param name="vec">The vector to multiply.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4 operator *(real_t scale, Vector4 vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ vec.w *= scale;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4"/>
+ /// by the components of the given <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4 operator *(Vector4 left, Vector4 right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ left.z *= right.z;
+ left.w *= right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Divides each component of the <see cref="Vector4"/>
+ /// by the given <see cref="real_t"/>.
+ /// </summary>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisor">The divisor value.</param>
+ /// <returns>The divided vector.</returns>
+ public static Vector4 operator /(Vector4 vec, real_t divisor)
+ {
+ vec.x /= divisor;
+ vec.y /= divisor;
+ vec.z /= divisor;
+ vec.w /= divisor;
+ return vec;
+ }
+
+ /// <summary>
+ /// Divides each component of the <see cref="Vector4"/>
+ /// by the components of the given <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisorv">The divisor vector.</param>
+ /// <returns>The divided vector.</returns>
+ public static Vector4 operator /(Vector4 vec, Vector4 divisorv)
+ {
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ vec.z /= divisorv.z;
+ vec.w /= divisorv.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are exactly equal.
+ /// Note: Due to floating-point precision errors, consider using
+ /// <see cref="IsEqualApprox"/> instead, which is more reliable.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the vectors are exactly equal.</returns>
+ public static bool operator ==(Vector4 left, Vector4 right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are not equal.
+ /// Note: Due to floating-point precision errors, consider using
+ /// <see cref="IsEqualApprox"/> instead, which is more reliable.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the vectors are not equal.</returns>
+ public static bool operator !=(Vector4 left, Vector4 right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is less than
+ /// the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is less than the right.</returns>
+ public static bool operator <(Vector4 left, Vector4 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w < right.w;
+ }
+ return left.z < right.z;
+ }
+ return left.y < right.y;
+ }
+ return left.x < right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is greater than
+ /// the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is greater than the right.</returns>
+ public static bool operator >(Vector4 left, Vector4 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w > right.w;
+ }
+ return left.z > right.z;
+ }
+ return left.y > right.y;
+ }
+ return left.x > right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is less than
+ /// or equal to the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is less than or equal to the right.</returns>
+ public static bool operator <=(Vector4 left, Vector4 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w <= right.w;
+ }
+ return left.z < right.z;
+ }
+ return left.y < right.y;
+ }
+ return left.x < right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is greater than
+ /// or equal to the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is greater than or equal to the right.</returns>
+ public static bool operator >=(Vector4 left, Vector4 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w >= right.w;
+ }
+ return left.z > right.z;
+ }
+ return left.y > right.y;
+ }
+ return left.x > right.x;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vector is exactly equal
+ /// to the given object (<see paramref="obj"/>).
+ /// Note: Due to floating-point precision errors, consider using
+ /// <see cref="IsEqualApprox"/> instead, which is more reliable.
+ /// </summary>
+ /// <param name="obj">The object to compare with.</param>
+ /// <returns>Whether or not the vector and the object are equal.</returns>
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector4)
+ {
+ return Equals((Vector4)obj);
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are exactly equal.
+ /// Note: Due to floating-point precision errors, consider using
+ /// <see cref="IsEqualApprox"/> instead, which is more reliable.
+ /// </summary>
+ /// <param name="other">The other vector.</param>
+ /// <returns>Whether or not the vectors are exactly equal.</returns>
+ public bool Equals(Vector4 other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are approximately equal,
+ /// by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component.
+ /// </summary>
+ /// <param name="other">The other vector to compare.</param>
+ /// <returns>Whether or not the vectors are approximately equal.</returns>
+ public bool IsEqualApprox(Vector4 other)
+ {
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
+ }
+
+ /// <summary>
+ /// Serves as the hash function for <see cref="Vector4"/>.
+ /// </summary>
+ /// <returns>A hash code for this vector.</returns>
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Vector4"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this vector.</returns>
+ public override string ToString()
+ {
+ return $"({x}, {y}, {z}, {w})";
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>.
+ /// </summary>
+ /// <returns>A string representation of this vector.</returns>
+ public string ToString(string format)
+ {
+ return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})";
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
new file mode 100644
index 0000000000..365dcef486
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
@@ -0,0 +1,702 @@
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ /// <summary>
+ /// 4-element structure that can be used to represent 4D grid coordinates or sets of integers.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector4i : IEquatable<Vector4i>
+ {
+ /// <summary>
+ /// Enumerated index values for the axes.
+ /// Returned by <see cref="MaxAxisIndex"/> and <see cref="MinAxisIndex"/>.
+ /// </summary>
+ public enum Axis
+ {
+ /// <summary>
+ /// The vector's X axis.
+ /// </summary>
+ X = 0,
+ /// <summary>
+ /// The vector's Y axis.
+ /// </summary>
+ Y,
+ /// <summary>
+ /// The vector's Z axis.
+ /// </summary>
+ Z,
+ /// <summary>
+ /// The vector's W axis.
+ /// </summary>
+ W
+ }
+
+ /// <summary>
+ /// The vector's X component. Also accessible by using the index position <c>[0]</c>.
+ /// </summary>
+ public int x;
+
+ /// <summary>
+ /// The vector's Y component. Also accessible by using the index position <c>[1]</c>.
+ /// </summary>
+ public int y;
+
+ /// <summary>
+ /// The vector's Z component. Also accessible by using the index position <c>[2]</c>.
+ /// </summary>
+ public int z;
+
+ /// <summary>
+ /// The vector's W component. Also accessible by using the index position <c>[3]</c>.
+ /// </summary>
+ public int w;
+
+ /// <summary>
+ /// Access vector components using their <paramref name="index"/>.
+ /// </summary>
+ /// <exception cref="IndexOutOfRangeException">
+ /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3.
+ /// </exception>
+ /// <value>
+ /// <c>[0]</c> is equivalent to <see cref="x"/>,
+ /// <c>[1]</c> is equivalent to <see cref="y"/>,
+ /// <c>[2]</c> is equivalent to <see cref="z"/>.
+ /// <c>[3]</c> is equivalent to <see cref="w"/>.
+ /// </value>
+ public int this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ case 3:
+ w = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Helper method for deconstruction into a tuple.
+ /// </summary>
+ public void Deconstruct(out int x, out int y, out int z, out int w)
+ {
+ x = this.x;
+ y = this.y;
+ z = this.z;
+ w = this.w;
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components in absolute values (i.e. positive).
+ /// </summary>
+ /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns>
+ public Vector4i Abs()
+ {
+ return new Vector4i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w));
+ }
+
+ /// <summary>
+ /// Returns a new vector with all components clamped between the
+ /// components of <paramref name="min"/> and <paramref name="max"/> using
+ /// <see cref="Mathf.Clamp(int, int, int)"/>.
+ /// </summary>
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector4i Clamp(Vector4i min, Vector4i max)
+ {
+ return new Vector4i
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y),
+ Mathf.Clamp(z, min.z, max.z),
+ Mathf.Clamp(w, min.w, max.w)
+ );
+ }
+
+ /// <summary>
+ /// Returns the length (magnitude) of this vector.
+ /// </summary>
+ /// <seealso cref="LengthSquared"/>
+ /// <returns>The length of this vector.</returns>
+ public real_t Length()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+ int z2 = z * z;
+ int w2 = w * w;
+
+ return Mathf.Sqrt(x2 + y2 + z2 + w2);
+ }
+
+ /// <summary>
+ /// Returns the squared length (squared magnitude) of this vector.
+ /// This method runs faster than <see cref="Length"/>, so prefer it if
+ /// you need to compare vectors or need the squared length for some formula.
+ /// </summary>
+ /// <returns>The squared length of this vector.</returns>
+ public int LengthSquared()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+ int z2 = z * z;
+ int w2 = w * w;
+
+ return x2 + y2 + z2 + w2;
+ }
+
+ /// <summary>
+ /// Returns the axis of the vector's highest value. See <see cref="Axis"/>.
+ /// If all components are equal, this method returns <see cref="Axis.X"/>.
+ /// </summary>
+ /// <returns>The index of the highest axis.</returns>
+ public Axis MaxAxisIndex()
+ {
+ int max_index = 0;
+ int max_value = x;
+ for (int i = 1; i < 4; i++)
+ {
+ if (this[i] > max_value)
+ {
+ max_index = i;
+ max_value = this[i];
+ }
+ }
+ return (Axis)max_index;
+ }
+
+ /// <summary>
+ /// Returns the axis of the vector's lowest value. See <see cref="Axis"/>.
+ /// If all components are equal, this method returns <see cref="Axis.W"/>.
+ /// </summary>
+ /// <returns>The index of the lowest axis.</returns>
+ public Axis MinAxisIndex()
+ {
+ int min_index = 0;
+ int min_value = x;
+ for (int i = 1; i < 4; i++)
+ {
+ if (this[i] <= min_value)
+ {
+ min_index = i;
+ min_value = this[i];
+ }
+ }
+ return (Axis)min_index;
+ }
+
+ /// <summary>
+ /// Returns a vector with each component set to one or negative one, depending
+ /// on the signs of this vector's components, or zero if the component is zero,
+ /// by calling <see cref="Mathf.Sign(int)"/> on each component.
+ /// </summary>
+ /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns>
+ public Vector4i Sign()
+ {
+ return new Vector4i(Mathf.Sign(x), Mathf.Sign(y), Mathf.Sign(z), Mathf.Sign(w));
+ }
+
+ // Constants
+ private static readonly Vector4i _zero = new Vector4i(0, 0, 0, 0);
+ private static readonly Vector4i _one = new Vector4i(1, 1, 1, 1);
+
+ /// <summary>
+ /// Zero vector, a vector with all components set to <c>0</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4i(0, 0, 0, 0)</c>.</value>
+ public static Vector4i Zero { get { return _zero; } }
+ /// <summary>
+ /// One vector, a vector with all components set to <c>1</c>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4i(1, 1, 1, 1)</c>.</value>
+ public static Vector4i One { get { return _one; } }
+
+ /// <summary>
+ /// Constructs a new <see cref="Vector4i"/> with the given components.
+ /// </summary>
+ /// <param name="x">The vector's X component.</param>
+ /// <param name="y">The vector's Y component.</param>
+ /// <param name="z">The vector's Z component.</param>
+ /// <param name="w">The vector's W component.</param>
+ public Vector4i(int x, int y, int z, int w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="vi">The existing <see cref="Vector4i"/>.</param>
+ public Vector4i(Vector4i vi)
+ {
+ this.x = vi.x;
+ this.y = vi.y;
+ this.z = vi.z;
+ this.w = vi.w;
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4"/>
+ /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>.
+ /// </summary>
+ /// <param name="v">The <see cref="Vector4"/> to convert.</param>
+ public Vector4i(Vector4 v)
+ {
+ this.x = Mathf.RoundToInt(v.x);
+ this.y = Mathf.RoundToInt(v.y);
+ this.z = Mathf.RoundToInt(v.z);
+ this.w = Mathf.RoundToInt(v.w);
+ }
+
+ /// <summary>
+ /// Adds each component of the <see cref="Vector4i"/>
+ /// with the components of the given <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The added vector.</returns>
+ public static Vector4i operator +(Vector4i left, Vector4i right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+ left.w += right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Subtracts each component of the <see cref="Vector4i"/>
+ /// by the components of the given <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The subtracted vector.</returns>
+ public static Vector4i operator -(Vector4i left, Vector4i right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+ left.w -= right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Returns the negative value of the <see cref="Vector4i"/>.
+ /// This is the same as writing <c>new Vector4i(-v.x, -v.y, -v.z, -v.w)</c>.
+ /// This operation flips the direction of the vector while
+ /// keeping the same magnitude.
+ /// </summary>
+ /// <param name="vec">The vector to negate/flip.</param>
+ /// <returns>The negated/flipped vector.</returns>
+ public static Vector4i operator -(Vector4i vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ vec.z = -vec.z;
+ vec.w = -vec.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4i"/>
+ /// by the given <see langword="int"/>.
+ /// </summary>
+ /// <param name="vec">The vector to multiply.</param>
+ /// <param name="scale">The scale to multiply by.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4i operator *(Vector4i vec, int scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ vec.w *= scale;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4i"/>
+ /// by the given <see langword="int"/>.
+ /// </summary>
+ /// <param name="scale">The scale to multiply by.</param>
+ /// <param name="vec">The vector to multiply.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4i operator *(int scale, Vector4i vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ vec.w *= scale;
+ return vec;
+ }
+
+ /// <summary>
+ /// Multiplies each component of the <see cref="Vector4i"/>
+ /// by the components of the given <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>The multiplied vector.</returns>
+ public static Vector4i operator *(Vector4i left, Vector4i right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ left.z *= right.z;
+ left.w *= right.w;
+ return left;
+ }
+
+ /// <summary>
+ /// Divides each component of the <see cref="Vector4i"/>
+ /// by the given <see langword="int"/>.
+ /// </summary>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisor">The divisor value.</param>
+ /// <returns>The divided vector.</returns>
+ public static Vector4i operator /(Vector4i vec, int divisor)
+ {
+ vec.x /= divisor;
+ vec.y /= divisor;
+ vec.z /= divisor;
+ vec.w /= divisor;
+ return vec;
+ }
+
+ /// <summary>
+ /// Divides each component of the <see cref="Vector4i"/>
+ /// by the components of the given <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisorv">The divisor vector.</param>
+ /// <returns>The divided vector.</returns>
+ public static Vector4i operator /(Vector4i vec, Vector4i divisorv)
+ {
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ vec.z /= divisorv.z;
+ vec.w /= divisorv.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4i"/>
+ /// with the components of the given <see langword="int"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vecto43i(10, -20, 30, -40) % 7); // Prints "(3, -6, 2, -5)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisor">The divisor value.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4i operator %(Vector4i vec, int divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ vec.z %= divisor;
+ vec.w %= divisor;
+ return vec;
+ }
+
+ /// <summary>
+ /// Gets the remainder of each component of the <see cref="Vector4i"/>
+ /// with the components of the given <see cref="Vector4i"/>.
+ /// This operation uses truncated division, which is often not desired
+ /// as it does not work well with negative numbers.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// GD.Print(new Vector4i(10, -20, 30, -40) % new Vector4i(6, 7, 8, 9)); // Prints "(4, -6, 6, -4)"
+ /// </code>
+ /// </example>
+ /// <param name="vec">The dividend vector.</param>
+ /// <param name="divisorv">The divisor vector.</param>
+ /// <returns>The remainder vector.</returns>
+ public static Vector4i operator %(Vector4i vec, Vector4i divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ vec.z %= divisorv.z;
+ vec.w %= divisorv.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
+ /// and the given <see langword="int"/>.
+ /// </summary>
+ /// <param name="vec">The vector to AND with.</param>
+ /// <param name="and">The integer to AND with.</param>
+ /// <returns>The result of the bitwise AND.</returns>
+ public static Vector4i operator &(Vector4i vec, int and)
+ {
+ vec.x &= and;
+ vec.y &= and;
+ vec.z &= and;
+ vec.w &= and;
+ return vec;
+ }
+
+ /// <summary>
+ /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
+ /// and the given <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="vec">The left vector to AND with.</param>
+ /// <param name="andv">The right vector to AND with.</param>
+ /// <returns>The result of the bitwise AND.</returns>
+ public static Vector4i operator &(Vector4i vec, Vector4i andv)
+ {
+ vec.x &= andv.x;
+ vec.y &= andv.y;
+ vec.z &= andv.z;
+ vec.w &= andv.w;
+ return vec;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are equal.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the vectors are equal.</returns>
+ public static bool operator ==(Vector4i left, Vector4i right)
+ {
+ return left.Equals(right);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are not equal.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the vectors are not equal.</returns>
+ public static bool operator !=(Vector4i left, Vector4i right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is less than
+ /// the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is less than the right.</returns>
+ public static bool operator <(Vector4i left, Vector4i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w < right.w;
+ }
+ return left.z < right.z;
+ }
+ return left.y < right.y;
+ }
+ return left.x < right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is greater than
+ /// the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is greater than the right.</returns>
+ public static bool operator >(Vector4i left, Vector4i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w > right.w;
+ }
+ return left.z > right.z;
+ }
+ return left.y > right.y;
+ }
+ return left.x > right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is less than
+ /// or equal to the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is less than or equal to the right.</returns>
+ public static bool operator <=(Vector4i left, Vector4i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w <= right.w;
+ }
+ return left.z < right.z;
+ }
+ return left.y < right.y;
+ }
+ return left.x < right.x;
+ }
+
+ /// <summary>
+ /// Compares two <see cref="Vector4i"/> vectors by first checking if
+ /// the X value of the <paramref name="left"/> vector is greater than
+ /// or equal to the X value of the <paramref name="right"/> vector.
+ /// If the X values are exactly equal, then it repeats this check
+ /// with the Y, Z and finally W values of the two vectors.
+ /// This operator is useful for sorting vectors.
+ /// </summary>
+ /// <param name="left">The left vector.</param>
+ /// <param name="right">The right vector.</param>
+ /// <returns>Whether or not the left is greater than or equal to the right.</returns>
+ public static bool operator >=(Vector4i left, Vector4i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ {
+ if (left.z == right.z)
+ {
+ return left.w >= right.w;
+ }
+ return left.z > right.z;
+ }
+ return left.y > right.y;
+ }
+ return left.x > right.x;
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Vector4i"/> to a <see cref="Vector4"/>.
+ /// </summary>
+ /// <param name="value">The vector to convert.</param>
+ public static implicit operator Vector4(Vector4i value)
+ {
+ return new Vector4(value.x, value.y, value.z, value.w);
+ }
+
+ /// <summary>
+ /// Converts a <see cref="Vector4"/> to a <see cref="Vector4i"/>.
+ /// </summary>
+ /// <param name="value">The vector to convert.</param>
+ public static explicit operator Vector4i(Vector4 value)
+ {
+ return new Vector4i(value);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vector is equal
+ /// to the given object (<see paramref="obj"/>).
+ /// </summary>
+ /// <param name="obj">The object to compare with.</param>
+ /// <returns>Whether or not the vector and the object are equal.</returns>
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector4i)
+ {
+ return Equals((Vector4i)obj);
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the vectors are equal.
+ /// </summary>
+ /// <param name="other">The other vector.</param>
+ /// <returns>Whether or not the vectors are equal.</returns>
+ public bool Equals(Vector4i other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ /// <summary>
+ /// Serves as the hash function for <see cref="Vector4i"/>.
+ /// </summary>
+ /// <returns>A hash code for this vector.</returns>
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Vector4i"/> to a string.
+ /// </summary>
+ /// <returns>A string representation of this vector.</returns>
+ public override string ToString()
+ {
+ return $"({x}, {y}, {z}, {w})";
+ }
+
+ /// <summary>
+ /// Converts this <see cref="Vector4i"/> to a string with the given <paramref name="format"/>.
+ /// </summary>
+ /// <returns>A string representation of this vector.</returns>
+ public string ToString(string format)
+ {
+ return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}), {w.ToString(format)})";
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 1fcfe74c86..4f55ce47e8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -18,7 +18,7 @@
<Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.cs" />
<Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
- <Compile Include="Core\Attributes\RPCAttributes.cs" />
+ <Compile Include="Core\Attributes\RPCAttribute.cs" />
<Compile Include="Core\Attributes\ScriptPathAttribute.cs" />
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
@@ -50,6 +50,7 @@
<Compile Include="Core\NodePath.cs" />
<Compile Include="Core\Object.base.cs" />
<Compile Include="Core\Plane.cs" />
+ <Compile Include="Core\Projection.cs" />
<Compile Include="Core\Quaternion.cs" />
<Compile Include="Core\Rect2.cs" />
<Compile Include="Core\Rect2i.cs" />
@@ -65,6 +66,8 @@
<Compile Include="Core\Vector2i.cs" />
<Compile Include="Core\Vector3.cs" />
<Compile Include="Core\Vector3i.cs" />
+ <Compile Include="Core\Vector4.cs" />
+ <Compile Include="Core\Vector4i.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<!--
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
index 7c991d87a4..4405809887 100644
--- a/modules/mono/glue/arguments_vector.h
+++ b/modules/mono/glue/arguments_vector.h
@@ -37,7 +37,7 @@ template <typename T, int POOL_SIZE = 5>
struct ArgumentsVector {
private:
T pool[POOL_SIZE];
- T *_ptr;
+ T *_ptr = nullptr;
int size;
ArgumentsVector() = delete;
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 8e7b125ed5..7b9dbc87cf 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -68,7 +68,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
@@ -115,7 +115,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
void *data = CSharpLanguage::get_existing_instance_binding(rc);
if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
@@ -148,7 +148,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
if (rc) {
- REF r = rc;
+ Ref<RefCounted> r = rc;
if (!r.is_valid()) {
return nullptr;
}
@@ -199,7 +199,7 @@ MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoStrin
}
Callable::CallError error;
- Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error);
+ Variant result = p_ptr->callp(StringName(name), args.ptr(), argc, error);
*r_result = GDMonoMarshal::variant_to_mono_object(result);
diff --git a/modules/mono/glue/callable_glue.cpp b/modules/mono/glue/callable_glue.cpp
index e59b34313c..521dc3dff7 100644
--- a/modules/mono/glue/callable_glue.cpp
+++ b/modules/mono/glue/callable_glue.cpp
@@ -49,7 +49,7 @@ MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, Mon
Variant result;
Callable::CallError error;
- callable.call(args.ptr(), argc, result, error);
+ callable.callp(args.ptr(), argc, result, error);
return GDMonoMarshal::variant_to_mono_object(result);
}
@@ -68,7 +68,7 @@ void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, Mo
args.set(i, &arg_store.get(i));
}
- callable.call_deferred(args.ptr(), argc);
+ callable.call_deferredp(args.ptr(), argc);
}
void godot_register_callable_icalls() {
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 8aead217cf..8b1c2b729e 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -90,6 +90,27 @@ void godot_icall_GD_print(MonoArray *p_what) {
print_line(str);
}
+void godot_icall_GD_print_rich(MonoArray *p_what) {
+ String str;
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = nullptr;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
+ str += elem_str;
+ }
+
+ print_line_rich(str);
+}
+
void godot_icall_GD_printerr(MonoArray *p_what) {
String str;
int length = mono_array_length(p_what);
@@ -300,6 +321,7 @@ void godot_register_gd_icalls() {
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print);
+ GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print_rich", godot_icall_GD_print_rich);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints);
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 9638b23410..f9ad1a9893 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GLUE_HEADER_H
+#define GLUE_HEADER_H
+
#ifdef MONO_GLUE_ENABLED
#include "../mono_gd/gd_mono_marshal.h"
@@ -84,3 +87,5 @@ void godot_register_glue_header_icalls() {
#include "arguments_vector.h"
#endif // MONO_GLUE_ENABLED
+
+#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
index 0ea9814b1a..16e1509eb0 100644
--- a/modules/mono/glue/nodepath_glue.cpp
+++ b/modules/mono/glue/nodepath_glue.cpp
@@ -68,6 +68,10 @@ MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx) {
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_subname(p_idx));
}
+MonoString *godot_icall_NodePath_get_concatenated_names(NodePath *p_ptr) {
+ return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_names());
+}
+
MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) {
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames());
}
@@ -85,6 +89,7 @@ void godot_register_nodepath_icalls() {
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
+ GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_names", godot_icall_NodePath_get_concatenated_names);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index c0cd18e29d..f17b24e399 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -36,7 +36,7 @@
#ifdef TOOLS_ENABLED
#include "core/version.h"
-#include "editor/editor_settings.h"
+#include "editor/editor_paths.h"
#endif
#ifdef ANDROID_ENABLED
@@ -76,7 +76,7 @@ String _get_mono_user_dir() {
exe_dir = exe_dir.plus_file("../../..").simplify_path();
}
- DirAccessRef d = DirAccess::create_for_path(exe_dir);
+ Ref<DirAccess> d = DirAccess::create_for_path(exe_dir);
if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
// contain yourself
@@ -184,7 +184,7 @@ private:
data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
#endif
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools");
}
@@ -222,7 +222,7 @@ private:
data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
#endif
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index 8ed21c323f..c159bb9eea 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -36,7 +36,7 @@
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable>::List ManagedCallable::instances;
-Map<ManagedCallable *, Array> ManagedCallable::instances_pending_reload;
+RBMap<ManagedCallable *, Array> ManagedCallable::instances_pending_reload;
Mutex ManagedCallable::instances_mutex;
#endif
@@ -66,9 +66,8 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust
}
uint32_t ManagedCallable::hash() const {
- // hmm
uint32_t hash = delegate_invoke->get_name().hash();
- return hash_djb2_one_64(delegate_handle.handle, hash);
+ return hash_murmur3_one_64(delegate_handle.handle, hash);
}
String ManagedCallable::get_as_text() const {
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index ea7231f43b..11bee6cf60 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -43,12 +43,12 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
MonoGCHandleData delegate_handle;
- GDMonoMethod *delegate_invoke;
+ GDMonoMethod *delegate_invoke = nullptr;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
static SelfList<ManagedCallable>::List instances;
- static Map<ManagedCallable *, Array> instances_pending_reload;
+ static RBMap<ManagedCallable *, Array> instances_pending_reload;
static Mutex instances_mutex;
#endif
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index ab9e508c99..e2aff1d19d 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CSHARP_GC_HANDLE_H
-#define CSHARP_GC_HANDLE_H
+#ifndef MONO_GC_HANDLE_H
+#define MONO_GC_HANDLE_H
#include <mono/jit/jit.h>
@@ -104,4 +104,4 @@ public:
~MonoGCHandleRef() { release(); }
};
-#endif // CSHARP_GC_HANDLE_H
+#endif // MONO_GC_HANDLE_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index a7269d7f87..d3d3bb2bef 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -55,7 +55,7 @@
#ifdef ANDROID_ENABLED
#include "android_mono_config.h"
#include "support/android_support.h"
-#elif defined(IPHONE_ENABLED)
+#elif defined(IOS_ENABLED)
#include "support/ios_support.h"
#endif
@@ -151,8 +151,9 @@ void gd_mono_debug_init() {
.utf8();
}
#else
- if (da_args.length() == 0)
+ if (da_args.length() == 0) {
return; // Exported games don't use the project settings to setup the debugger agent
+ }
#endif
// Debugging enabled
@@ -187,7 +188,7 @@ MonoDomain *gd_initialize_mono_runtime() {
MonoDomain *gd_initialize_mono_runtime() {
gd_mono_debug_init();
-#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED)
+#if defined(IOS_ENABLED) || defined(ANDROID_ENABLED)
// I don't know whether this actually matters or not
const char *runtime_version = "mobile";
#else
@@ -226,8 +227,9 @@ void GDMono::add_mono_shared_libs_dir_to_path() {
path_value += mono_reg_info.bin_dir;
}
#else
- if (DirAccess::exists(bundled_bin_dir))
+ if (DirAccess::exists(bundled_bin_dir)) {
path_value += bundled_bin_dir;
+ }
#endif // TOOLS_ENABLED
#else
@@ -261,7 +263,7 @@ void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_di
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
r_config_dir = mono_reg_info.config_dir;
}
-#elif defined(OSX_ENABLED)
+#elif defined(MACOS_ENABLED)
const char *c_assembly_rootdir = mono_assembly_getrootdir();
const char *c_config_dir = mono_get_config_dir();
@@ -341,7 +343,7 @@ void GDMono::initialize() {
#if defined(ANDROID_ENABLED)
gdmono::android::support::initialize();
-#elif defined(IPHONE_ENABLED)
+#elif defined(IOS_ENABLED)
gdmono::ios::support::initialize();
#endif
@@ -641,9 +643,8 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
// Create destination directory if needed
if (!DirAccess::exists(dst_dir)) {
- DirAccess *da = DirAccess::create_for_path(dst_dir);
+ Ref<DirAccess> da = DirAccess::create_for_path(dst_dir);
Error err = da->make_dir_recursive(dst_dir);
- memdelete(da);
if (err != OK) {
ERR_PRINT("Failed to create destination directory for the API assemblies. Error: " + itos(err) + ".");
@@ -651,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
}
}
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = assembly_name + ".xml";
if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
@@ -1166,9 +1167,8 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ GDMonoAssembly *assembly = E.value;
if (assembly->get_image() == image) {
GDMonoClass *klass = assembly->get_class(p_raw_class);
if (klass) {
@@ -1189,9 +1189,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ GDMonoAssembly *assembly = E.value;
klass = assembly->get_class(p_namespace, p_name);
if (klass) {
return klass;
@@ -1204,9 +1203,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- memdelete(domain_assemblies.get(*k));
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ memdelete(E.value);
}
assemblies.erase(p_domain_id);
@@ -1269,8 +1267,9 @@ GDMono::~GDMono() {
print_verbose("Mono: Finalizing scripts domain...");
- if (mono_domain_get() != root_domain)
+ if (mono_domain_get() != root_domain) {
mono_domain_set(root_domain, true);
+ }
finalizing_scripts_domain = true;
@@ -1296,13 +1295,11 @@ GDMono::~GDMono() {
// Leave the rest to 'mono_jit_cleanup'
#endif
- const int32_t *k = nullptr;
- while ((k = assemblies.next(k))) {
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
+ for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) {
+ const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value;
- const String *kk = nullptr;
- while ((kk = domain_assemblies.next(kk))) {
- memdelete(domain_assemblies.get(*kk));
+ for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) {
+ memdelete(F.value);
}
}
assemblies.clear();
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index aab0b31c37..51fd0f8483 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -94,16 +94,16 @@ private:
UnhandledExceptionPolicy unhandled_exception_policy;
- MonoDomain *root_domain;
- MonoDomain *scripts_domain;
+ MonoDomain *root_domain = nullptr;
+ MonoDomain *scripts_domain = nullptr;
HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies;
- GDMonoAssembly *corlib_assembly;
- GDMonoAssembly *project_assembly;
+ GDMonoAssembly *corlib_assembly = nullptr;
+ GDMonoAssembly *project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- GDMonoAssembly *tools_assembly;
- GDMonoAssembly *tools_project_editor_assembly;
+ GDMonoAssembly *tools_assembly = nullptr;
+ GDMonoAssembly *tools_project_editor_assembly = nullptr;
#endif
LoadedApiAssembly core_api_assembly;
@@ -150,7 +150,7 @@ private:
void _init_godot_api_hashes();
void _init_exception_policy();
- GDMonoLog *gdmono_log;
+ GDMonoLog *gdmono_log = nullptr;
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
MonoRegInfo mono_reg_info;
@@ -250,7 +250,7 @@ public:
namespace gdmono {
class ScopeDomain {
- MonoDomain *prev_domain;
+ MonoDomain *prev_domain = nullptr;
public:
ScopeDomain(MonoDomain *p_domain) {
@@ -270,7 +270,7 @@ public:
};
class ScopeExitDomainUnload {
- MonoDomain *domain;
+ MonoDomain *domain = nullptr;
public:
ScopeExitDomainUnload(MonoDomain *p_domain) :
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 3991b14612..42c6b6305f 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -412,10 +412,10 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri
GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
ERR_FAIL_NULL_V(image, nullptr);
- Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
+ HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class);
if (match) {
- return match->value();
+ return match->value;
}
StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class));
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index b25d773be7..0a3ae6c4fe 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -36,7 +36,7 @@
#include "core/string/ustring.h"
#include "core/templates/hash_map.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "gd_mono_utils.h"
class GDMonoAssembly {
@@ -68,8 +68,8 @@ class GDMonoAssembly {
};
String name;
- MonoImage *image;
- MonoAssembly *assembly;
+ MonoImage *image = nullptr;
+ MonoAssembly *assembly = nullptr;
bool attrs_fetched = false;
MonoCustomAttrInfo *attributes = nullptr;
@@ -79,7 +79,7 @@ class GDMonoAssembly {
#endif
HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
- Map<MonoClass *, GDMonoClass *> cached_raw;
+ HashMap<MonoClass *, GDMonoClass *> cached_raw;
static Vector<String> search_dirs;
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index d8fd244067..69d8c7edc9 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -108,9 +108,12 @@ void CachedData::clear_godot_api_cache() {
class_Transform2D = nullptr;
class_Vector3 = nullptr;
class_Vector3i = nullptr;
+ class_Vector4 = nullptr;
+ class_Vector4i = nullptr;
class_Basis = nullptr;
class_Quaternion = nullptr;
class_Transform3D = nullptr;
+ class_Projection = nullptr;
class_AABB = nullptr;
class_Color = nullptr;
class_Plane = nullptr;
@@ -140,8 +143,11 @@ void CachedData::clear_godot_api_cache() {
field_ExportAttribute_hintString = nullptr;
class_SignalAttribute = nullptr;
class_ToolAttribute = nullptr;
- class_AnyPeerAttribute = nullptr;
- class_AuthorityAttribute = nullptr;
+ class_RPCAttribute = nullptr;
+ property_RPCAttribute_Mode = nullptr;
+ property_RPCAttribute_CallLocal = nullptr;
+ property_RPCAttribute_TransferMode = nullptr;
+ property_RPCAttribute_TransferChannel = nullptr;
class_GodotMethodAttribute = nullptr;
field_GodotMethodAttribute_methodName = nullptr;
class_ScriptPathAttribute = nullptr;
@@ -176,6 +182,7 @@ void CachedData::clear_godot_api_cache() {
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
+ methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
@@ -235,9 +242,12 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i));
+ CACHE_CLASS_AND_CHECK(Vector4, GODOT_API_CLASS(Vector4));
+ CACHE_CLASS_AND_CHECK(Vector4i, GODOT_API_CLASS(Vector4i));
CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion));
CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D));
+ CACHE_CLASS_AND_CHECK(Projection, GODOT_API_CLASS(Projection));
CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
@@ -267,8 +277,11 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
- CACHE_CLASS_AND_CHECK(AnyPeerAttribute, GODOT_API_CLASS(AnyPeerAttribute));
- CACHE_CLASS_AND_CHECK(AuthorityAttribute, GODOT_API_CLASS(AuthorityAttribute));
+ CACHE_CLASS_AND_CHECK(RPCAttribute, GODOT_API_CLASS(RPCAttribute));
+ CACHE_PROPERTY_AND_CHECK(RPCAttribute, Mode, CACHED_CLASS(RPCAttribute)->get_property("Mode"));
+ CACHE_PROPERTY_AND_CHECK(RPCAttribute, CallLocal, CACHED_CLASS(RPCAttribute)->get_property("CallLocal"));
+ CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferMode, CACHED_CLASS(RPCAttribute)->get_property("TransferMode"));
+ CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferChannel, CACHED_CLASS(RPCAttribute)->get_property("TransferChannel"));
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
@@ -300,6 +313,7 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 49f47b0a15..e9cc26899e 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -41,91 +41,97 @@ struct CachedData {
// corlib classes
// Let's use the no-namespace format for these too
- GDMonoClass *class_MonoObject; // object
- GDMonoClass *class_bool; // bool
- GDMonoClass *class_int8_t; // sbyte
- GDMonoClass *class_int16_t; // short
- GDMonoClass *class_int32_t; // int
- GDMonoClass *class_int64_t; // long
- GDMonoClass *class_uint8_t; // byte
- GDMonoClass *class_uint16_t; // ushort
- GDMonoClass *class_uint32_t; // uint
- GDMonoClass *class_uint64_t; // ulong
- GDMonoClass *class_float; // float
- GDMonoClass *class_double; // double
- GDMonoClass *class_String; // string
- GDMonoClass *class_IntPtr; // System.IntPtr
-
- GDMonoClass *class_System_Collections_IEnumerable;
- GDMonoClass *class_System_Collections_ICollection;
- GDMonoClass *class_System_Collections_IDictionary;
+ GDMonoClass *class_MonoObject = nullptr; // object
+ GDMonoClass *class_bool = nullptr; // bool
+ GDMonoClass *class_int8_t = nullptr; // sbyte
+ GDMonoClass *class_int16_t = nullptr; // short
+ GDMonoClass *class_int32_t = nullptr; // int
+ GDMonoClass *class_int64_t = nullptr; // long
+ GDMonoClass *class_uint8_t = nullptr; // byte
+ GDMonoClass *class_uint16_t = nullptr; // ushort
+ GDMonoClass *class_uint32_t = nullptr; // uint
+ GDMonoClass *class_uint64_t = nullptr; // ulong
+ GDMonoClass *class_float = nullptr; // float
+ GDMonoClass *class_double = nullptr; // double
+ GDMonoClass *class_String = nullptr; // string
+ GDMonoClass *class_IntPtr = nullptr; // System.IntPtr
+
+ GDMonoClass *class_System_Collections_IEnumerable = nullptr;
+ GDMonoClass *class_System_Collections_ICollection = nullptr;
+ GDMonoClass *class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_System_Diagnostics_StackTrace;
+ GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
#endif
- GDMonoClass *class_KeyNotFoundException;
+ GDMonoClass *class_KeyNotFoundException = nullptr;
- MonoClass *rawclass_Dictionary;
+ MonoClass *rawclass_Dictionary = nullptr;
// -----------------------------------------------
- GDMonoClass *class_Vector2;
- GDMonoClass *class_Vector2i;
- GDMonoClass *class_Rect2;
- GDMonoClass *class_Rect2i;
- GDMonoClass *class_Transform2D;
- GDMonoClass *class_Vector3;
- GDMonoClass *class_Vector3i;
- GDMonoClass *class_Basis;
- GDMonoClass *class_Quaternion;
- GDMonoClass *class_Transform3D;
- GDMonoClass *class_AABB;
- GDMonoClass *class_Color;
- GDMonoClass *class_Plane;
- GDMonoClass *class_StringName;
- GDMonoClass *class_NodePath;
- GDMonoClass *class_RID;
- GDMonoClass *class_GodotObject;
- GDMonoClass *class_GodotResource;
- GDMonoClass *class_Node;
- GDMonoClass *class_Control;
- GDMonoClass *class_Node3D;
- GDMonoClass *class_WeakRef;
- GDMonoClass *class_Callable;
- GDMonoClass *class_SignalInfo;
- GDMonoClass *class_Array;
- GDMonoClass *class_Dictionary;
- GDMonoClass *class_MarshalUtils;
- GDMonoClass *class_ISerializationListener;
+ GDMonoClass *class_Vector2 = nullptr;
+ GDMonoClass *class_Vector2i = nullptr;
+ GDMonoClass *class_Rect2 = nullptr;
+ GDMonoClass *class_Rect2i = nullptr;
+ GDMonoClass *class_Transform2D = nullptr;
+ GDMonoClass *class_Vector3 = nullptr;
+ GDMonoClass *class_Vector3i = nullptr;
+ GDMonoClass *class_Vector4 = nullptr;
+ GDMonoClass *class_Vector4i = nullptr;
+ GDMonoClass *class_Basis = nullptr;
+ GDMonoClass *class_Quaternion = nullptr;
+ GDMonoClass *class_Transform3D = nullptr;
+ GDMonoClass *class_Projection = nullptr;
+ GDMonoClass *class_AABB = nullptr;
+ GDMonoClass *class_Color = nullptr;
+ GDMonoClass *class_Plane = nullptr;
+ GDMonoClass *class_StringName = nullptr;
+ GDMonoClass *class_NodePath = nullptr;
+ GDMonoClass *class_RID = nullptr;
+ GDMonoClass *class_GodotObject = nullptr;
+ GDMonoClass *class_GodotResource = nullptr;
+ GDMonoClass *class_Node = nullptr;
+ GDMonoClass *class_Control = nullptr;
+ GDMonoClass *class_Node3D = nullptr;
+ GDMonoClass *class_WeakRef = nullptr;
+ GDMonoClass *class_Callable = nullptr;
+ GDMonoClass *class_SignalInfo = nullptr;
+ GDMonoClass *class_Array = nullptr;
+ GDMonoClass *class_Dictionary = nullptr;
+ GDMonoClass *class_MarshalUtils = nullptr;
+ GDMonoClass *class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_DebuggingUtils;
+ GDMonoClass *class_DebuggingUtils = nullptr;
GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
#endif
- GDMonoClass *class_ExportAttribute;
- GDMonoField *field_ExportAttribute_hint;
- GDMonoField *field_ExportAttribute_hintString;
- GDMonoClass *class_SignalAttribute;
- GDMonoClass *class_ToolAttribute;
- GDMonoClass *class_AnyPeerAttribute;
- GDMonoClass *class_AuthorityAttribute;
- GDMonoClass *class_GodotMethodAttribute;
- GDMonoField *field_GodotMethodAttribute_methodName;
- GDMonoClass *class_ScriptPathAttribute;
- GDMonoField *field_ScriptPathAttribute_path;
- GDMonoClass *class_AssemblyHasScriptsAttribute;
- GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup;
- GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes;
-
- GDMonoField *field_GodotObject_ptr;
- GDMonoField *field_StringName_ptr;
- GDMonoField *field_NodePath_ptr;
- GDMonoField *field_Image_ptr;
- GDMonoField *field_RID_ptr;
+ GDMonoClass *class_ExportAttribute = nullptr;
+ GDMonoField *field_ExportAttribute_hint = nullptr;
+ GDMonoField *field_ExportAttribute_hintString = nullptr;
+ GDMonoClass *class_SignalAttribute = nullptr;
+ GDMonoClass *class_ToolAttribute = nullptr;
+ GDMonoClass *class_RPCAttribute = nullptr;
+ GDMonoProperty *property_RPCAttribute_Mode = nullptr;
+ GDMonoProperty *property_RPCAttribute_CallLocal = nullptr;
+ GDMonoProperty *property_RPCAttribute_TransferMode = nullptr;
+ GDMonoProperty *property_RPCAttribute_TransferChannel = nullptr;
+ GDMonoClass *class_GodotMethodAttribute = nullptr;
+ GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
+ GDMonoClass *class_ScriptPathAttribute = nullptr;
+ GDMonoField *field_ScriptPathAttribute_path = nullptr;
+ GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
+
+ GDMonoField *field_GodotObject_ptr = nullptr;
+ GDMonoField *field_StringName_ptr = nullptr;
+ GDMonoField *field_NodePath_ptr = nullptr;
+ GDMonoField *field_Image_ptr = nullptr;
+ GDMonoField *field_RID_ptr = nullptr;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
@@ -147,6 +153,7 @@ struct CachedData {
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
+ GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 89c37e087b..51c5aa3542 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -194,7 +194,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
#ifdef DEBUG_ENABLED
// For debug builds, we also fetched from native base classes as well before if this is not a native base class.
- // This allows us to warn the user here if he is using snake_case by mistake.
+ // This allows us to warn the user here if they are using snake_case by mistake.
if (p_native_base != this) {
GDMonoClass *native_top = p_native_base;
@@ -247,7 +247,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
if (existing_method) {
memdelete(*existing_method); // Must delete old one
}
- methods.set(key, method);
+ methods.insert(key, method);
break;
}
@@ -266,11 +266,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
ERR_FAIL_COND_V(!methods_fetched, nullptr);
- const MethodKey *k = nullptr;
-
- while ((k = methods.next(k))) {
- if (k->name == p_name) {
- return methods.get(*k);
+ for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+ if (E.key.name == p_name) {
+ return E.value;
}
}
@@ -307,7 +305,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_param
if (raw_method) {
GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
- methods.set(key, method);
+ methods.insert(key, method);
return method;
}
@@ -342,7 +340,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
}
GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
- methods.set(key, method);
+ methods.insert(key, method);
return method;
}
@@ -362,10 +360,10 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo
}
GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
- Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);
+ HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name);
if (result) {
- return result->value();
+ return result->value;
}
if (fields_fetched) {
@@ -394,10 +392,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
StringName name = String::utf8(mono_field_get_name(raw_field));
- Map<StringName, GDMonoField *>::Element *match = fields.find(name);
+ HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name);
if (match) {
- fields_list.push_back(match->get());
+ fields_list.push_back(match->value);
} else {
GDMonoField *field = memnew(GDMonoField(raw_field, this));
fields.insert(name, field);
@@ -411,10 +409,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
}
GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
- Map<StringName, GDMonoProperty *>::Element *result = properties.find(p_name);
+ HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name);
if (result) {
- return result->value();
+ return result->value;
}
if (properties_fetched) {
@@ -443,10 +441,10 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
StringName name = String::utf8(mono_property_get_name(raw_property));
- Map<StringName, GDMonoProperty *>::Element *match = properties.find(name);
+ HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name);
if (match) {
- properties_list.push_back(match->get());
+ properties_list.push_back(match->value);
} else {
GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
properties.insert(name, property);
@@ -479,10 +477,10 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
if (mono_class_is_delegate(raw_class)) {
StringName name = String::utf8(mono_class_get_name(raw_class));
- Map<StringName, GDMonoClass *>::Element *match = delegates.find(name);
+ HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name);
if (match) {
- delegates_list.push_back(match->get());
+ delegates_list.push_back(match->value);
} else {
GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly));
delegates.insert(name, delegate);
@@ -549,9 +547,8 @@ GDMonoClass::~GDMonoClass() {
Vector<GDMonoMethod *> deleted_methods;
deleted_methods.resize(methods.size());
- const MethodKey *k = nullptr;
- while ((k = methods.next(k))) {
- GDMonoMethod *method = methods.get(*k);
+ for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+ GDMonoMethod *method = E.value;
if (method) {
for (int i = 0; i < offset; i++) {
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index bfb5797d4b..6b35da30f9 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -32,7 +32,7 @@
#define GD_MONO_CLASS_H
#include "core/string/ustring.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "gd_mono_field.h"
#include "gd_mono_header.h"
@@ -70,11 +70,11 @@ class GDMonoClass {
StringName namespace_name;
StringName class_name;
- MonoClass *mono_class;
- GDMonoAssembly *assembly;
+ MonoClass *mono_class = nullptr;
+ GDMonoAssembly *assembly = nullptr;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
// This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
// Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
@@ -85,15 +85,15 @@ class GDMonoClass {
Vector<GDMonoMethod *> method_list;
bool fields_fetched;
- Map<StringName, GDMonoField *> fields;
+ HashMap<StringName, GDMonoField *> fields;
Vector<GDMonoField *> fields_list;
bool properties_fetched;
- Map<StringName, GDMonoProperty *> properties;
+ HashMap<StringName, GDMonoProperty *> properties;
Vector<GDMonoProperty *> properties_list;
bool delegates_fetched;
- Map<StringName, GDMonoClass *> delegates;
+ HashMap<StringName, GDMonoClass *> delegates;
Vector<GDMonoClass *> delegates_list;
friend class GDMonoAssembly;
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 333a06c94a..cb025fc67a 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -140,6 +140,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (tclass == CACHED_CLASS(Vector4)) {
+ GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
+ mono_field_set_value(p_object, mono_field, &from);
+ break;
+ }
+
+ if (tclass == CACHED_CLASS(Vector4i)) {
+ GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
+ mono_field_set_value(p_object, mono_field, &from);
+ break;
+ }
+
if (tclass == CACHED_CLASS(Basis)) {
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
mono_field_set_value(p_object, mono_field, &from);
@@ -158,6 +170,12 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (tclass == CACHED_CLASS(Projection)) {
+ GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
+ mono_field_set_value(p_object, mono_field, &from);
+ break;
+ }
+
if (tclass == CACHED_CLASS(AABB)) {
GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
mono_field_set_value(p_object, mono_field, &from);
@@ -328,6 +346,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
mono_field_set_value(p_object, mono_field, &from);
} break;
+ case Variant::VECTOR4: {
+ GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
+ mono_field_set_value(p_object, mono_field, &from);
+ } break;
+ case Variant::VECTOR4I: {
+ GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
+ mono_field_set_value(p_object, mono_field, &from);
+ } break;
case Variant::TRANSFORM2D: {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
mono_field_set_value(p_object, mono_field, &from);
@@ -352,6 +378,10 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
mono_field_set_value(p_object, mono_field, &from);
} break;
+ case Variant::PROJECTION: {
+ GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
+ mono_field_set_value(p_object, mono_field, &from);
+ } break;
case Variant::COLOR: {
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
mono_field_set_value(p_object, mono_field, &from);
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index abcdef378c..1d30f7a369 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -28,22 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GDMONOFIELD_H
-#define GDMONOFIELD_H
+#ifndef GD_MONO_FIELD_H
+#define GD_MONO_FIELD_H
#include "gd_mono.h"
#include "gd_mono_header.h"
#include "i_mono_class_member.h"
class GDMonoField : public IMonoClassMember {
- GDMonoClass *owner;
- MonoClassField *mono_field;
+ GDMonoClass *owner = nullptr;
+ MonoClassField *mono_field = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final { return owner; }
@@ -75,4 +75,4 @@ public:
~GDMonoField();
};
-#endif // GDMONOFIELD_H
+#endif // GD_MONO_FIELD_H
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 01a6521876..6ea3c5539e 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -77,23 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha
}
void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- FileAccess *f = GDMonoLog::get_singleton()->log_file;
-
if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
String text = make_text(log_domain, log_level, message);
text += "\n";
- f->seek_end();
- f->store_string(text);
+ 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
- f->flush();
- f->close();
- memdelete(f);
+ GDMonoLog::get_singleton()->log_file->flush();
+ GDMonoLog::get_singleton()->log_file.unref();
abort();
}
@@ -101,8 +98,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level,
bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
if (!DirAccess::exists(p_logs_dir)) {
- DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!diraccess, false);
+ 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.");
}
@@ -113,8 +110,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
static const uint64_t MAX_SECS = 5 * 86400; // 5 days
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND(!da);
+ 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 + "'.");
@@ -170,7 +167,7 @@ void GDMonoLog::initialize() {
log_file_path = logs_dir.plus_file(log_file_name);
log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
- if (!log_file) {
+ if (log_file.is_null()) {
ERR_PRINT("Mono: Cannot create log file at: " + log_file_path);
}
}
@@ -178,7 +175,7 @@ void GDMonoLog::initialize() {
mono_trace_set_level_string(log_level.get_data());
log_level_id = get_log_level_id(log_level.get_data());
- if (log_file) {
+ 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 {
@@ -192,11 +189,6 @@ GDMonoLog::GDMonoLog() {
GDMonoLog::~GDMonoLog() {
singleton = nullptr;
-
- if (log_file) {
- log_file->close();
- memdelete(log_file);
- }
}
#else
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 9aa67a09e2..93ba6a410e 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -35,7 +35,7 @@
#include "core/typedefs.h"
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED)
+#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
// We have custom mono log callbacks for WASM and iOS
#define GD_MONO_LOG_ENABLED
#endif
@@ -48,7 +48,7 @@ class GDMonoLog {
#ifdef GD_MONO_LOG_ENABLED
int log_level_id = -1;
- FileAccess *log_file = nullptr;
+ Ref<FileAccess> log_file;
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 957abca37b..a860442764 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -99,6 +99,13 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
if (vtclass == CACHED_CLASS(Vector3i)) {
return Variant::VECTOR3I;
}
+ if (vtclass == CACHED_CLASS(Vector4)) {
+ return Variant::VECTOR4;
+ }
+
+ if (vtclass == CACHED_CLASS(Vector4i)) {
+ return Variant::VECTOR4I;
+ }
if (vtclass == CACHED_CLASS(Basis)) {
return Variant::BASIS;
@@ -111,7 +118,9 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
if (vtclass == CACHED_CLASS(Transform3D)) {
return Variant::TRANSFORM3D;
}
-
+ if (vtclass == CACHED_CLASS(Projection)) {
+ return Variant::PROJECTION;
+ }
if (vtclass == CACHED_CLASS(AABB)) {
return Variant::AABB;
}
@@ -539,6 +548,14 @@ MonoObject *variant_to_mono_object(const Variant &p_var) {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
}
+ case Variant::VECTOR4: {
+ GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_var.operator ::Vector4());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4), &from);
+ }
+ case Variant::VECTOR4I: {
+ GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_var.operator ::Vector4i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4i), &from);
+ }
case Variant::PLANE: {
GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
@@ -559,6 +576,10 @@ MonoObject *variant_to_mono_object(const Variant &p_var) {
GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from);
}
+ case Variant::PROJECTION: {
+ GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_var.operator ::Projection());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Projection), &from);
+ }
case Variant::COLOR: {
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 20d4743e5c..51f11ab18a 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GDMONOMARSHAL_H
-#define GDMONOMARSHAL_H
+#ifndef GD_MONO_MARSHAL_H
+#define GD_MONO_MARSHAL_H
#include "core/variant/variant.h"
@@ -196,14 +196,14 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
#pragma pack(push, 1)
struct M_Callable {
- MonoObject *target;
- MonoObject *method_string_name;
- MonoDelegate *delegate;
+ MonoObject *target = nullptr;
+ MonoObject *method_string_name = nullptr;
+ MonoDelegate *delegate = nullptr;
};
struct M_SignalInfo {
- MonoObject *owner;
- MonoObject *name_string_name;
+ MonoObject *owner = nullptr;
+ MonoObject *name_string_name = nullptr;
};
#pragma pack(pop)
@@ -256,6 +256,18 @@ enum {
offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
offsetof(Vector3, z) == (sizeof(real_t) * 2)),
+ MATCHES_Vector4 = (MATCHES_real_t && (sizeof(Vector4) == (sizeof(real_t) * 4)) &&
+ offsetof(Vector4, x) == (sizeof(real_t) * 0) &&
+ offsetof(Vector4, y) == (sizeof(real_t) * 1) &&
+ offsetof(Vector4, z) == (sizeof(real_t) * 2) &&
+ offsetof(Vector4, w) == (sizeof(real_t) * 3)),
+
+ MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4)) &&
+ offsetof(Vector4i, x) == (sizeof(int32_t) * 0) &&
+ offsetof(Vector4i, y) == (sizeof(int32_t) * 1) &&
+ offsetof(Vector4i, z) == (sizeof(int32_t) * 2) &&
+ offsetof(Vector4i, w) == (sizeof(int32_t) * 3)),
+
MATCHES_Vector3i = (MATCHES_int && (sizeof(Vector3i) == (sizeof(int32_t) * 3)) &&
offsetof(Vector3i, x) == (sizeof(int32_t) * 0) &&
offsetof(Vector3i, y) == (sizeof(int32_t) * 1) &&
@@ -273,6 +285,8 @@ enum {
offsetof(Transform3D, basis) == 0 &&
offsetof(Transform3D, origin) == sizeof(Basis)),
+ MATCHES_Projection = (MATCHES_Vector4 && (sizeof(Projection) == (sizeof(Vector4) * 4))),
+
MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
offsetof(AABB, size) == (sizeof(Vector3) * 1)),
@@ -291,9 +305,9 @@ enum {
// In the future we may force this if we want to ref return these structs
#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
/* clang-format off */
-static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
- MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_AABB && MATCHES_Color &&
- MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i);
+static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && MATCHES_Vector4 &&
+ MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_Projection && MATCHES_AABB && MATCHES_Color &&
+ MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i && MATCHES_Vector4i);
/* clang-format on */
#endif
} // namespace InteropLayout
@@ -367,9 +381,9 @@ struct M_Transform2D {
static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
M_Transform2D ret = {
- M_Vector2::convert_from(p_from.elements[0]),
- M_Vector2::convert_from(p_from.elements[1]),
- M_Vector2::convert_from(p_from.elements[2])
+ M_Vector2::convert_from(p_from.columns[0]),
+ M_Vector2::convert_from(p_from.columns[1]),
+ M_Vector2::convert_from(p_from.columns[2])
};
return ret;
}
@@ -401,6 +415,32 @@ struct M_Vector3i {
}
};
+struct M_Vector4 {
+ real_t x, y, z, w;
+
+ static _FORCE_INLINE_ Vector4 convert_to(const M_Vector4 &p_from) {
+ return Vector4(p_from.x, p_from.y, p_from.z, p_from.w);
+ }
+
+ static _FORCE_INLINE_ M_Vector4 convert_from(const Vector4 &p_from) {
+ M_Vector4 ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+ return ret;
+ }
+};
+
+struct M_Vector4i {
+ int32_t x, y, z, w;
+
+ static _FORCE_INLINE_ Vector4i convert_to(const M_Vector4i &p_from) {
+ return Vector4i(p_from.x, p_from.y, p_from.z, p_from.w);
+ }
+
+ static _FORCE_INLINE_ M_Vector4i convert_from(const Vector4i &p_from) {
+ M_Vector4i ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+ return ret;
+ }
+};
+
struct M_Basis {
M_Vector3 elements[3];
@@ -412,9 +452,9 @@ struct M_Basis {
static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
M_Basis ret = {
- M_Vector3::convert_from(p_from.elements[0]),
- M_Vector3::convert_from(p_from.elements[1]),
- M_Vector3::convert_from(p_from.elements[2])
+ M_Vector3::convert_from(p_from.rows[0]),
+ M_Vector3::convert_from(p_from.rows[1]),
+ M_Vector3::convert_from(p_from.rows[2])
};
return ret;
}
@@ -447,6 +487,22 @@ struct M_Transform3D {
}
};
+struct M_Projection {
+ M_Vector4 vec1;
+ M_Vector4 vec2;
+ M_Vector4 vec3;
+ M_Vector4 vec4;
+
+ static _FORCE_INLINE_ Projection convert_to(const M_Projection &p_from) {
+ return Projection(M_Vector4::convert_to(p_from.vec1), M_Vector4::convert_to(p_from.vec2), M_Vector4::convert_to(p_from.vec3), M_Vector4::convert_to(p_from.vec4));
+ }
+
+ static _FORCE_INLINE_ M_Projection convert_from(const Projection &p_from) {
+ M_Projection ret = { M_Vector4::convert_from(p_from.matrix[0]), M_Vector4::convert_from(p_from.matrix[1]), M_Vector4::convert_from(p_from.matrix[2]), M_Vector4::convert_from(p_from.matrix[3]) };
+ return ret;
+ }
+};
+
struct M_AABB {
M_Vector3 position;
M_Vector3 size;
@@ -533,8 +589,11 @@ DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
DECL_TYPE_MARSHAL_TEMPLATES(Vector3i)
DECL_TYPE_MARSHAL_TEMPLATES(Basis)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector4)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector4i)
DECL_TYPE_MARSHAL_TEMPLATES(Quaternion)
DECL_TYPE_MARSHAL_TEMPLATES(Transform3D)
+DECL_TYPE_MARSHAL_TEMPLATES(Projection)
DECL_TYPE_MARSHAL_TEMPLATES(AABB)
DECL_TYPE_MARSHAL_TEMPLATES(Color)
DECL_TYPE_MARSHAL_TEMPLATES(Plane)
@@ -543,4 +602,4 @@ DECL_TYPE_MARSHAL_TEMPLATES(Plane)
#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
} // namespace GDMonoMarshal
-#endif // GDMONOMARSHAL_H
+#endif // GD_MONO_MARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 6e87a60ee2..be11ef5bfe 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -54,7 +54,7 @@ class GDMonoMethod : public IMonoClassMember {
friend class GDMonoClass;
- MonoMethod *mono_method;
+ MonoMethod *mono_method = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final;
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
index bb163b89bc..0180dee3ea 100644
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ b/modules/mono/mono_gd/gd_mono_method_thunk.h
@@ -39,7 +39,7 @@
#include "gd_mono_method.h"
#include "gd_mono_utils.h"
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED)
+#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
#define HAVE_METHOD_THUNKS
#endif
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 003bcf05e1..6fc681aeb5 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -36,14 +36,14 @@
#include "i_mono_class_member.h"
class GDMonoProperty : public IMonoClassMember {
- GDMonoClass *owner;
- MonoProperty *mono_property;
+ GDMonoClass *owner = nullptr;
+ MonoProperty *mono_property = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
unsigned int param_buffer_size;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index a884bf4da0..1983d6ebe2 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -70,7 +70,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
void *data = CSharpLanguage::get_instance_binding(unmanaged);
ERR_FAIL_NULL_V(data, nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
ERR_FAIL_COND_V(!script_binding.inited, nullptr);
MonoGCHandleData &gchandle = script_binding.gchandle;
@@ -614,6 +614,14 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
return (bool)res;
}
+bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
+ NO_GLUE_RET(false);
+ MonoException *exc = nullptr;
+ MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
+}
+
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 4c2c2c93c2..300cacfa4b 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GD_MONOUTILS_H
-#define GD_MONOUTILS_H
+#ifndef GD_MONO_UTILS_H
+#define GD_MONO_UTILS_H
#include <mono/metadata/threads.h>
@@ -61,6 +61,7 @@ bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
+bool type_has_flags_attribute(MonoReflectionType *p_reftype);
void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
@@ -201,4 +202,4 @@ void add_internal_call(const char *p_name, R (*p_func)(P...)) {
#define GD_MONO_ASSERT_THREAD_ATTACHED ((void)0)
#endif
-#endif // GD_MONOUTILS_H
+#endif // GD_MONO_UTILS_H
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
index 68299aa984..83e2750e5a 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -47,11 +47,11 @@ struct Mono_InterpMethodArguments {
size_t ilen;
void **iargs;
size_t flen;
- double *fargs;
+ double *fargs = nullptr;
void **retval;
size_t is_float_ret;
//#ifdef TARGET_WASM
- void *sig;
+ void *sig = nullptr;
//#endif
};
} // extern "C"
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index eb8bbab948..4797d5dae1 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -134,8 +134,9 @@ String determine_app_native_lib_dir() {
}
String get_app_native_lib_dir() {
- if (app_native_lib_dir_cache.is_empty())
+ if (app_native_lib_dir_cache.is_empty()) {
app_native_lib_dir_cache = determine_app_native_lib_dir();
+ }
return app_native_lib_dir_cache;
}
@@ -144,10 +145,11 @@ int gd_mono_convert_dl_flags(int flags) {
int lflags = flags & MONO_DL_LOCAL ? 0 : RTLD_GLOBAL;
- if (flags & MONO_DL_LAZY)
+ if (flags & MONO_DL_LAZY) {
lflags |= RTLD_LAZY;
- else
+ } else {
lflags |= RTLD_NOW;
+ }
return lflags;
}
@@ -164,8 +166,9 @@ void *godot_dl_handle = nullptr;
void *try_dlopen(const String &p_so_path, int p_flags) {
if (!FileAccess::exists(p_so_path)) {
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data());
+ }
return nullptr;
}
@@ -174,13 +177,15 @@ void *try_dlopen(const String &p_so_path, int p_flags) {
void *handle = dlopen(p_so_path.utf8().get_data(), lflags);
if (!handle) {
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror());
+ }
return nullptr;
}
- if (OS::get_singleton()->is_stdout_verbose())
+ if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data());
+ }
return handle;
}
@@ -217,20 +222,23 @@ void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void
void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) {
void *sym_addr = dlsym(p_handle, p_name);
- if (sym_addr)
+ if (sym_addr) {
return sym_addr;
+ }
if (p_handle == mono_dl_handle && godot_dl_handle) {
// Looking up for '__Internal' P/Invoke. We want to search in both the Mono and Godot shared libraries.
// This is needed to resolve the monodroid P/Invoke functions that are defined at the bottom of the file.
sym_addr = dlsym(godot_dl_handle, p_name);
- if (sym_addr)
+ if (sym_addr) {
return sym_addr;
+ }
}
- if (r_err)
+ if (r_err) {
*r_err = str_format_new("%s\n", dlerror());
+ }
return nullptr;
}
@@ -239,8 +247,9 @@ void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) {
dlclose(p_handle);
// Not sure if this ever happens. Does Mono close the handle for the main module?
- if (p_handle == mono_dl_handle)
+ if (p_handle == mono_dl_handle) {
mono_dl_handle = nullptr;
+ }
return nullptr;
}
@@ -292,13 +301,15 @@ MonoBoolean _gd_mono_init_cert_store() {
ScopedLocalRef<jobject> certStoreLocal(env, env->CallStaticObjectMethod(keyStoreClass, getInstance, androidCAStoreString.get()));
- if (jni_exception_check(env))
+ if (jni_exception_check(env)) {
return 0;
+ }
env->CallVoidMethod(certStoreLocal, load, nullptr);
- if (jni_exception_check(env))
+ if (jni_exception_check(env)) {
return 0;
+ }
certStore = env->NewGlobalRef(certStoreLocal);
@@ -309,8 +320,9 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
// The JNI code is the equivalent of:
//
// Certificate certificate = certStore.getCertificate(alias);
- // if (certificate == null)
+ // if (certificate == null) {
// return null;
+ // }
// return certificate.getEncoded();
MonoError mono_error;
@@ -340,8 +352,9 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
ScopedLocalRef<jobject> certificate(env, env->CallObjectMethod(certStore, getCertificate, js_alias.get()));
- if (!certificate)
+ if (!certificate) {
return nullptr;
+ }
ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded));
jsize encodedLength = env->GetArrayLength(encoded);
@@ -374,11 +387,13 @@ void initialize() {
void cleanup() {
// This is called after shutting down the Mono runtime
- if (mono_dl_handle)
+ if (mono_dl_handle) {
gd_mono_android_dlclose(mono_dl_handle, nullptr);
+ }
- if (godot_dl_handle)
+ if (godot_dl_handle) {
gd_mono_android_dlclose(godot_dl_handle, nullptr);
+ }
JNIEnv *env = get_jni_env();
@@ -431,8 +446,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char
//
// NetworkInterface.getByName(p_ifname).isUp()
- if (!r_is_up || !p_ifname || strlen(p_ifname) == 0)
+ if (!r_is_up || !p_ifname || strlen(p_ifname) == 0) {
return 0;
+ }
*r_is_up = 0;
@@ -450,8 +466,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char
ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
- if (!networkInterface)
+ if (!networkInterface) {
return 0;
+ }
*r_is_up = (mono_bool)env->CallBooleanMethod(networkInterface, isUp);
@@ -463,8 +480,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast(
//
// NetworkInterface.getByName(p_ifname).supportsMulticast()
- if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0)
+ if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0) {
return 0;
+ }
*r_supports_multicast = 0;
@@ -482,8 +500,9 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast(
ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
- if (!networkInterface)
+ if (!networkInterface) {
return 0;
+ }
*r_supports_multicast = (mono_bool)env->CallBooleanMethod(networkInterface, supportsMulticast);
@@ -528,8 +547,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
ScopedLocalRef<jobject> connectivityManager(env, env->CallObjectMethod(applicationContext, getSystemService, connectivityServiceString.get()));
- if (!connectivityManager)
+ if (!connectivityManager) {
return;
+ }
ScopedLocalRef<jclass> connectivityManagerClass(env, env->FindClass("android/net/ConnectivityManager"));
ERR_FAIL_NULL(connectivityManagerClass);
@@ -539,8 +559,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
ScopedLocalRef<jobject> activeNetwork(env, env->CallObjectMethod(connectivityManager, getActiveNetwork));
- if (!activeNetwork)
+ if (!activeNetwork) {
return;
+ }
jmethodID getLinkProperties = env->GetMethodID(connectivityManagerClass,
"getLinkProperties", "(Landroid/net/Network;)Landroid/net/LinkProperties;");
@@ -548,8 +569,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
ScopedLocalRef<jobject> linkProperties(env, env->CallObjectMethod(connectivityManager, getLinkProperties, activeNetwork.get()));
- if (!linkProperties)
+ if (!linkProperties) {
return;
+ }
ScopedLocalRef<jclass> linkPropertiesClass(env, env->FindClass("android/net/LinkProperties"));
ERR_FAIL_NULL(linkPropertiesClass);
@@ -559,8 +581,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
ScopedLocalRef<jobject> dnsServers(env, env->CallObjectMethod(linkProperties, getDnsServers));
- if (!dnsServers)
+ if (!dnsServers) {
return;
+ }
ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List"));
ERR_FAIL_NULL(listClass);
@@ -570,11 +593,13 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
int dnsServersCount = env->CallIntMethod(dnsServers, listSize);
- if (dnsServersCount > dns_servers_len)
+ if (dnsServersCount > dns_servers_len) {
dnsServersCount = dns_servers_len;
+ }
- if (dnsServersCount <= 0)
+ if (dnsServersCount <= 0) {
return;
+ }
jmethodID listGet = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;");
ERR_FAIL_NULL(listGet);
@@ -587,8 +612,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
for (int i = 0; i < dnsServersCount; i++) {
ScopedLocalRef<jobject> dnsServer(env, env->CallObjectMethod(dnsServers, listGet, (jint)i));
- if (!dnsServer)
+ if (!dnsServer) {
continue;
+ }
ScopedLocalRef<jstring> hostAddress(env, (jstring)env->CallObjectMethod(dnsServer, getHostAddress));
const char *host_address = env->GetStringUTFChars(hostAddress, 0);
@@ -603,8 +629,9 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn
}
GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array) {
- if (!r_dns_servers_array)
+ if (!r_dns_servers_array) {
return -1;
+ }
*r_dns_servers_array = nullptr;
@@ -661,13 +688,15 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() {
ScopedLocalRef<jobject> defaultTimeZone(env, env->CallStaticObjectMethod(timeZoneClass, getDefault));
- if (!defaultTimeZone)
+ if (!defaultTimeZone) {
return nullptr;
+ }
ScopedLocalRef<jstring> defaultTimeZoneID(env, (jstring)env->CallObjectMethod(defaultTimeZone, getID));
- if (!defaultTimeZoneID)
+ if (!defaultTimeZoneID) {
return nullptr;
+ }
const char *default_time_zone_id = env->GetStringUTFChars(defaultTimeZoneID, 0);
diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h
index 2f444d5089..03e86df698 100644
--- a/modules/mono/mono_gd/support/ios_support.h
+++ b/modules/mono/mono_gd/support/ios_support.h
@@ -31,7 +31,7 @@
#ifndef IOS_SUPPORT_H
#define IOS_SUPPORT_H
-#if defined(IPHONE_ENABLED)
+#if defined(IOS_ENABLED)
#include "core/string/ustring.h"
@@ -45,6 +45,6 @@ void cleanup();
} // namespace ios
} // namespace gdmono
-#endif // IPHONE_ENABLED
+#endif // IOS_ENABLED
#endif // IOS_SUPPORT_H
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
index e66b88db32..7c941b9d1e 100644
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -30,7 +30,7 @@
#include "ios_support.h"
-#if defined(IPHONE_ENABLED)
+#if defined(IOS_ENABLED)
#import <Foundation/Foundation.h>
#include <os/log.h>
@@ -94,8 +94,9 @@ GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) {
int length = 0;
const uint16_t *ptr = p_unicode_message;
- while (*ptr++)
+ while (*ptr++) {
length += sizeof(uint16_t);
+ }
NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding];
os_log_info(OS_LOG_DEFAULT, "%{public}@", msg);
@@ -146,4 +147,4 @@ GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) {
os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'");
}
-#endif // IPHONE_ENABLED
+#endif // IOS_ENABLED
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 531a4bb11f..755e1f7a30 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -40,7 +40,11 @@ Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
mono_bind::GodotSharp *_godotsharp = nullptr;
-void register_mono_types() {
+void initialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(CSharpScript);
_godotsharp = memnew(mono_bind::GodotSharp);
@@ -59,7 +63,11 @@ void register_mono_types() {
ResourceSaver::add_resource_format_saver(resource_saver_cs);
}
-void unregister_mono_types() {
+void uninitialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ScriptServer::unregister_language(script_language_cs);
if (script_language_cs) {
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index 12f7e36f02..bc2690c277 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -31,7 +31,9 @@
#ifndef MONO_REGISTER_TYPES_H
#define MONO_REGISTER_TYPES_H
-void register_mono_types();
-void unregister_mono_types();
+#include "modules/register_module_types.h"
+
+void initialize_mono_module(ModuleInitializationLevel p_level);
+void uninitialize_mono_module(ModuleInitializationLevel p_level);
#endif // MONO_REGISTER_TYPES_H
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 315a9c29f6..437c4ca54a 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -44,7 +44,7 @@ Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signa
SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, p_awaiter, p_signal));
Callable callable = Callable(awaiter_callable);
- return p_source->connect(p_signal, callable, Vector<Variant>(), Object::CONNECT_ONESHOT);
+ return p_source->connect(p_signal, callable, Object::CONNECT_ONESHOT);
}
bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -63,7 +63,7 @@ bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const Callab
uint32_t SignalAwaiterCallable::hash() const {
uint32_t hash = signal.hash();
- return hash_djb2_one_64(target_id, hash);
+ return hash_murmur3_one_64(target_id, hash);
}
String SignalAwaiterCallable::get_as_text() const {
@@ -164,7 +164,7 @@ bool EventSignalCallable::compare_less(const CallableCustom *p_a, const Callable
uint32_t EventSignalCallable::hash() const {
uint32_t hash = event_signal->field->get_name().hash();
- return hash_djb2_one_64(owner->get_instance_id(), hash);
+ return hash_murmur3_one_64(owner->get_instance_id(), hash);
}
String EventSignalCallable::get_as_text() const {
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 1a62f36625..532aa3e327 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -68,7 +68,7 @@ public:
};
class EventSignalCallable : public CallableCustom {
- Object *owner;
+ Object *owner = nullptr;
const CSharpScript::EventSignal *event_signal;
public:
diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/macos_utils.cpp
index 835c611709..cd4f7a827e 100644
--- a/modules/mono/utils/osx_utils.cpp
+++ b/modules/mono/utils/macos_utils.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* osx_utils.cpp */
+/* macos_utils.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "osx_utils.h"
+#include "macos_utils.h"
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
#include "core/string/print_string.h"
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <CoreServices/CoreServices.h>
-bool osx_is_app_bundle_installed(const String &p_bundle_id) {
+bool macos_is_app_bundle_installed(const String &p_bundle_id) {
CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8);
CFArrayRef result = LSCopyApplicationURLsForBundleIdentifier(bundle_id, nullptr);
CFRelease(bundle_id);
diff --git a/modules/mono/utils/osx_utils.h b/modules/mono/utils/macos_utils.h
index 2f6c6dad51..ca4957f5a7 100644
--- a/modules/mono/utils/osx_utils.h
+++ b/modules/mono/utils/macos_utils.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* osx_utils.h */
+/* macos_utils.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,13 +30,13 @@
#include "core/string/ustring.h"
-#ifndef OSX_UTILS_H
-#define OSX_UTILS_H
+#ifndef MONO_MACOS_UTILS_H
+#define MONO_MACOS_UTILS_H
-#ifdef OSX_ENABLED
+#ifdef MACOS_ENABLED
-bool osx_is_app_bundle_installed(const String &p_bundle_id);
+bool macos_is_app_bundle_installed(const String &p_bundle_id);
#endif
-#endif // OSX_UTILS_H
+#endif // MONO_MACOS_UTILS_H
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index 2ca1a4cbf1..b7bd9a2495 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef UTIL_MACROS_H
-#define UTIL_MACROS_H
+#ifndef MONO_MACROS_H
+#define MONO_MACROS_H
#define _GD_VARNAME_CONCAT_B_(m_ignore, m_name) m_name
#define _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B_(hello there, m_a##m_b##m_c)
@@ -69,4 +69,4 @@ public:
#define SCOPE_EXIT \
auto GD_UNIQUE_NAME(gd_scope_exit) = gdmono::ScopeExitAux() + [=]() -> void
-#endif // UTIL_MACROS_H
+#endif // MONO_MACROS_H
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index f388661207..8e37e6943c 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -60,8 +60,9 @@ REGSAM _get_bitness_sam() {
LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) {
LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult);
+ }
return res;
}
@@ -92,31 +93,37 @@ LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_r
HKEY hKey;
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
if (!p_old_reg) {
res = _RegKeyQueryString(hKey, "Version", r_info.version);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
}
res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
- if (r_info.install_root_dir.ends_with("\\"))
+ if (r_info.install_root_dir.ends_with("\\")) {
r_info.bin_dir = r_info.install_root_dir + "bin";
- else
+ } else {
r_info.bin_dir = r_info.install_root_dir + "\\bin";
+ }
cleanup:
RegCloseKey(hKey);
@@ -129,8 +136,9 @@ LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
HKEY hKey;
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr);
@@ -147,11 +155,13 @@ cleanup:
MonoRegInfo find_mono() {
MonoRegInfo info;
- if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS)
+ if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS) {
return info;
+ }
- if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS)
+ if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS) {
return info;
+ }
return MonoRegInfo();
}
@@ -212,13 +222,15 @@ String find_msbuild_tools_path() {
HKEY hKey;
LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path);
- if (res != ERROR_SUCCESS)
+ if (res != ERROR_SUCCESS) {
goto cleanup;
+ }
cleanup:
RegCloseKey(hKey);
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 89851fc4d3..a1905dfcfe 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -57,11 +57,13 @@ String cwd() {
Char16String buffer;
buffer.resize((int)expected_size);
- if (::GetCurrentDirectoryW(expected_size, (wchar_t *)buffer.ptrw()) == 0)
+ if (::GetCurrentDirectoryW(expected_size, (wchar_t *)buffer.ptrw()) == 0) {
return ".";
+ }
String result;
- if (result.parse_utf16(buffer.ptr())) {
+ result.parse_utf16(buffer.ptr());
+ if (result.is_empty()) {
return ".";
}
return result.simplify_path();
@@ -72,7 +74,7 @@ String cwd() {
}
String result;
- if (result.parse_utf8(buffer)) {
+ if (result.parse_utf8(buffer) != OK) {
return ".";
}
@@ -95,8 +97,9 @@ String realpath(const String &p_path) {
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
- if (hFile == INVALID_HANDLE_VALUE)
+ if (hFile == INVALID_HANDLE_VALUE) {
return p_path;
+ }
const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED);
@@ -112,7 +115,8 @@ String realpath(const String &p_path) {
::CloseHandle(hFile);
String result;
- if (result.parse_utf16(buffer.ptr())) {
+ result.parse_utf16(buffer.ptr());
+ if (result.is_empty()) {
return p_path;
}
@@ -125,10 +129,10 @@ String realpath(const String &p_path) {
}
String result;
- bool parse_ok = result.parse_utf8(resolved_path);
+ Error parse_ok = result.parse_utf8(resolved_path);
::free(resolved_path);
- if (parse_ok) {
+ if (parse_ok != OK) {
return p_path;
}
@@ -177,8 +181,9 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
#ifdef WINDOWS_ENABLED
String get_drive_letter(const String &p_norm_path) {
int idx = p_norm_path.find(":/");
- if (idx != -1 && idx < p_norm_path.find("/"))
+ if (idx != -1 && idx < p_norm_path.find("/")) {
return p_norm_path.substr(0, idx + 1);
+ }
return String();
}
#endif
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
index a8cd8daf04..9a2c757361 100644
--- a/modules/mono/utils/path_utils.h
+++ b/modules/mono/utils/path_utils.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PATH_UTILS_H
-#define PATH_UTILS_H
+#ifndef MONO_PATH_UTILS_H
+#define MONO_PATH_UTILS_H
#include "core/string/string_builder.h"
#include "core/string/ustring.h"
@@ -58,4 +58,4 @@ String realpath(const String &p_path);
String relative_to(const String &p_path, const String &p_relative_to);
} // namespace path
-#endif // PATH_UTILS_H
+#endif // MONO_PATH_UTILS_H
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index dd29299330..975f2d8332 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -145,7 +145,7 @@ bool is_csharp_keyword(const String &p_name) {
p_name == "do" || p_name == "double" || p_name == "else" || p_name == "enum" ||
p_name == "event" || p_name == "explicit" || p_name == "extern" || p_name == "false" ||
p_name == "finally" || p_name == "fixed" || p_name == "float" || p_name == "for" ||
- p_name == "forech" || p_name == "goto" || p_name == "if" || p_name == "implicit" ||
+ p_name == "foreach" || p_name == "goto" || p_name == "if" || p_name == "implicit" ||
p_name == "in" || p_name == "int" || p_name == "interface" || p_name == "internal" ||
p_name == "is" || p_name == "lock" || p_name == "long" || p_name == "namespace" ||
p_name == "new" || p_name == "null" || p_name == "object" || p_name == "operator" ||
@@ -167,20 +167,18 @@ String escape_csharp_keyword(const String &p_name) {
Error read_all_file_utf8(const String &p_path, String &r_content) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, len);
- f->close();
- memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
w[len] = 0;
String source;
- if (source.parse_utf8((const char *)w)) {
+ if (source.parse_utf8((const char *)w) != OK) {
ERR_FAIL_V(ERR_INVALID_DATA);
}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index d79888716a..fa4c5e89f4 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef STRING_FORMAT_H
-#define STRING_FORMAT_H
+#ifndef MONO_STRING_UTILS_H
+#define MONO_STRING_UTILS_H
#include "core/string/ustring.h"
#include "core/variant/variant.h"
@@ -59,4 +59,4 @@ String str_format(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE
char *str_format_new(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2;
char *str_format_new(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0;
-#endif // STRING_FORMAT_H
+#endif // MONO_STRING_UTILS_H