summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub2
-rw-r--r--core/config/project_settings.cpp28
-rw-r--r--core/config/project_settings.h1
-rw-r--r--core/core_bind.cpp12
-rw-r--r--core/core_bind.h2
-rw-r--r--core/core_builders.py1
-rw-r--r--core/debugger/local_debugger.cpp5
-rw-r--r--core/doc_data.cpp2
-rw-r--r--core/doc_data.h25
-rw-r--r--core/extension/gdextension.cpp40
-rw-r--r--core/extension/gdextension.h3
-rw-r--r--core/extension/gdextension_interface.cpp319
-rw-r--r--core/extension/gdextension_interface.h142
-rw-r--r--core/input/input.cpp93
-rw-r--r--core/input/input.h19
-rw-r--r--core/input/input_event.cpp15
-rw-r--r--core/input/input_event.h2
-rw-r--r--core/input/input_map.cpp4
-rw-r--r--core/io/compression.cpp8
-rw-r--r--core/io/file_access.cpp5
-rw-r--r--core/io/file_access_pack.cpp7
-rw-r--r--core/io/file_access_pack.h5
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/image.cpp254
-rw-r--r--core/io/image.h5
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/ip.h1
-rw-r--r--core/io/json.cpp8
-rw-r--r--core/io/pck_packer.cpp4
-rw-r--r--core/io/resource_format_binary.cpp15
-rw-r--r--core/io/resource_importer.cpp20
-rw-r--r--core/io/resource_loader.cpp26
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/io/xml_parser.cpp2
-rw-r--r--core/io/xml_parser.h2
-rw-r--r--core/math/basis.cpp2
-rw-r--r--core/math/convex_hull.cpp4
-rw-r--r--core/math/delaunay_2d.h2
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/object/make_virtuals.py2
-rw-r--r--core/object/object.cpp32
-rw-r--r--core/object/object.h12
-rw-r--r--core/object/ref_counted.h10
-rw-r--r--core/object/script_language.cpp57
-rw-r--r--core/object/script_language.h19
-rw-r--r--core/object/script_language_extension.h2
-rw-r--r--core/object/undo_redo.cpp28
-rw-r--r--core/object/undo_redo.h7
-rw-r--r--core/object/worker_thread_pool.cpp7
-rw-r--r--core/os/keyboard.cpp29
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.cpp8
-rw-r--r--core/os/main_loop.h4
-rw-r--r--core/os/os.cpp10
-rw-r--r--core/os/threaded_array_processor.h87
-rw-r--r--core/os/time.cpp3
-rw-r--r--core/os/time.h3
-rw-r--r--core/string/ustring.cpp90
-rw-r--r--core/string/ustring.h1
-rw-r--r--core/templates/rid_owner.h3
-rw-r--r--core/variant/callable_bind.cpp22
-rw-r--r--core/variant/callable_bind.h2
-rw-r--r--core/variant/dictionary.cpp11
-rw-r--r--core/variant/method_ptrcall.h10
-rw-r--r--core/variant/native_ptr.h70
-rw-r--r--core/variant/variant.h2
-rw-r--r--core/variant/variant_internal.h4
-rw-r--r--core/variant/variant_op.cpp33
-rw-r--r--core/variant/variant_op.h11
-rw-r--r--core/variant/variant_parser.cpp60
70 files changed, 955 insertions, 781 deletions
diff --git a/core/SCsub b/core/SCsub
index a0176f6c33..7e9cd97351 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -65,7 +65,7 @@ thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_mis
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
# Brotli
-if env["brotli"]:
+if env["brotli"] and env["builtin_brotli"]:
thirdparty_brotli_dir = "#thirdparty/brotli/"
thirdparty_brotli_sources = [
"common/constants.c",
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index cb25dc9ebf..79fab50882 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -67,14 +67,6 @@ String ProjectSettings::get_resource_path() const {
return resource_path;
}
-String ProjectSettings::get_safe_project_name() const {
- String safe_name = OS::get_singleton()->get_safe_dir_name(get("application/config/name"));
- if (safe_name.is_empty()) {
- safe_name = "UnnamedProject";
- }
- return safe_name;
-}
-
String ProjectSettings::get_imported_files_path() const {
return get_project_data_path().path_join("imported");
}
@@ -930,10 +922,26 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
}
Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array?
-
return save_custom(p_file);
}
+#ifdef TOOLS_ENABLED
+bool _csproj_exists(String p_root_dir) {
+ Ref<DirAccess> dir = DirAccess::open(p_root_dir);
+
+ dir->list_dir_begin();
+ String file_name = dir->_get_next();
+ while (file_name != "") {
+ if (!dir->current_is_dir() && file_name.get_extension() == "csproj") {
+ return true;
+ }
+ file_name = dir->_get_next();
+ }
+
+ return false;
+}
+#endif // TOOLS_ENABLED
+
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
@@ -952,7 +960,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
+ if (_csproj_exists(get_resource_path())) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index a0249ef267..b89e6694b0 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -166,7 +166,6 @@ public:
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
- String get_safe_project_name() const;
String get_imported_files_path() const;
static ProjectSettings *get_singleton();
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 8771aa88cc..2d0d24406c 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -39,6 +39,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
+#include "core/os/thread_safe.h"
#include "core/variant/typed_array.h"
namespace core_bind {
@@ -1187,7 +1188,11 @@ void Thread::_start_func(void *ud) {
ERR_FAIL_MSG(vformat("Could not call function '%s' on previously freed instance to start thread %s.", t->target_callable.get_method(), t->get_id()));
}
+ // Finding out a suitable name for the thread can involve querying a node, if the target is one.
+ // We know this is safe (unless the user is causing life cycle race conditions, which would be a bug on their part).
+ set_current_thread_safe_for_nodes(true);
String func_name = t->target_callable.is_custom() ? t->target_callable.get_custom()->get_as_text() : String(t->target_callable.get_method());
+ set_current_thread_safe_for_nodes(false);
::Thread::set_name(func_name);
// To avoid a circular reference between the thread and the script which can possibly contain a reference
@@ -1255,6 +1260,11 @@ Variant Thread::wait_to_finish() {
return r;
}
+void Thread::set_thread_safety_checks_enabled(bool p_enabled) {
+ ERR_FAIL_COND_MSG(::Thread::is_main_thread(), "This call is forbidden on the main thread.");
+ set_current_thread_safe_for_nodes(!p_enabled);
+}
+
void Thread::_bind_methods() {
ClassDB::bind_method(D_METHOD("start", "callable", "priority"), &Thread::start, DEFVAL(PRIORITY_NORMAL));
ClassDB::bind_method(D_METHOD("get_id"), &Thread::get_id);
@@ -1262,6 +1272,8 @@ void Thread::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_alive"), &Thread::is_alive);
ClassDB::bind_method(D_METHOD("wait_to_finish"), &Thread::wait_to_finish);
+ ClassDB::bind_static_method("Thread", D_METHOD("set_thread_safety_checks_enabled", "enabled"), &Thread::set_thread_safety_checks_enabled);
+
BIND_ENUM_CONSTANT(PRIORITY_LOW);
BIND_ENUM_CONSTANT(PRIORITY_NORMAL);
BIND_ENUM_CONSTANT(PRIORITY_HIGH);
diff --git a/core/core_bind.h b/core/core_bind.h
index 55c365eb7c..6b25510b14 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -408,6 +408,8 @@ public:
bool is_started() const;
bool is_alive() const;
Variant wait_to_finish();
+
+ static void set_thread_safety_checks_enabled(bool p_enabled);
};
namespace special {
diff --git a/core/core_builders.py b/core/core_builders.py
index b0a3b85d58..e40ebbb14d 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -239,7 +239,6 @@ def make_license_header(target, source, env):
data_list += part["Copyright"]
with open(dst, "w", encoding="utf-8") as f:
-
f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
f.write("#ifndef LICENSE_GEN_H\n")
f.write("#define LICENSE_GEN_H\n")
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index 623b1eb0ce..dc46ffc307 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -138,7 +138,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
// Cache options
String variable_prefix = options["variable_prefix"];
- if (line.is_empty()) {
+ if (line.is_empty() && !feof(stdin)) {
print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'");
print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'");
print_line("Enter \"help\" for assistance.");
@@ -267,7 +267,8 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
print_line("Added breakpoint at " + source + ":" + itos(linenr));
}
- } else if (line == "q" || line == "quit") {
+ } else if (line == "q" || line == "quit" ||
+ (line.is_empty() && feof(stdin))) {
// Do not stop again on quit
script_debugger->clear_breakpoints();
script_debugger->set_depth(-1);
diff --git a/core/doc_data.cpp b/core/doc_data.cpp
index 2d909f5335..7549ba884e 100644
--- a/core/doc_data.cpp
+++ b/core/doc_data.cpp
@@ -51,6 +51,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper
if (p_method.return_enum.begins_with("_")) { //proxy class
p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
}
+ p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_method.return_type = "int";
} else if (p_retinfo.class_name != StringName()) {
p_method.return_type = p_retinfo.class_name;
@@ -82,6 +83,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const
if (p_argument.enumeration.begins_with("_")) { //proxy class
p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
}
+ p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD;
p_argument.type = "int";
} else if (p_arginfo.class_name != StringName()) {
p_argument.type = p_arginfo.class_name;
diff --git a/core/doc_data.h b/core/doc_data.h
index fc184c411c..0fe7414b98 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -50,6 +50,7 @@ public:
String name;
String type;
String enumeration;
+ bool is_bitfield = false;
String default_value;
bool operator<(const ArgumentDoc &p_arg) const {
if (name == p_arg.name) {
@@ -70,6 +71,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("default_value")) {
@@ -91,6 +95,7 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.default_value.is_empty()) {
@@ -105,6 +110,7 @@ public:
String name;
String return_type;
String return_enum;
+ bool return_is_bitfield = false;
String qualifiers;
String description;
bool is_deprecated = false;
@@ -152,6 +158,9 @@ public:
if (p_dict.has("return_enum")) {
doc.return_enum = p_dict["return_enum"];
+ if (p_dict.has("return_is_bitfield")) {
+ doc.return_is_bitfield = p_dict["return_is_bitfield"];
+ }
}
if (p_dict.has("qualifiers")) {
@@ -201,6 +210,7 @@ public:
if (!p_doc.return_enum.is_empty()) {
dict["return_enum"] = p_doc.return_enum;
+ dict["return_is_bitfield"] = p_doc.return_is_bitfield;
}
if (!p_doc.qualifiers.is_empty()) {
@@ -264,10 +274,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
- }
-
- if (p_dict.has("is_bitfield")) {
- doc.is_bitfield = p_dict["is_bitfield"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("description")) {
@@ -299,10 +308,9 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
- dict["is_bitfield"] = p_doc.is_bitfield;
-
if (!p_doc.description.is_empty()) {
dict["description"] = p_doc.description;
}
@@ -319,6 +327,7 @@ public:
String name;
String type;
String enumeration;
+ bool is_bitfield = false;
String description;
String setter, getter;
String default_value;
@@ -342,6 +351,9 @@ public:
if (p_dict.has("enumeration")) {
doc.enumeration = p_dict["enumeration"];
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
}
if (p_dict.has("description")) {
@@ -391,6 +403,7 @@ public:
if (!p_doc.enumeration.is_empty()) {
dict["enumeration"] = p_doc.enumeration;
+ dict["is_bitfield"] = p_doc.is_bitfield;
}
if (!p_doc.description.is_empty()) {
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 8bdea01ae6..73526fae3e 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -37,7 +37,6 @@
#include "core/version.h"
extern void gdextension_setup_interface();
-extern void *gdextension_get_legacy_interface();
extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name);
typedef GDExtensionBool (*GDExtensionLegacyInitializationFunction)(void *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
@@ -450,7 +449,7 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p
return *function;
}
-Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface) {
+Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path);
if (err != OK) {
ERR_PRINT("GDExtension dynamic library not found: " + p_path);
@@ -467,15 +466,8 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
return err;
}
- GDExtensionBool ret = 0;
- if (p_use_legacy_interface) {
- GDExtensionLegacyInitializationFunction initialization_function = (GDExtensionLegacyInitializationFunction)entry_funcptr;
- ret = initialization_function(gdextension_get_legacy_interface(), this, &initialization);
-
- } else {
- GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
- ret = initialization_function(&gdextension_get_proc_address, this, &initialization);
- }
+ GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
+ GDExtensionBool ret = initialization_function(&gdextension_get_proc_address, this, &initialization);
if (ret) {
level_initialized = -1;
@@ -486,10 +478,6 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
}
}
-Error GDExtension::open_library_compat_76406(const String &p_path, const String &p_entry_symbol) {
- return open_library(p_path, p_entry_symbol, true);
-}
-
void GDExtension::close_library() {
ERR_FAIL_COND(library == nullptr);
OS::get_singleton()->close_dynamic_library(library);
@@ -525,8 +513,7 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) {
}
void GDExtension::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library, DEFVAL(false));
- ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library_compat_76406);
+ ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library);
ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library);
ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open);
@@ -599,9 +586,20 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
compatibility_minimum[i] = parts[i];
}
}
+ } else {
+ if (r_error) {
+ *r_error = ERR_INVALID_DATA;
+ }
+ ERR_PRINT("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: " + p_path);
+ return Ref<Resource>();
}
- if (compatibility_minimum[0] < 4) {
- compatibility_minimum[0] = 4;
+
+ if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) {
+ if (r_error) {
+ *r_error = ERR_INVALID_DATA;
+ }
+ ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path));
+ return Ref<Resource>();
}
bool compatible = true;
@@ -635,12 +633,10 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
library_path = p_path.get_base_dir().path_join(library_path);
}
- bool use_legacy_interface = compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0;
-
Ref<GDExtension> lib;
lib.instantiate();
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
- err = lib->open_library(abs_path, entry_symbol, use_legacy_interface);
+ err = lib->open_library(abs_path, entry_symbol);
if (r_error) {
*r_error = err;
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index 49f1cf1d8e..77ec458d30 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -72,8 +72,7 @@ public:
static String get_extension_list_config_file();
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);
- Error open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface = false);
- Error open_library_compat_76406(const String &p_path, const String &p_entry_symbol);
+ Error open_library(const String &p_path, const String &p_entry_symbol);
void close_library();
enum InitializationLevel {
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 21d34b6e0c..7fbf2d00a1 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -1218,322 +1218,3 @@ void gdextension_setup_interface() {
}
#undef REGISTER_INTERFACE_FUNCTION
-
-/*
- * Handle legacy GDExtension interface from Godot 4.0.
- */
-
-typedef struct {
- uint32_t version_major;
- uint32_t version_minor;
- uint32_t version_patch;
- const char *version_string;
-
- GDExtensionInterfaceMemAlloc mem_alloc;
- GDExtensionInterfaceMemRealloc mem_realloc;
- GDExtensionInterfaceMemFree mem_free;
-
- GDExtensionInterfacePrintError print_error;
- GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
- GDExtensionInterfacePrintWarning print_warning;
- GDExtensionInterfacePrintWarningWithMessage print_warning_with_message;
- GDExtensionInterfacePrintScriptError print_script_error;
- GDExtensionInterfacePrintScriptErrorWithMessage print_script_error_with_message;
-
- GDExtensionInterfaceGetNativeStructSize get_native_struct_size;
-
- GDExtensionInterfaceVariantNewCopy variant_new_copy;
- GDExtensionInterfaceVariantNewNil variant_new_nil;
- GDExtensionInterfaceVariantDestroy variant_destroy;
-
- GDExtensionInterfaceVariantCall variant_call;
- GDExtensionInterfaceVariantCallStatic variant_call_static;
- GDExtensionInterfaceVariantEvaluate variant_evaluate;
- GDExtensionInterfaceVariantSet variant_set;
- GDExtensionInterfaceVariantSetNamed variant_set_named;
- GDExtensionInterfaceVariantSetKeyed variant_set_keyed;
- GDExtensionInterfaceVariantSetIndexed variant_set_indexed;
- GDExtensionInterfaceVariantGet variant_get;
- GDExtensionInterfaceVariantGetNamed variant_get_named;
- GDExtensionInterfaceVariantGetKeyed variant_get_keyed;
- GDExtensionInterfaceVariantGetIndexed variant_get_indexed;
- GDExtensionInterfaceVariantIterInit variant_iter_init;
- GDExtensionInterfaceVariantIterNext variant_iter_next;
- GDExtensionInterfaceVariantIterGet variant_iter_get;
- GDExtensionInterfaceVariantHash variant_hash;
- GDExtensionInterfaceVariantRecursiveHash variant_recursive_hash;
- GDExtensionInterfaceVariantHashCompare variant_hash_compare;
- GDExtensionInterfaceVariantBooleanize variant_booleanize;
- GDExtensionInterfaceVariantDuplicate variant_duplicate;
- GDExtensionInterfaceVariantStringify variant_stringify;
-
- GDExtensionInterfaceVariantGetType variant_get_type;
- GDExtensionInterfaceVariantHasMethod variant_has_method;
- GDExtensionInterfaceVariantHasMember variant_has_member;
- GDExtensionInterfaceVariantHasKey variant_has_key;
- GDExtensionInterfaceVariantGetTypeName variant_get_type_name;
- GDExtensionInterfaceVariantCanConvert variant_can_convert;
- GDExtensionInterfaceVariantCanConvertStrict variant_can_convert_strict;
-
- GDExtensionInterfaceGetVariantFromTypeConstructor get_variant_from_type_constructor;
- GDExtensionInterfaceGetVariantToTypeConstructor get_variant_to_type_constructor;
- GDExtensionInterfaceVariantGetPtrOperatorEvaluator variant_get_ptr_operator_evaluator;
- GDExtensionInterfaceVariantGetPtrBuiltinMethod variant_get_ptr_builtin_method;
- GDExtensionInterfaceVariantGetPtrConstructor variant_get_ptr_constructor;
- GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor;
- GDExtensionInterfaceVariantConstruct variant_construct;
- GDExtensionInterfaceVariantGetPtrSetter variant_get_ptr_setter;
- GDExtensionInterfaceVariantGetPtrGetter variant_get_ptr_getter;
- GDExtensionInterfaceVariantGetPtrIndexedSetter variant_get_ptr_indexed_setter;
- GDExtensionInterfaceVariantGetPtrIndexedGetter variant_get_ptr_indexed_getter;
- GDExtensionInterfaceVariantGetPtrKeyedSetter variant_get_ptr_keyed_setter;
- GDExtensionInterfaceVariantGetPtrKeyedGetter variant_get_ptr_keyed_getter;
- GDExtensionInterfaceVariantGetPtrKeyedChecker variant_get_ptr_keyed_checker;
- GDExtensionInterfaceVariantGetConstantValue variant_get_constant_value;
- GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function;
-
- GDExtensionInterfaceStringNewWithLatin1Chars string_new_with_latin1_chars;
- GDExtensionInterfaceStringNewWithUtf8Chars string_new_with_utf8_chars;
- GDExtensionInterfaceStringNewWithUtf16Chars string_new_with_utf16_chars;
- GDExtensionInterfaceStringNewWithUtf32Chars string_new_with_utf32_chars;
- GDExtensionInterfaceStringNewWithWideChars string_new_with_wide_chars;
- GDExtensionInterfaceStringNewWithLatin1CharsAndLen string_new_with_latin1_chars_and_len;
- GDExtensionInterfaceStringNewWithUtf8CharsAndLen string_new_with_utf8_chars_and_len;
- GDExtensionInterfaceStringNewWithUtf16CharsAndLen string_new_with_utf16_chars_and_len;
- GDExtensionInterfaceStringNewWithUtf32CharsAndLen string_new_with_utf32_chars_and_len;
- GDExtensionInterfaceStringNewWithWideCharsAndLen string_new_with_wide_chars_and_len;
- GDExtensionInterfaceStringToLatin1Chars string_to_latin1_chars;
- GDExtensionInterfaceStringToUtf8Chars string_to_utf8_chars;
- GDExtensionInterfaceStringToUtf16Chars string_to_utf16_chars;
- GDExtensionInterfaceStringToUtf32Chars string_to_utf32_chars;
- GDExtensionInterfaceStringToWideChars string_to_wide_chars;
- GDExtensionInterfaceStringOperatorIndex string_operator_index;
- GDExtensionInterfaceStringOperatorIndexConst string_operator_index_const;
-
- GDExtensionInterfaceStringOperatorPlusEqString string_operator_plus_eq_string;
- GDExtensionInterfaceStringOperatorPlusEqChar string_operator_plus_eq_char;
- GDExtensionInterfaceStringOperatorPlusEqCstr string_operator_plus_eq_cstr;
- GDExtensionInterfaceStringOperatorPlusEqWcstr string_operator_plus_eq_wcstr;
- GDExtensionInterfaceStringOperatorPlusEqC32str string_operator_plus_eq_c32str;
-
- GDExtensionInterfaceXmlParserOpenBuffer xml_parser_open_buffer;
-
- GDExtensionInterfaceFileAccessStoreBuffer file_access_store_buffer;
- GDExtensionInterfaceFileAccessGetBuffer file_access_get_buffer;
-
- GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask worker_thread_pool_add_native_group_task;
- GDExtensionInterfaceWorkerThreadPoolAddNativeTask worker_thread_pool_add_native_task;
-
- GDExtensionInterfacePackedByteArrayOperatorIndex packed_byte_array_operator_index;
- GDExtensionInterfacePackedByteArrayOperatorIndexConst packed_byte_array_operator_index_const;
- GDExtensionInterfacePackedColorArrayOperatorIndex packed_color_array_operator_index;
- GDExtensionInterfacePackedColorArrayOperatorIndexConst packed_color_array_operator_index_const;
- GDExtensionInterfacePackedFloat32ArrayOperatorIndex packed_float32_array_operator_index;
- GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst packed_float32_array_operator_index_const;
- GDExtensionInterfacePackedFloat64ArrayOperatorIndex packed_float64_array_operator_index;
- GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst packed_float64_array_operator_index_const;
- GDExtensionInterfacePackedInt32ArrayOperatorIndex packed_int32_array_operator_index;
- GDExtensionInterfacePackedInt32ArrayOperatorIndexConst packed_int32_array_operator_index_const;
- GDExtensionInterfacePackedInt64ArrayOperatorIndex packed_int64_array_operator_index;
- GDExtensionInterfacePackedInt64ArrayOperatorIndexConst packed_int64_array_operator_index_const;
- GDExtensionInterfacePackedStringArrayOperatorIndex packed_string_array_operator_index;
- GDExtensionInterfacePackedStringArrayOperatorIndexConst packed_string_array_operator_index_const;
- GDExtensionInterfacePackedVector2ArrayOperatorIndex packed_vector2_array_operator_index;
- GDExtensionInterfacePackedVector2ArrayOperatorIndexConst packed_vector2_array_operator_index_const;
- GDExtensionInterfacePackedVector3ArrayOperatorIndex packed_vector3_array_operator_index;
- GDExtensionInterfacePackedVector3ArrayOperatorIndexConst packed_vector3_array_operator_index_const;
- GDExtensionInterfaceArrayOperatorIndex array_operator_index;
- GDExtensionInterfaceArrayOperatorIndexConst array_operator_index_const;
- GDExtensionInterfaceArrayRef array_ref;
- GDExtensionInterfaceArraySetTyped array_set_typed;
-
- GDExtensionInterfaceDictionaryOperatorIndex dictionary_operator_index;
- GDExtensionInterfaceDictionaryOperatorIndexConst dictionary_operator_index_const;
-
- GDExtensionInterfaceObjectMethodBindCall object_method_bind_call;
- GDExtensionInterfaceObjectMethodBindPtrcall object_method_bind_ptrcall;
- GDExtensionInterfaceObjectDestroy object_destroy;
- GDExtensionInterfaceGlobalGetSingleton global_get_singleton;
- GDExtensionInterfaceObjectGetInstanceBinding object_get_instance_binding;
- GDExtensionInterfaceObjectSetInstanceBinding object_set_instance_binding;
- GDExtensionInterfaceObjectSetInstance object_set_instance;
- GDExtensionInterfaceObjectCastTo object_cast_to;
- GDExtensionInterfaceObjectGetInstanceFromId object_get_instance_from_id;
- GDExtensionInterfaceObjectGetInstanceId object_get_instance_id;
-
- GDExtensionInterfaceRefGetObject ref_get_object;
- GDExtensionInterfaceRefSetObject ref_set_object;
-
- GDExtensionInterfaceScriptInstanceCreate script_instance_create;
-
- GDExtensionInterfaceClassdbConstructObject classdb_construct_object;
- GDExtensionInterfaceClassdbGetMethodBind classdb_get_method_bind;
- GDExtensionInterfaceClassdbGetClassTag classdb_get_class_tag;
-
- GDExtensionInterfaceClassdbRegisterExtensionClass classdb_register_extension_class;
- GDExtensionInterfaceClassdbRegisterExtensionClassMethod classdb_register_extension_class_method;
- GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant classdb_register_extension_class_integer_constant;
- GDExtensionInterfaceClassdbRegisterExtensionClassProperty classdb_register_extension_class_property;
- GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup classdb_register_extension_class_property_group;
- GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup classdb_register_extension_class_property_subgroup;
- GDExtensionInterfaceClassdbRegisterExtensionClassSignal classdb_register_extension_class_signal;
- GDExtensionInterfaceClassdbUnregisterExtensionClass classdb_unregister_extension_class;
-
- GDExtensionInterfaceGetLibraryPath get_library_path;
-
-} LegacyGDExtensionInterface;
-
-static LegacyGDExtensionInterface *legacy_gdextension_interface = nullptr;
-
-#define SETUP_LEGACY_FUNC(m_name, m_type) legacy_gdextension_interface->m_name = (m_type)GDExtension::get_interface_function(#m_name)
-
-void *gdextension_get_legacy_interface() {
- if (legacy_gdextension_interface != nullptr) {
- return legacy_gdextension_interface;
- }
-
- legacy_gdextension_interface = memnew(LegacyGDExtensionInterface);
-
- // Force to 4.0.999 to make it easier to detect this structure.
- legacy_gdextension_interface->version_major = 4;
- legacy_gdextension_interface->version_minor = 0;
- legacy_gdextension_interface->version_patch = 999;
- legacy_gdextension_interface->version_string = "Godot Engine v4.0.999.stable.official [000000000]";
-
- SETUP_LEGACY_FUNC(mem_alloc, GDExtensionInterfaceMemAlloc);
- SETUP_LEGACY_FUNC(mem_realloc, GDExtensionInterfaceMemRealloc);
- SETUP_LEGACY_FUNC(mem_free, GDExtensionInterfaceMemFree);
- SETUP_LEGACY_FUNC(print_error, GDExtensionInterfacePrintError);
- SETUP_LEGACY_FUNC(print_error_with_message, GDExtensionInterfacePrintErrorWithMessage);
- SETUP_LEGACY_FUNC(print_warning, GDExtensionInterfacePrintWarning);
- SETUP_LEGACY_FUNC(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage);
- SETUP_LEGACY_FUNC(print_script_error, GDExtensionInterfacePrintScriptError);
- SETUP_LEGACY_FUNC(print_script_error_with_message, GDExtensionInterfacePrintScriptErrorWithMessage);
- SETUP_LEGACY_FUNC(get_native_struct_size, GDExtensionInterfaceGetNativeStructSize);
- SETUP_LEGACY_FUNC(variant_new_copy, GDExtensionInterfaceVariantNewCopy);
- SETUP_LEGACY_FUNC(variant_new_nil, GDExtensionInterfaceVariantNewNil);
- SETUP_LEGACY_FUNC(variant_destroy, GDExtensionInterfaceVariantDestroy);
- SETUP_LEGACY_FUNC(variant_call, GDExtensionInterfaceVariantCall);
- SETUP_LEGACY_FUNC(variant_call_static, GDExtensionInterfaceVariantCallStatic);
- SETUP_LEGACY_FUNC(variant_evaluate, GDExtensionInterfaceVariantEvaluate);
- SETUP_LEGACY_FUNC(variant_set, GDExtensionInterfaceVariantSet);
- SETUP_LEGACY_FUNC(variant_set_named, GDExtensionInterfaceVariantSetNamed);
- SETUP_LEGACY_FUNC(variant_set_keyed, GDExtensionInterfaceVariantSetKeyed);
- SETUP_LEGACY_FUNC(variant_set_indexed, GDExtensionInterfaceVariantSetIndexed);
- SETUP_LEGACY_FUNC(variant_get, GDExtensionInterfaceVariantGet);
- SETUP_LEGACY_FUNC(variant_get_named, GDExtensionInterfaceVariantGetNamed);
- SETUP_LEGACY_FUNC(variant_get_keyed, GDExtensionInterfaceVariantGetKeyed);
- SETUP_LEGACY_FUNC(variant_get_indexed, GDExtensionInterfaceVariantGetIndexed);
- SETUP_LEGACY_FUNC(variant_iter_init, GDExtensionInterfaceVariantIterInit);
- SETUP_LEGACY_FUNC(variant_iter_next, GDExtensionInterfaceVariantIterNext);
- SETUP_LEGACY_FUNC(variant_iter_get, GDExtensionInterfaceVariantIterGet);
- SETUP_LEGACY_FUNC(variant_hash, GDExtensionInterfaceVariantHash);
- SETUP_LEGACY_FUNC(variant_recursive_hash, GDExtensionInterfaceVariantRecursiveHash);
- SETUP_LEGACY_FUNC(variant_hash_compare, GDExtensionInterfaceVariantHashCompare);
- SETUP_LEGACY_FUNC(variant_booleanize, GDExtensionInterfaceVariantBooleanize);
- SETUP_LEGACY_FUNC(variant_duplicate, GDExtensionInterfaceVariantDuplicate);
- SETUP_LEGACY_FUNC(variant_stringify, GDExtensionInterfaceVariantStringify);
- SETUP_LEGACY_FUNC(variant_get_type, GDExtensionInterfaceVariantGetType);
- SETUP_LEGACY_FUNC(variant_has_method, GDExtensionInterfaceVariantHasMethod);
- SETUP_LEGACY_FUNC(variant_has_member, GDExtensionInterfaceVariantHasMember);
- SETUP_LEGACY_FUNC(variant_has_key, GDExtensionInterfaceVariantHasKey);
- SETUP_LEGACY_FUNC(variant_get_type_name, GDExtensionInterfaceVariantGetTypeName);
- SETUP_LEGACY_FUNC(variant_can_convert, GDExtensionInterfaceVariantCanConvert);
- SETUP_LEGACY_FUNC(variant_can_convert_strict, GDExtensionInterfaceVariantCanConvertStrict);
- SETUP_LEGACY_FUNC(get_variant_from_type_constructor, GDExtensionInterfaceGetVariantFromTypeConstructor);
- SETUP_LEGACY_FUNC(get_variant_to_type_constructor, GDExtensionInterfaceGetVariantToTypeConstructor);
- SETUP_LEGACY_FUNC(variant_get_ptr_operator_evaluator, GDExtensionInterfaceVariantGetPtrOperatorEvaluator);
- SETUP_LEGACY_FUNC(variant_get_ptr_builtin_method, GDExtensionInterfaceVariantGetPtrBuiltinMethod);
- SETUP_LEGACY_FUNC(variant_get_ptr_constructor, GDExtensionInterfaceVariantGetPtrConstructor);
- SETUP_LEGACY_FUNC(variant_get_ptr_destructor, GDExtensionInterfaceVariantGetPtrDestructor);
- SETUP_LEGACY_FUNC(variant_construct, GDExtensionInterfaceVariantConstruct);
- SETUP_LEGACY_FUNC(variant_get_ptr_setter, GDExtensionInterfaceVariantGetPtrSetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_getter, GDExtensionInterfaceVariantGetPtrGetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_indexed_setter, GDExtensionInterfaceVariantGetPtrIndexedSetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_indexed_getter, GDExtensionInterfaceVariantGetPtrIndexedGetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_keyed_setter, GDExtensionInterfaceVariantGetPtrKeyedSetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_keyed_getter, GDExtensionInterfaceVariantGetPtrKeyedGetter);
- SETUP_LEGACY_FUNC(variant_get_ptr_keyed_checker, GDExtensionInterfaceVariantGetPtrKeyedChecker);
- SETUP_LEGACY_FUNC(variant_get_constant_value, GDExtensionInterfaceVariantGetConstantValue);
- SETUP_LEGACY_FUNC(variant_get_ptr_utility_function, GDExtensionInterfaceVariantGetPtrUtilityFunction);
- SETUP_LEGACY_FUNC(string_new_with_latin1_chars, GDExtensionInterfaceStringNewWithLatin1Chars);
- SETUP_LEGACY_FUNC(string_new_with_utf8_chars, GDExtensionInterfaceStringNewWithUtf8Chars);
- SETUP_LEGACY_FUNC(string_new_with_utf16_chars, GDExtensionInterfaceStringNewWithUtf16Chars);
- SETUP_LEGACY_FUNC(string_new_with_utf32_chars, GDExtensionInterfaceStringNewWithUtf32Chars);
- SETUP_LEGACY_FUNC(string_new_with_wide_chars, GDExtensionInterfaceStringNewWithWideChars);
- SETUP_LEGACY_FUNC(string_new_with_latin1_chars_and_len, GDExtensionInterfaceStringNewWithLatin1CharsAndLen);
- SETUP_LEGACY_FUNC(string_new_with_utf8_chars_and_len, GDExtensionInterfaceStringNewWithUtf8CharsAndLen);
- SETUP_LEGACY_FUNC(string_new_with_utf16_chars_and_len, GDExtensionInterfaceStringNewWithUtf16CharsAndLen);
- SETUP_LEGACY_FUNC(string_new_with_utf32_chars_and_len, GDExtensionInterfaceStringNewWithUtf32CharsAndLen);
- SETUP_LEGACY_FUNC(string_new_with_wide_chars_and_len, GDExtensionInterfaceStringNewWithWideCharsAndLen);
- SETUP_LEGACY_FUNC(string_to_latin1_chars, GDExtensionInterfaceStringToLatin1Chars);
- SETUP_LEGACY_FUNC(string_to_utf8_chars, GDExtensionInterfaceStringToUtf8Chars);
- SETUP_LEGACY_FUNC(string_to_utf16_chars, GDExtensionInterfaceStringToUtf16Chars);
- SETUP_LEGACY_FUNC(string_to_utf32_chars, GDExtensionInterfaceStringToUtf32Chars);
- SETUP_LEGACY_FUNC(string_to_wide_chars, GDExtensionInterfaceStringToWideChars);
- SETUP_LEGACY_FUNC(string_operator_index, GDExtensionInterfaceStringOperatorIndex);
- SETUP_LEGACY_FUNC(string_operator_index_const, GDExtensionInterfaceStringOperatorIndexConst);
- SETUP_LEGACY_FUNC(string_operator_plus_eq_string, GDExtensionInterfaceStringOperatorPlusEqString);
- SETUP_LEGACY_FUNC(string_operator_plus_eq_char, GDExtensionInterfaceStringOperatorPlusEqChar);
- SETUP_LEGACY_FUNC(string_operator_plus_eq_cstr, GDExtensionInterfaceStringOperatorPlusEqCstr);
- SETUP_LEGACY_FUNC(string_operator_plus_eq_wcstr, GDExtensionInterfaceStringOperatorPlusEqWcstr);
- SETUP_LEGACY_FUNC(string_operator_plus_eq_c32str, GDExtensionInterfaceStringOperatorPlusEqC32str);
- SETUP_LEGACY_FUNC(xml_parser_open_buffer, GDExtensionInterfaceXmlParserOpenBuffer);
- SETUP_LEGACY_FUNC(file_access_store_buffer, GDExtensionInterfaceFileAccessStoreBuffer);
- SETUP_LEGACY_FUNC(file_access_get_buffer, GDExtensionInterfaceFileAccessGetBuffer);
- SETUP_LEGACY_FUNC(worker_thread_pool_add_native_group_task, GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask);
- SETUP_LEGACY_FUNC(worker_thread_pool_add_native_task, GDExtensionInterfaceWorkerThreadPoolAddNativeTask);
- SETUP_LEGACY_FUNC(packed_byte_array_operator_index, GDExtensionInterfacePackedByteArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_byte_array_operator_index_const, GDExtensionInterfacePackedByteArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_color_array_operator_index, GDExtensionInterfacePackedColorArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_color_array_operator_index_const, GDExtensionInterfacePackedColorArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_float32_array_operator_index, GDExtensionInterfacePackedFloat32ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_float32_array_operator_index_const, GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_float64_array_operator_index, GDExtensionInterfacePackedFloat64ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_float64_array_operator_index_const, GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_int32_array_operator_index, GDExtensionInterfacePackedInt32ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_int32_array_operator_index_const, GDExtensionInterfacePackedInt32ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_int64_array_operator_index, GDExtensionInterfacePackedInt64ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_int64_array_operator_index_const, GDExtensionInterfacePackedInt64ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_string_array_operator_index, GDExtensionInterfacePackedStringArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_string_array_operator_index_const, GDExtensionInterfacePackedStringArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_vector2_array_operator_index, GDExtensionInterfacePackedVector2ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_vector2_array_operator_index_const, GDExtensionInterfacePackedVector2ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(packed_vector3_array_operator_index, GDExtensionInterfacePackedVector3ArrayOperatorIndex);
- SETUP_LEGACY_FUNC(packed_vector3_array_operator_index_const, GDExtensionInterfacePackedVector3ArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(array_operator_index, GDExtensionInterfaceArrayOperatorIndex);
- SETUP_LEGACY_FUNC(array_operator_index_const, GDExtensionInterfaceArrayOperatorIndexConst);
- SETUP_LEGACY_FUNC(array_ref, GDExtensionInterfaceArrayRef);
- SETUP_LEGACY_FUNC(array_set_typed, GDExtensionInterfaceArraySetTyped);
- SETUP_LEGACY_FUNC(dictionary_operator_index, GDExtensionInterfaceDictionaryOperatorIndex);
- SETUP_LEGACY_FUNC(dictionary_operator_index_const, GDExtensionInterfaceDictionaryOperatorIndexConst);
- SETUP_LEGACY_FUNC(object_method_bind_call, GDExtensionInterfaceObjectMethodBindCall);
- SETUP_LEGACY_FUNC(object_method_bind_ptrcall, GDExtensionInterfaceObjectMethodBindPtrcall);
- SETUP_LEGACY_FUNC(object_destroy, GDExtensionInterfaceObjectDestroy);
- SETUP_LEGACY_FUNC(global_get_singleton, GDExtensionInterfaceGlobalGetSingleton);
- SETUP_LEGACY_FUNC(object_get_instance_binding, GDExtensionInterfaceObjectGetInstanceBinding);
- SETUP_LEGACY_FUNC(object_set_instance_binding, GDExtensionInterfaceObjectSetInstanceBinding);
- SETUP_LEGACY_FUNC(object_set_instance, GDExtensionInterfaceObjectSetInstance);
- SETUP_LEGACY_FUNC(object_cast_to, GDExtensionInterfaceObjectCastTo);
- SETUP_LEGACY_FUNC(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId);
- SETUP_LEGACY_FUNC(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId);
- SETUP_LEGACY_FUNC(ref_get_object, GDExtensionInterfaceRefGetObject);
- SETUP_LEGACY_FUNC(ref_set_object, GDExtensionInterfaceRefSetObject);
- SETUP_LEGACY_FUNC(script_instance_create, GDExtensionInterfaceScriptInstanceCreate);
- SETUP_LEGACY_FUNC(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
- SETUP_LEGACY_FUNC(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
- SETUP_LEGACY_FUNC(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
- SETUP_LEGACY_FUNC(classdb_register_extension_class, GDExtensionInterfaceClassdbRegisterExtensionClass);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_property_group, GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_property_subgroup, GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup);
- SETUP_LEGACY_FUNC(classdb_register_extension_class_signal, GDExtensionInterfaceClassdbRegisterExtensionClassSignal);
- SETUP_LEGACY_FUNC(classdb_unregister_extension_class, GDExtensionInterfaceClassdbUnregisterExtensionClass);
- SETUP_LEGACY_FUNC(get_library_path, GDExtensionInterfaceGetLibraryPath);
-
- return legacy_gdextension_interface;
-}
-
-#undef SETUP_LEGACY_FUNC
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 3aa41f28da..4d7bdf9502 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -195,11 +195,11 @@ typedef struct {
int32_t expected;
} GDExtensionCallError;
-typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr);
-typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionTypePtr, GDExtensionVariantPtr);
+typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
+typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
-typedef void (*GDExtensionPtrConstructor)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args);
+typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
typedef void (*GDExtensionPtrDestructor)(GDExtensionTypePtr p_base);
typedef void (*GDExtensionPtrSetter)(GDExtensionTypePtr p_base, GDExtensionConstTypePtr p_value);
typedef void (*GDExtensionPtrGetter)(GDExtensionConstTypePtr p_base, GDExtensionTypePtr r_value);
@@ -490,6 +490,7 @@ typedef struct {
/**
* @name get_godot_version
+ * @since 4.1
*
* Gets the Godot version that the GDExtension was loaded into.
*
@@ -501,6 +502,7 @@ typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_g
/**
* @name mem_alloc
+ * @since 4.1
*
* Allocates memory.
*
@@ -512,6 +514,7 @@ typedef void *(*GDExtensionInterfaceMemAlloc)(size_t p_bytes);
/**
* @name mem_realloc
+ * @since 4.1
*
* Reallocates memory.
*
@@ -524,6 +527,7 @@ typedef void *(*GDExtensionInterfaceMemRealloc)(void *p_ptr, size_t p_bytes);
/**
* @name mem_free
+ * @since 4.1
*
* Frees memory.
*
@@ -535,6 +539,7 @@ typedef void (*GDExtensionInterfaceMemFree)(void *p_ptr);
/**
* @name print_error
+ * @since 4.1
*
* Logs an error to Godot's built-in debugger and to the OS terminal.
*
@@ -548,6 +553,7 @@ typedef void (*GDExtensionInterfacePrintError)(const char *p_description, const
/**
* @name print_error_with_message
+ * @since 4.1
*
* Logs an error with a message to Godot's built-in debugger and to the OS terminal.
*
@@ -562,6 +568,7 @@ typedef void (*GDExtensionInterfacePrintErrorWithMessage)(const char *p_descript
/**
* @name print_warning
+ * @since 4.1
*
* Logs a warning to Godot's built-in debugger and to the OS terminal.
*
@@ -575,6 +582,7 @@ typedef void (*GDExtensionInterfacePrintWarning)(const char *p_description, cons
/**
* @name print_warning_with_message
+ * @since 4.1
*
* Logs a warning with a message to Godot's built-in debugger and to the OS terminal.
*
@@ -589,6 +597,7 @@ typedef void (*GDExtensionInterfacePrintWarningWithMessage)(const char *p_descri
/**
* @name print_script_error
+ * @since 4.1
*
* Logs a script error to Godot's built-in debugger and to the OS terminal.
*
@@ -602,6 +611,7 @@ typedef void (*GDExtensionInterfacePrintScriptError)(const char *p_description,
/**
* @name print_script_error_with_message
+ * @since 4.1
*
* Logs a script error with a message to Godot's built-in debugger and to the OS terminal.
*
@@ -616,6 +626,7 @@ typedef void (*GDExtensionInterfacePrintScriptErrorWithMessage)(const char *p_de
/**
* @name get_native_struct_size
+ * @since 4.1
*
* Gets the size of a native struct (ex. ObjectID) in bytes.
*
@@ -629,6 +640,7 @@ typedef uint64_t (*GDExtensionInterfaceGetNativeStructSize)(GDExtensionConstStri
/**
* @name variant_new_copy
+ * @since 4.1
*
* Copies one Variant into a another.
*
@@ -639,6 +651,7 @@ typedef void (*GDExtensionInterfaceVariantNewCopy)(GDExtensionUninitializedVaria
/**
* @name variant_new_nil
+ * @since 4.1
*
* Creates a new Variant containing nil.
*
@@ -648,6 +661,7 @@ typedef void (*GDExtensionInterfaceVariantNewNil)(GDExtensionUninitializedVarian
/**
* @name variant_destroy
+ * @since 4.1
*
* Destroys a Variant.
*
@@ -657,6 +671,7 @@ typedef void (*GDExtensionInterfaceVariantDestroy)(GDExtensionVariantPtr p_self)
/**
* @name variant_call
+ * @since 4.1
*
* Calls a method on a Variant.
*
@@ -673,6 +688,7 @@ typedef void (*GDExtensionInterfaceVariantCall)(GDExtensionVariantPtr p_self, GD
/**
* @name variant_call_static
+ * @since 4.1
*
* Calls a static method on a Variant.
*
@@ -689,6 +705,7 @@ typedef void (*GDExtensionInterfaceVariantCallStatic)(GDExtensionVariantType p_t
/**
* @name variant_evaluate
+ * @since 4.1
*
* Evaluate an operator on two Variants.
*
@@ -704,6 +721,7 @@ typedef void (*GDExtensionInterfaceVariantEvaluate)(GDExtensionVariantOperator p
/**
* @name variant_set
+ * @since 4.1
*
* Sets a key on a Variant to a value.
*
@@ -718,6 +736,7 @@ typedef void (*GDExtensionInterfaceVariantSet)(GDExtensionVariantPtr p_self, GDE
/**
* @name variant_set_named
+ * @since 4.1
*
* Sets a named key on a Variant to a value.
*
@@ -732,6 +751,7 @@ typedef void (*GDExtensionInterfaceVariantSetNamed)(GDExtensionVariantPtr p_self
/**
* @name variant_set_keyed
+ * @since 4.1
*
* Sets a keyed property on a Variant to a value.
*
@@ -746,6 +766,7 @@ typedef void (*GDExtensionInterfaceVariantSetKeyed)(GDExtensionVariantPtr p_self
/**
* @name variant_set_indexed
+ * @since 4.1
*
* Sets an index on a Variant to a value.
*
@@ -759,6 +780,7 @@ typedef void (*GDExtensionInterfaceVariantSetIndexed)(GDExtensionVariantPtr p_se
/**
* @name variant_get
+ * @since 4.1
*
* Gets the value of a key from a Variant.
*
@@ -771,6 +793,7 @@ typedef void (*GDExtensionInterfaceVariantGet)(GDExtensionConstVariantPtr p_self
/**
* @name variant_get_named
+ * @since 4.1
*
* Gets the value of a named key from a Variant.
*
@@ -783,6 +806,7 @@ typedef void (*GDExtensionInterfaceVariantGetNamed)(GDExtensionConstVariantPtr p
/**
* @name variant_get_keyed
+ * @since 4.1
*
* Gets the value of a keyed property from a Variant.
*
@@ -795,6 +819,7 @@ typedef void (*GDExtensionInterfaceVariantGetKeyed)(GDExtensionConstVariantPtr p
/**
* @name variant_get_indexed
+ * @since 4.1
*
* Gets the value of an index from a Variant.
*
@@ -808,6 +833,7 @@ typedef void (*GDExtensionInterfaceVariantGetIndexed)(GDExtensionConstVariantPtr
/**
* @name variant_iter_init
+ * @since 4.1
*
* Initializes an iterator over a Variant.
*
@@ -823,6 +849,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantIterInit)(GDExtensionConstV
/**
* @name variant_iter_next
+ * @since 4.1
*
* Gets the next value for an iterator over a Variant.
*
@@ -838,6 +865,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantIterNext)(GDExtensionConstV
/**
* @name variant_iter_get
+ * @since 4.1
*
* Gets the next value for an iterator over a Variant.
*
@@ -852,6 +880,7 @@ typedef void (*GDExtensionInterfaceVariantIterGet)(GDExtensionConstVariantPtr p_
/**
* @name variant_hash
+ * @since 4.1
*
* Gets the hash of a Variant.
*
@@ -865,6 +894,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceVariantHash)(GDExtensionConstVarian
/**
* @name variant_recursive_hash
+ * @since 4.1
*
* Gets the recursive hash of a Variant.
*
@@ -879,6 +909,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceVariantRecursiveHash)(GDExtensionCo
/**
* @name variant_hash_compare
+ * @since 4.1
*
* Compares two Variants by their hash.
*
@@ -893,6 +924,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHashCompare)(GDExtensionCon
/**
* @name variant_booleanize
+ * @since 4.1
*
* Converts a Variant to a boolean.
*
@@ -904,6 +936,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantBooleanize)(GDExtensionCons
/**
* @name variant_duplicate
+ * @since 4.1
*
* Duplicates a Variant.
*
@@ -915,6 +948,7 @@ typedef void (*GDExtensionInterfaceVariantDuplicate)(GDExtensionConstVariantPtr
/**
* @name variant_stringify
+ * @since 4.1
*
* Converts a Variant to a string.
*
@@ -925,6 +959,7 @@ typedef void (*GDExtensionInterfaceVariantStringify)(GDExtensionConstVariantPtr
/**
* @name variant_get_type
+ * @since 4.1
*
* Gets the type of a Variant.
*
@@ -936,6 +971,7 @@ typedef GDExtensionVariantType (*GDExtensionInterfaceVariantGetType)(GDExtension
/**
* @name variant_has_method
+ * @since 4.1
*
* Checks if a Variant has the given method.
*
@@ -948,6 +984,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMethod)(GDExtensionConst
/**
* @name variant_has_member
+ * @since 4.1
*
* Checks if a type of Variant has the given member.
*
@@ -960,6 +997,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria
/**
* @name variant_has_key
+ * @since 4.1
*
* Checks if a Variant has a key.
*
@@ -973,6 +1011,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVar
/**
* @name variant_get_type_name
+ * @since 4.1
*
* Gets the name of a Variant type.
*
@@ -983,6 +1022,7 @@ typedef void (*GDExtensionInterfaceVariantGetTypeName)(GDExtensionVariantType p_
/**
* @name variant_can_convert
+ * @since 4.1
*
* Checks if Variants can be converted from one type to another.
*
@@ -995,6 +1035,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantCanConvert)(GDExtensionVari
/**
* @name variant_can_convert_strict
+ * @since 4.1
*
* Checks if Variant can be converted from one type to another using stricter rules.
*
@@ -1007,6 +1048,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantCanConvertStrict)(GDExtensi
/**
* @name get_variant_from_type_constructor
+ * @since 4.1
*
* Gets a pointer to a function that can create a Variant of the given type from a raw value.
*
@@ -1018,6 +1060,7 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria
/**
* @name get_variant_to_type_constructor
+ * @since 4.1
*
* Gets a pointer to a function that can get the raw value from a Variant of the given type.
*
@@ -1029,6 +1072,7 @@ typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVaria
/**
* @name variant_get_ptr_operator_evaluator
+ * @since 4.1
*
* Gets a pointer to a function that can evaluate the given Variant operator on the given Variant types.
*
@@ -1042,6 +1086,7 @@ typedef GDExtensionPtrOperatorEvaluator (*GDExtensionInterfaceVariantGetPtrOpera
/**
* @name variant_get_ptr_builtin_method
+ * @since 4.1
*
* Gets a pointer to a function that can call a builtin method on a type of Variant.
*
@@ -1055,6 +1100,7 @@ typedef GDExtensionPtrBuiltInMethod (*GDExtensionInterfaceVariantGetPtrBuiltinMe
/**
* @name variant_get_ptr_constructor
+ * @since 4.1
*
* Gets a pointer to a function that can call one of the constructors for a type of Variant.
*
@@ -1067,6 +1113,7 @@ typedef GDExtensionPtrConstructor (*GDExtensionInterfaceVariantGetPtrConstructor
/**
* @name variant_get_ptr_destructor
+ * @since 4.1
*
* Gets a pointer to a function than can call the destructor for a type of Variant.
*
@@ -1078,6 +1125,7 @@ typedef GDExtensionPtrDestructor (*GDExtensionInterfaceVariantGetPtrDestructor)(
/**
* @name variant_construct
+ * @since 4.1
*
* Constructs a Variant of the given type, using the first constructor that matches the given arguments.
*
@@ -1091,6 +1139,7 @@ typedef void (*GDExtensionInterfaceVariantConstruct)(GDExtensionVariantType p_ty
/**
* @name variant_get_ptr_setter
+ * @since 4.1
*
* Gets a pointer to a function that can call a member's setter on the given Variant type.
*
@@ -1103,6 +1152,7 @@ typedef GDExtensionPtrSetter (*GDExtensionInterfaceVariantGetPtrSetter)(GDExtens
/**
* @name variant_get_ptr_getter
+ * @since 4.1
*
* Gets a pointer to a function that can call a member's getter on the given Variant type.
*
@@ -1115,6 +1165,7 @@ typedef GDExtensionPtrGetter (*GDExtensionInterfaceVariantGetPtrGetter)(GDExtens
/**
* @name variant_get_ptr_indexed_setter
+ * @since 4.1
*
* Gets a pointer to a function that can set an index on the given Variant type.
*
@@ -1126,6 +1177,7 @@ typedef GDExtensionPtrIndexedSetter (*GDExtensionInterfaceVariantGetPtrIndexedSe
/**
* @name variant_get_ptr_indexed_getter
+ * @since 4.1
*
* Gets a pointer to a function that can get an index on the given Variant type.
*
@@ -1137,6 +1189,7 @@ typedef GDExtensionPtrIndexedGetter (*GDExtensionInterfaceVariantGetPtrIndexedGe
/**
* @name variant_get_ptr_keyed_setter
+ * @since 4.1
*
* Gets a pointer to a function that can set a key on the given Variant type.
*
@@ -1148,6 +1201,7 @@ typedef GDExtensionPtrKeyedSetter (*GDExtensionInterfaceVariantGetPtrKeyedSetter
/**
* @name variant_get_ptr_keyed_getter
+ * @since 4.1
*
* Gets a pointer to a function that can get a key on the given Variant type.
*
@@ -1159,6 +1213,7 @@ typedef GDExtensionPtrKeyedGetter (*GDExtensionInterfaceVariantGetPtrKeyedGetter
/**
* @name variant_get_ptr_keyed_checker
+ * @since 4.1
*
* Gets a pointer to a function that can check a key on the given Variant type.
*
@@ -1170,6 +1225,7 @@ typedef GDExtensionPtrKeyedChecker (*GDExtensionInterfaceVariantGetPtrKeyedCheck
/**
* @name variant_get_constant_value
+ * @since 4.1
*
* Gets the value of a constant from the given Variant type.
*
@@ -1181,6 +1237,7 @@ typedef void (*GDExtensionInterfaceVariantGetConstantValue)(GDExtensionVariantTy
/**
* @name variant_get_ptr_utility_function
+ * @since 4.1
*
* Gets a pointer to a function that can call a Variant utility function.
*
@@ -1195,6 +1252,7 @@ typedef GDExtensionPtrUtilityFunction (*GDExtensionInterfaceVariantGetPtrUtility
/**
* @name string_new_with_latin1_chars
+ * @since 4.1
*
* Creates a String from a Latin-1 encoded C string.
*
@@ -1205,6 +1263,7 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1Chars)(GDExtensionUninitia
/**
* @name string_new_with_utf8_chars
+ * @since 4.1
*
* Creates a String from a UTF-8 encoded C string.
*
@@ -1215,6 +1274,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf8Chars)(GDExtensionUninitiali
/**
* @name string_new_with_utf16_chars
+ * @since 4.1
*
* Creates a String from a UTF-16 encoded C string.
*
@@ -1225,6 +1285,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf16Chars)(GDExtensionUninitial
/**
* @name string_new_with_utf32_chars
+ * @since 4.1
*
* Creates a String from a UTF-32 encoded C string.
*
@@ -1235,6 +1296,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf32Chars)(GDExtensionUninitial
/**
* @name string_new_with_wide_chars
+ * @since 4.1
*
* Creates a String from a wide C string.
*
@@ -1245,6 +1307,7 @@ typedef void (*GDExtensionInterfaceStringNewWithWideChars)(GDExtensionUninitiali
/**
* @name string_new_with_latin1_chars_and_len
+ * @since 4.1
*
* Creates a String from a Latin-1 encoded C string with the given length.
*
@@ -1256,6 +1319,7 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1CharsAndLen)(GDExtensionUn
/**
* @name string_new_with_utf8_chars_and_len
+ * @since 4.1
*
* Creates a String from a UTF-8 encoded C string with the given length.
*
@@ -1267,6 +1331,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen)(GDExtensionUnin
/**
* @name string_new_with_utf16_chars_and_len
+ * @since 4.1
*
* Creates a String from a UTF-16 encoded C string with the given length.
*
@@ -1278,6 +1343,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen)(GDExtensionUni
/**
* @name string_new_with_utf32_chars_and_len
+ * @since 4.1
*
* Creates a String from a UTF-32 encoded C string with the given length.
*
@@ -1289,6 +1355,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf32CharsAndLen)(GDExtensionUni
/**
* @name string_new_with_wide_chars_and_len
+ * @since 4.1
*
* Creates a String from a wide C string with the given length.
*
@@ -1300,6 +1367,7 @@ typedef void (*GDExtensionInterfaceStringNewWithWideCharsAndLen)(GDExtensionUnin
/**
* @name string_to_latin1_chars
+ * @since 4.1
*
* Converts a String to a Latin-1 encoded C string.
*
@@ -1315,6 +1383,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToLatin1Chars)(GDExtensionCon
/**
* @name string_to_utf8_chars
+ * @since 4.1
*
* Converts a String to a UTF-8 encoded C string.
*
@@ -1330,6 +1399,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf8Chars)(GDExtensionConst
/**
* @name string_to_utf16_chars
+ * @since 4.1
*
* Converts a String to a UTF-16 encoded C string.
*
@@ -1345,6 +1415,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf16Chars)(GDExtensionCons
/**
* @name string_to_utf32_chars
+ * @since 4.1
*
* Converts a String to a UTF-32 encoded C string.
*
@@ -1360,6 +1431,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf32Chars)(GDExtensionCons
/**
* @name string_to_wide_chars
+ * @since 4.1
*
* Converts a String to a wide C string.
*
@@ -1375,6 +1447,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToWideChars)(GDExtensionConst
/**
* @name string_operator_index
+ * @since 4.1
*
* Gets a pointer to the character at the given index from a String.
*
@@ -1387,6 +1460,7 @@ typedef char32_t *(*GDExtensionInterfaceStringOperatorIndex)(GDExtensionStringPt
/**
* @name string_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to the character at the given index from a String.
*
@@ -1399,6 +1473,7 @@ typedef const char32_t *(*GDExtensionInterfaceStringOperatorIndexConst)(GDExtens
/**
* @name string_operator_plus_eq_string
+ * @since 4.1
*
* Appends another String to a String.
*
@@ -1409,6 +1484,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqString)(GDExtensionString
/**
* @name string_operator_plus_eq_char
+ * @since 4.1
*
* Appends a character to a String.
*
@@ -1419,6 +1495,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqChar)(GDExtensionStringPt
/**
* @name string_operator_plus_eq_cstr
+ * @since 4.1
*
* Appends a Latin-1 encoded C string to a String.
*
@@ -1429,6 +1506,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqCstr)(GDExtensionStringPt
/**
* @name string_operator_plus_eq_wcstr
+ * @since 4.1
*
* Appends a wide C string to a String.
*
@@ -1439,6 +1517,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqWcstr)(GDExtensionStringP
/**
* @name string_operator_plus_eq_c32str
+ * @since 4.1
*
* Appends a UTF-32 encoded C string to a String.
*
@@ -1451,6 +1530,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqC32str)(GDExtensionString
/**
* @name xml_parser_open_buffer
+ * @since 4.1
*
* Opens a raw XML buffer on an XMLParser instance.
*
@@ -1468,6 +1548,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceXmlParserOpenBuffer)(GDExtensionObj
/**
* @name file_access_store_buffer
+ * @since 4.1
*
* Stores the given buffer using an instance of FileAccess.
*
@@ -1481,6 +1562,7 @@ typedef void (*GDExtensionInterfaceFileAccessStoreBuffer)(GDExtensionObjectPtr p
/**
* @name file_access_get_buffer
+ * @since 4.1
*
* Reads the next p_length bytes into the given buffer using an instance of FileAccess.
*
@@ -1496,6 +1578,7 @@ typedef uint64_t (*GDExtensionInterfaceFileAccessGetBuffer)(GDExtensionConstObje
/**
* @name worker_thread_pool_add_native_group_task
+ * @since 4.1
*
* Adds a group task to an instance of WorkerThreadPool.
*
@@ -1514,6 +1597,7 @@ typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask)(GDExte
/**
* @name worker_thread_pool_add_native_task
+ * @since 4.1
*
* Adds a task to an instance of WorkerThreadPool.
*
@@ -1531,6 +1615,7 @@ typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeTask)(GDExtension
/**
* @name packed_byte_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a byte in a PackedByteArray.
*
@@ -1543,6 +1628,7 @@ typedef uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndex)(GDExtension
/**
* @name packed_byte_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a byte in a PackedByteArray.
*
@@ -1555,6 +1641,7 @@ typedef const uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndexConst)(
/**
* @name packed_color_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a color in a PackedColorArray.
*
@@ -1567,6 +1654,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndex)(
/**
* @name packed_color_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a color in a PackedColorArray.
*
@@ -1579,6 +1667,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndexCo
/**
* @name packed_float32_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a 32-bit float in a PackedFloat32Array.
*
@@ -1591,6 +1680,7 @@ typedef float *(*GDExtensionInterfacePackedFloat32ArrayOperatorIndex)(GDExtensio
/**
* @name packed_float32_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a 32-bit float in a PackedFloat32Array.
*
@@ -1603,6 +1693,7 @@ typedef const float *(*GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst)
/**
* @name packed_float64_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a 64-bit float in a PackedFloat64Array.
*
@@ -1615,6 +1706,7 @@ typedef double *(*GDExtensionInterfacePackedFloat64ArrayOperatorIndex)(GDExtensi
/**
* @name packed_float64_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a 64-bit float in a PackedFloat64Array.
*
@@ -1627,6 +1719,7 @@ typedef const double *(*GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst
/**
* @name packed_int32_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a 32-bit integer in a PackedInt32Array.
*
@@ -1639,6 +1732,7 @@ typedef int32_t *(*GDExtensionInterfacePackedInt32ArrayOperatorIndex)(GDExtensio
/**
* @name packed_int32_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a 32-bit integer in a PackedInt32Array.
*
@@ -1651,6 +1745,7 @@ typedef const int32_t *(*GDExtensionInterfacePackedInt32ArrayOperatorIndexConst)
/**
* @name packed_int64_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a 64-bit integer in a PackedInt64Array.
*
@@ -1663,6 +1758,7 @@ typedef int64_t *(*GDExtensionInterfacePackedInt64ArrayOperatorIndex)(GDExtensio
/**
* @name packed_int64_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a 64-bit integer in a PackedInt64Array.
*
@@ -1675,6 +1771,7 @@ typedef const int64_t *(*GDExtensionInterfacePackedInt64ArrayOperatorIndexConst)
/**
* @name packed_string_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a string in a PackedStringArray.
*
@@ -1687,6 +1784,7 @@ typedef GDExtensionStringPtr (*GDExtensionInterfacePackedStringArrayOperatorInde
/**
* @name packed_string_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a string in a PackedStringArray.
*
@@ -1699,6 +1797,7 @@ typedef GDExtensionStringPtr (*GDExtensionInterfacePackedStringArrayOperatorInde
/**
* @name packed_vector2_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a Vector2 in a PackedVector2Array.
*
@@ -1711,6 +1810,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector2ArrayOperatorIndex
/**
* @name packed_vector2_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a Vector2 in a PackedVector2Array.
*
@@ -1723,6 +1823,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector2ArrayOperatorIndex
/**
* @name packed_vector3_array_operator_index
+ * @since 4.1
*
* Gets a pointer to a Vector3 in a PackedVector3Array.
*
@@ -1735,6 +1836,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndex
/**
* @name packed_vector3_array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a Vector3 in a PackedVector3Array.
*
@@ -1747,6 +1849,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndex
/**
* @name array_operator_index
+ * @since 4.1
*
* Gets a pointer to a Variant in an Array.
*
@@ -1759,6 +1862,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceArrayOperatorIndex)(GDExtens
/**
* @name array_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a Variant in an Array.
*
@@ -1771,6 +1875,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceArrayOperatorIndexConst)(GDE
/**
* @name array_ref
+ * @since 4.1
*
* Sets an Array to be a reference to another Array object.
*
@@ -1781,6 +1886,7 @@ typedef void (*GDExtensionInterfaceArrayRef)(GDExtensionTypePtr p_self, GDExtens
/**
* @name array_set_typed
+ * @since 4.1
*
* Makes an Array into a typed Array.
*
@@ -1795,6 +1901,7 @@ typedef void (*GDExtensionInterfaceArraySetTyped)(GDExtensionTypePtr p_self, GDE
/**
* @name dictionary_operator_index
+ * @since 4.1
*
* Gets a pointer to a Variant in a Dictionary with the given key.
*
@@ -1807,6 +1914,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndex)(GDE
/**
* @name dictionary_operator_index_const
+ * @since 4.1
*
* Gets a const pointer to a Variant in a Dictionary with the given key.
*
@@ -1821,6 +1929,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndexConst
/**
* @name object_method_bind_call
+ * @since 4.1
*
* Calls a method on an Object.
*
@@ -1835,6 +1944,7 @@ typedef void (*GDExtensionInterfaceObjectMethodBindCall)(GDExtensionMethodBindPt
/**
* @name object_method_bind_ptrcall
+ * @since 4.1
*
* Calls a method on an Object (using a "ptrcall").
*
@@ -1847,6 +1957,7 @@ typedef void (*GDExtensionInterfaceObjectMethodBindPtrcall)(GDExtensionMethodBin
/**
* @name object_destroy
+ * @since 4.1
*
* Destroys an Object.
*
@@ -1856,6 +1967,7 @@ typedef void (*GDExtensionInterfaceObjectDestroy)(GDExtensionObjectPtr p_o);
/**
* @name global_get_singleton
+ * @since 4.1
*
* Gets a global singleton by name.
*
@@ -1867,6 +1979,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceGlobalGetSingleton)(GDExtensi
/**
* @name object_get_instance_binding
+ * @since 4.1
*
* Gets a pointer representing an Object's instance binding.
*
@@ -1880,6 +1993,7 @@ typedef void *(*GDExtensionInterfaceObjectGetInstanceBinding)(GDExtensionObjectP
/**
* @name object_set_instance_binding
+ * @since 4.1
*
* Sets an Object's instance binding.
*
@@ -1892,6 +2006,7 @@ typedef void (*GDExtensionInterfaceObjectSetInstanceBinding)(GDExtensionObjectPt
/**
* @name object_set_instance
+ * @since 4.1
*
* Sets an extension class instance on a Object.
*
@@ -1903,6 +2018,7 @@ typedef void (*GDExtensionInterfaceObjectSetInstance)(GDExtensionObjectPtr p_o,
/**
* @name object_get_class_name
+ * @since 4.1
*
* Gets the class name of an Object.
*
@@ -1916,6 +2032,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceObjectGetClassName)(GDExtensionCon
/**
* @name object_cast_to
+ * @since 4.1
*
* Casts an Object to a different type.
*
@@ -1928,6 +2045,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectCastTo)(GDExtensionCons
/**
* @name object_get_instance_from_id
+ * @since 4.1
*
* Gets an Object by its instance ID.
*
@@ -1939,6 +2057,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectGetInstanceFromId)(GDOb
/**
* @name object_get_instance_id
+ * @since 4.1
*
* Gets the instance ID from an Object.
*
@@ -1952,6 +2071,7 @@ typedef GDObjectInstanceID (*GDExtensionInterfaceObjectGetInstanceId)(GDExtensio
/**
* @name ref_get_object
+ * @since 4.1
*
* Gets the Object from a reference.
*
@@ -1963,6 +2083,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceRefGetObject)(GDExtensionCons
/**
* @name ref_set_object
+ * @since 4.1
*
* Sets the Object referred to by a reference.
*
@@ -1975,6 +2096,7 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte
/**
* @name script_instance_create
+ * @since 4.1
*
* Creates a script instance that contains the given info and instance data.
*
@@ -1989,6 +2111,7 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)
/**
* @name classdb_construct_object
+ * @since 4.1
*
* Constructs an Object of the requested class.
*
@@ -2002,6 +2125,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject)(GDExt
/**
* @name classdb_get_method_bind
+ * @since 4.1
*
* Gets a pointer to the MethodBind in ClassDB for the given class, method and hash.
*
@@ -2015,6 +2139,7 @@ typedef GDExtensionMethodBindPtr (*GDExtensionInterfaceClassdbGetMethodBind)(GDE
/**
* @name classdb_get_class_tag
+ * @since 4.1
*
* Gets a pointer uniquely identifying the given built-in class in the ClassDB.
*
@@ -2028,6 +2153,7 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa
/**
* @name classdb_register_extension_class
+ * @since 4.1
*
* Registers an extension class in the ClassDB.
*
@@ -2042,6 +2168,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
/**
* @name classdb_register_extension_class_method
+ * @since 4.1
*
* Registers a method on an extension class in the ClassDB.
*
@@ -2055,6 +2182,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassMethod)(GDExtens
/**
* @name classdb_register_extension_class_integer_constant
+ * @since 4.1
*
* Registers an integer constant on an extension class in the ClassDB.
*
@@ -2069,6 +2197,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant)
/**
* @name classdb_register_extension_class_property
+ * @since 4.1
*
* Registers a property on an extension class in the ClassDB.
*
@@ -2084,6 +2213,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassProperty)(GDExte
/**
* @name classdb_register_extension_class_property_group
+ * @since 4.1
*
* Registers a property group on an extension class in the ClassDB.
*
@@ -2096,6 +2226,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup)(G
/**
* @name classdb_register_extension_class_property_subgroup
+ * @since 4.1
*
* Registers a property subgroup on an extension class in the ClassDB.
*
@@ -2108,6 +2239,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup
/**
* @name classdb_register_extension_class_signal
+ * @since 4.1
*
* Registers a signal on an extension class in the ClassDB.
*
@@ -2123,6 +2255,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassSignal)(GDExtens
/**
* @name classdb_unregister_extension_class
+ * @since 4.1
*
* Unregisters an extension class in the ClassDB.
*
@@ -2133,6 +2266,7 @@ typedef void (*GDExtensionInterfaceClassdbUnregisterExtensionClass)(GDExtensionC
/**
* @name get_library_path
+ * @since 4.1
*
* Gets the path to the current GDExtension library.
*
@@ -2143,6 +2277,7 @@ typedef void (*GDExtensionInterfaceGetLibraryPath)(GDExtensionClassLibraryPtr p_
/**
* @name editor_add_plugin
+ * @since 4.1
*
* Adds an editor plugin.
*
@@ -2154,6 +2289,7 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt
/**
* @name editor_remove_plugin
+ * @since 4.1
*
* Removes an editor plugin.
*
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 1348389481..d481acf005 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -113,6 +113,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
+ ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device);
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
@@ -297,10 +298,13 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con
return false;
}
+ // Backward compatibility for legacy behavior, only return true if currently pressed.
+ bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true;
+
if (Engine::get_singleton()->is_in_physics_frame()) {
- return E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames();
+ return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
- return E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames();
+ return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames();
}
}
@@ -315,10 +319,13 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co
return false;
}
+ // Backward compatibility for legacy behavior, only return true if currently released.
+ bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true;
+
if (Engine::get_singleton()->is_in_physics_frame()) {
- return !E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames();
+ return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
- return !E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames();
+ return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames();
}
}
@@ -686,19 +693,24 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) {
if (InputMap::get_singleton()->event_is_action(p_event, E.key)) {
+ Action &action = action_state[E.key];
// If not echo and action pressed state has changed
if (!p_event->is_echo() && is_action_pressed(E.key, false) != p_event->is_action_pressed(E.key)) {
- Action action;
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.process_frame = Engine::get_singleton()->get_process_frames();
- action.pressed = p_event->is_action_pressed(E.key);
+ if (p_event->is_action_pressed(E.key)) {
+ action.pressed = true;
+ action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
+ } else {
+ action.pressed = false;
+ action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ }
action.strength = 0.0f;
action.raw_strength = 0.0f;
action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
- action_state[E.key] = action;
}
- action_state[E.key].strength = p_event->get_action_strength(E.key);
- action_state[E.key].raw_strength = p_event->get_action_raw_strength(E.key);
+ action.strength = p_event->get_action_strength(E.key);
+ action.raw_strength = p_event->get_action_raw_strength(E.key);
}
}
@@ -813,29 +825,27 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
}
void Input::action_press(const StringName &p_action, float p_strength) {
- Action action;
+ // Create or retrieve existing action.
+ Action &action = action_state[p_action];
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.process_frame = Engine::get_singleton()->get_process_frames();
+ action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = true;
action.strength = p_strength;
action.raw_strength = p_strength;
action.exact = true;
-
- action_state[p_action] = action;
}
void Input::action_release(const StringName &p_action) {
- Action action;
+ // Create or retrieve existing action.
+ Action &action = action_state[p_action];
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.process_frame = Engine::get_singleton()->get_process_frames();
+ action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.released_process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = false;
- action.strength = 0.f;
- action.raw_strength = 0.f;
+ action.strength = 0.0f;
+ action.raw_strength = 0.0f;
action.exact = true;
-
- action_state[p_action] = action;
}
void Input::set_emulate_touch_from_mouse(bool p_emulate) {
@@ -1356,8 +1366,9 @@ void Input::parse_mapping(String p_mapping) {
String output = entry[idx].get_slice(":", 0).replace(" ", "");
String input = entry[idx].get_slice(":", 1).replace(" ", "");
- ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2,
- vformat("Invalid device mapping entry \"%s\" in mapping:\n%s", entry[idx], p_mapping));
+ if (output.length() < 1 || input.length() < 2) {
+ continue;
+ }
if (output == "platform" || output == "hint") {
continue;
@@ -1488,6 +1499,11 @@ String Input::get_joy_guid(int p_device) const {
return joy_names[p_device].uid;
}
+bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const {
+ uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id);
+ return ignored_device_ids.has(full_id);
+}
+
TypedArray<int> Input::get_connected_joypads() {
TypedArray<int> ret;
HashMap<int, Joypad>::Iterator elem = joy_names.begin();
@@ -1531,6 +1547,33 @@ Input::Input() {
parse_mapping(entries[i]);
}
}
+
+ String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES");
+ if (!env_ignore_devices.is_empty()) {
+ Vector<String> entries = env_ignore_devices.split(",");
+ for (int i = 0; i < entries.size(); i++) {
+ Vector<String> vid_pid = entries[i].split("/");
+
+ if (vid_pid.size() < 2) {
+ continue;
+ }
+
+ print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1]));
+ const uint16_t vid_unswapped = vid_pid[0].hex_to_int();
+ const uint16_t pid_unswapped = vid_pid[1].hex_to_int();
+ const uint16_t vid = BSWAP16(vid_unswapped);
+ const uint16_t pid = BSWAP16(pid_unswapped);
+
+ uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid);
+ ignored_device_ids.insert(full_id);
+ }
+ }
+
+ legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // Always use standard behavior in the editor.
+ legacy_just_pressed_behavior = false;
+ }
}
Input::~Input() {
diff --git a/core/input/input.h b/core/input/input.h
index c254650ef8..ec16871b72 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -96,14 +96,17 @@ private:
Vector3 gyroscope;
Vector2 mouse_pos;
int64_t mouse_window = 0;
+ bool legacy_just_pressed_behavior = false;
struct Action {
- uint64_t physics_frame;
- uint64_t process_frame;
- bool pressed;
- bool exact;
- float strength;
- float raw_strength;
+ uint64_t pressed_physics_frame = UINT64_MAX;
+ uint64_t pressed_process_frame = UINT64_MAX;
+ uint64_t released_physics_frame = UINT64_MAX;
+ uint64_t released_process_frame = UINT64_MAX;
+ bool pressed = false;
+ bool exact = true;
+ float strength = 0.0f;
+ float raw_strength = 0.0f;
};
HashMap<StringName, Action> action_state;
@@ -151,6 +154,9 @@ private:
VelocityTrack mouse_velocity_track;
HashMap<int, VelocityTrack> touch_velocity_track;
HashMap<int, Joypad> joy_names;
+
+ HashSet<uint32_t> ignored_device_ids;
+
int fallback_mapping = -1;
CursorShape default_shape = CURSOR_ARROW;
@@ -325,6 +331,7 @@ public:
bool is_joy_known(int p_device);
String get_joy_guid(int p_device) const;
+ bool should_ignore_device(int p_vendor_id, int p_product_id) const;
void set_fallback_mapping(String p_guid);
void flush_buffered_events();
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 95be01bc65..e37886cbe9 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -201,7 +201,7 @@ bool InputEventWithModifiers::is_alt_pressed() const {
}
void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) {
- ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Control directly!");
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Control directly!");
ctrl_pressed = p_enabled;
emit_changed();
}
@@ -211,7 +211,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const {
}
void InputEventWithModifiers::set_meta_pressed(bool p_enabled) {
- ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Meta directly!");
+ ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Meta directly!");
meta_pressed = p_enabled;
emit_changed();
}
@@ -1109,6 +1109,15 @@ String InputEventJoypadMotion::to_string() {
return vformat("InputEventJoypadMotion: axis=%d, axis_value=%.2f", axis, axis_value);
}
+Ref<InputEventJoypadMotion> InputEventJoypadMotion::create_reference(JoyAxis p_axis, float p_value) {
+ Ref<InputEventJoypadMotion> ie;
+ ie.instantiate();
+ ie->set_axis(p_axis);
+ ie->set_axis_value(p_value);
+
+ return ie;
+}
+
void InputEventJoypadMotion::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_axis", "axis"), &InputEventJoypadMotion::set_axis);
ClassDB::bind_method(D_METHOD("get_axis"), &InputEventJoypadMotion::get_axis);
@@ -1183,7 +1192,7 @@ static const char *_joy_button_descriptions[(size_t)JoyButton::SDL_MAX] = {
TTRC("Top Action, Sony Triangle, Xbox Y, Nintendo X"),
TTRC("Back, Sony Select, Xbox Back, Nintendo -"),
TTRC("Guide, Sony PS, Xbox Home"),
- TTRC("Start, Nintendo +"),
+ TTRC("Start, Xbox Menu, Nintendo +"),
TTRC("Left Stick, Sony L3, Xbox L/LS"),
TTRC("Right Stick, Sony R3, Xbox R/RS"),
TTRC("Left Shoulder, Sony L1, Xbox LB"),
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 59a87239bd..e9d4fb8325 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -319,6 +319,8 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
+ static Ref<InputEventJoypadMotion> create_reference(JoyAxis p_axis, float p_value);
+
InputEventJoypadMotion() {}
};
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 910778324c..ddfde0e7cd 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -399,21 +399,25 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::LEFT));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_LEFT));
+ inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, -1.0));
default_builtin_cache.insert("ui_left", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::RIGHT));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_RIGHT));
+ inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, 1.0));
default_builtin_cache.insert("ui_right", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::UP));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_UP));
+ inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, -1.0));
default_builtin_cache.insert("ui_up", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::DOWN));
inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_DOWN));
+ inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, 1.0));
default_builtin_cache.insert("ui_down", inputs);
inputs = List<Ref<InputEvent>>();
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index ac4a637597..e36fb0afa4 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -35,13 +35,13 @@
#include "thirdparty/misc/fastlz.h"
-#ifdef BROTLI_ENABLED
-#include "thirdparty/brotli/include/brotli/decode.h"
-#endif
-
#include <zlib.h>
#include <zstd.h>
+#ifdef BROTLI_ENABLED
+#include <brotli/decode.h>
+#endif
+
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {
switch (p_mode) {
case MODE_BROTLI: {
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index a6a1a224b3..b669afdc99 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -441,6 +441,11 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
current += c;
}
}
+
+ if (in_quote) {
+ WARN_PRINT(vformat("Reached end of file before closing '\"' in CSV file '%s'.", get_path()));
+ }
+
strings.push_back(current);
return strings;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 88a906a38e..74c5c1c191 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -48,7 +48,8 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t
}
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
- PathMD5 pmd5(p_path.md5_buffer());
+ String simplified_path = p_path.simplify_path();
+ PathMD5 pmd5(simplified_path.md5_buffer());
bool exists = files.has(pmd5);
@@ -68,7 +69,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
if (!exists) {
//search for dir
- String p = p_path.replace_first("res://", "");
+ String p = simplified_path.replace_first("res://", "");
PackedDir *cd = root;
if (p.contains("/")) { //in a subdir
@@ -87,7 +88,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
}
}
}
- String filename = p_path.get_file();
+ String filename = simplified_path.get_file();
// Don't add as a file if the path points to a directory
if (!filename.is_empty()) {
cd->files.insert(filename);
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 8bfabc9529..1538b302c2 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -184,7 +184,8 @@ public:
};
Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
- PathMD5 pmd5(p_path.md5_buffer());
+ String simplified_path = p_path.simplify_path();
+ PathMD5 pmd5(simplified_path.md5_buffer());
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
if (!E) {
return nullptr; //not found
@@ -197,7 +198,7 @@ Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
}
bool PackedData::has_path(const String &p_path) {
- return files.has(PathMD5(p_path.md5_buffer()));
+ return files.has(PathMD5(p_path.simplify_path().md5_buffer()));
}
bool PackedData::has_directory(const String &p_path) {
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 064353476f..c7f1a73f97 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -47,7 +47,7 @@ static void *godot_open(voidpf opaque, const char *p_fname, int mode) {
return nullptr;
}
- Ref<FileAccess> f = FileAccess::open(p_fname, FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(String::utf8(p_fname), FileAccess::READ);
ERR_FAIL_COND_V(f.is_null(), nullptr);
ZipData *zd = memnew(ZipData);
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 9bb987b670..7326563f18 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -517,21 +517,31 @@ void Image::convert(Format p_new_format) {
return;
}
+ // Includes the main image.
+ const int mipmap_count = get_mipmap_count() + 1;
+
if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) {
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
} else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) {
//use put/set pixel which is slower but works with non byte formats
- Image new_img(width, height, false, p_new_format);
+ Image new_img(width, height, mipmaps, p_new_format);
- for (int i = 0; i < width; i++) {
- for (int j = 0; j < height; j++) {
- new_img.set_pixel(i, j, get_pixel(i, j));
+ for (int mip = 0; mip < mipmap_count; mip++) {
+ Ref<Image> src_mip = get_image_from_mipmap(mip);
+ Ref<Image> new_mip = new_img.get_image_from_mipmap(mip);
+
+ for (int y = 0; y < src_mip->height; y++) {
+ for (int x = 0; x < src_mip->width; x++) {
+ new_mip->set_pixel(x, y, src_mip->get_pixel(x, y));
+ }
}
- }
- if (has_mipmaps()) {
- new_img.generate_mipmaps();
+ int mip_offset = 0;
+ int mip_size = 0;
+ new_img.get_mipmap_offset_and_size(mip, mip_offset, mip_size);
+
+ memcpy(new_img.data.ptrw() + mip_offset, new_mip->data.ptr(), mip_size);
}
_copy_internals_from(new_img);
@@ -539,113 +549,115 @@ void Image::convert(Format p_new_format) {
return;
}
- Image new_img(width, height, false, p_new_format);
-
- const uint8_t *rptr = data.ptr();
- uint8_t *wptr = new_img.data.ptrw();
+ Image new_img(width, height, mipmaps, p_new_format);
int conversion_type = format | p_new_format << 8;
- switch (conversion_type) {
- case FORMAT_L8 | (FORMAT_LA8 << 8):
- _convert<1, false, 1, true, true, true>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_R8 << 8):
- _convert<1, false, 1, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RG8 << 8):
- _convert<1, false, 2, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RGB8 << 8):
- _convert<1, false, 3, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_L8 | (FORMAT_RGBA8 << 8):
- _convert<1, false, 3, true, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_L8 << 8):
- _convert<1, true, 1, false, true, true>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_R8 << 8):
- _convert<1, true, 1, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RG8 << 8):
- _convert<1, true, 2, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RGB8 << 8):
- _convert<1, true, 3, false, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_LA8 | (FORMAT_RGBA8 << 8):
- _convert<1, true, 3, true, true, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_L8 << 8):
- _convert<1, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_LA8 << 8):
- _convert<1, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RG8 << 8):
- _convert<1, false, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RGB8 << 8):
- _convert<1, false, 3, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_R8 | (FORMAT_RGBA8 << 8):
- _convert<1, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_L8 << 8):
- _convert<2, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_LA8 << 8):
- _convert<2, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_R8 << 8):
- _convert<2, false, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_RGB8 << 8):
- _convert<2, false, 3, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RG8 | (FORMAT_RGBA8 << 8):
- _convert<2, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_L8 << 8):
- _convert<3, false, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_LA8 << 8):
- _convert<3, false, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_R8 << 8):
- _convert<3, false, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_RG8 << 8):
- _convert<3, false, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGB8 | (FORMAT_RGBA8 << 8):
- _convert<3, false, 3, true, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_L8 << 8):
- _convert<3, true, 1, false, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_LA8 << 8):
- _convert<3, true, 1, true, false, true>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_R8 << 8):
- _convert<3, true, 1, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_RG8 << 8):
- _convert<3, true, 2, false, false, false>(width, height, rptr, wptr);
- break;
- case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
- _convert<3, true, 3, false, false, false>(width, height, rptr, wptr);
- break;
- }
-
- bool gen_mipmaps = mipmaps;
+ for (int mip = 0; mip < mipmap_count; mip++) {
+ int mip_offset = 0;
+ int mip_size = 0;
+ int mip_width = 0;
+ int mip_height = 0;
+ get_mipmap_offset_size_and_dimensions(mip, mip_offset, mip_size, mip_width, mip_height);
- _copy_internals_from(new_img);
+ const uint8_t *rptr = data.ptr() + mip_offset;
+ uint8_t *wptr = new_img.data.ptrw() + new_img.get_mipmap_offset(mip);
- if (gen_mipmaps) {
- generate_mipmaps();
+ switch (conversion_type) {
+ case FORMAT_L8 | (FORMAT_LA8 << 8):
+ _convert<1, false, 1, true, true, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_R8 << 8):
+ _convert<1, false, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RG8 << 8):
+ _convert<1, false, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RGB8 << 8):
+ _convert<1, false, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_L8 | (FORMAT_RGBA8 << 8):
+ _convert<1, false, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_L8 << 8):
+ _convert<1, true, 1, false, true, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_R8 << 8):
+ _convert<1, true, 1, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RG8 << 8):
+ _convert<1, true, 2, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RGB8 << 8):
+ _convert<1, true, 3, false, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_LA8 | (FORMAT_RGBA8 << 8):
+ _convert<1, true, 3, true, true, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_L8 << 8):
+ _convert<1, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_LA8 << 8):
+ _convert<1, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RG8 << 8):
+ _convert<1, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RGB8 << 8):
+ _convert<1, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_R8 | (FORMAT_RGBA8 << 8):
+ _convert<1, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_L8 << 8):
+ _convert<2, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_LA8 << 8):
+ _convert<2, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_R8 << 8):
+ _convert<2, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_RGB8 << 8):
+ _convert<2, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RG8 | (FORMAT_RGBA8 << 8):
+ _convert<2, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_L8 << 8):
+ _convert<3, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_LA8 << 8):
+ _convert<3, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_R8 << 8):
+ _convert<3, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_RG8 << 8):
+ _convert<3, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGB8 | (FORMAT_RGBA8 << 8):
+ _convert<3, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_L8 << 8):
+ _convert<3, true, 1, false, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_LA8 << 8):
+ _convert<3, true, 1, true, false, true>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_R8 << 8):
+ _convert<3, true, 1, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_RG8 << 8):
+ _convert<3, true, 2, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ case FORMAT_RGBA8 | (FORMAT_RGB8 << 8):
+ _convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr);
+ break;
+ }
}
+
+ _copy_internals_from(new_img);
}
Image::Format Image::get_format() const {
@@ -3004,6 +3016,7 @@ ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
+ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
@@ -3476,6 +3489,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
BIND_CONSTANT(MAX_WIDTH);
@@ -3825,6 +3841,28 @@ Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _bmp_mem_loader_func);
}
+Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) {
+ ERR_FAIL_NULL_V_MSG(
+ _svg_scalable_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The SVG module isn't enabled. Recompile the Godot editor or export template binary with the `module_svg_enabled=yes` SCons option.");
+
+ int buffer_size = p_array.size();
+
+ ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
+
+ Ref<Image> image = _svg_scalable_mem_loader_func(p_array.ptr(), buffer_size, scale);
+ ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
+
+ copy_internals_from(image);
+
+ return OK;
+}
+
+Error Image::load_svg_from_string(const String &p_svg_str, float scale) {
+ return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale);
+}
+
void Image::convert_rg_to_ra_rgba8() {
ERR_FAIL_COND(format != FORMAT_RGBA8);
ERR_FAIL_COND(!data.size());
diff --git a/core/io/image.h b/core/io/image.h
index 8e353a8bb7..f877b00ee6 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -48,6 +48,7 @@ typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
+typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
@@ -148,6 +149,7 @@ public:
static ImageMemLoadFunc _webp_mem_loader_func;
static ImageMemLoadFunc _tga_mem_loader_func;
static ImageMemLoadFunc _bmp_mem_loader_func;
+ static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
@@ -401,6 +403,9 @@ public:
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
+ Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);
+
void convert_rg_to_ra_rgba8();
void convert_ra_rgba8_to_rg();
void convert_rgba8_to_bgra8();
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 65728f34f6..772f700916 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -35,8 +35,6 @@
#include "core/templates/hash_map.h"
#include "core/variant/typed_array.h"
-VARIANT_ENUM_CAST(IP::ResolverStatus);
-
/************* RESOLVER ******************/
struct _IP_ResolverPrivate {
diff --git a/core/io/ip.h b/core/io/ip.h
index b768f0b9d4..4816d59ac2 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -109,5 +109,6 @@ public:
};
VARIANT_ENUM_CAST(IP::Type);
+VARIANT_ENUM_CAST(IP::ResolverStatus);
#endif // IP_H
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a6e054a9fe..496400a5ea 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -299,9 +299,15 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
}
} break;
- default: {
+ case '"':
+ case '\\':
+ case '/': {
res = next;
} break;
+ default: {
+ r_err_str = "Invalid escape sequence.";
+ return ERR_PARSE_ERROR;
+ }
}
str += res;
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index e7f4980e94..9b49cc3d8c 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -115,7 +115,9 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr
}
File pf;
- pf.path = p_file;
+ // Simplify path here and on every 'files' access so that paths that have extra '/'
+ // symbols in them still match to the MD5 hash for the saved path.
+ pf.path = p_file.simplify_path();
pf.src_path = p_src;
pf.ofs = ofs;
pf.size = f->get_length();
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index b4da314e96..3037f603c4 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -920,8 +920,11 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p
for (int i = 0; i < external_resources.size(); i++) {
String dep;
+ String fallback_path;
+
if (external_resources[i].uid != ResourceUID::INVALID_ID) {
dep = ResourceUID::get_singleton()->id_to_text(external_resources[i].uid);
+ fallback_path = external_resources[i].path; // Used by Dependency Editor, in case uid path fails.
} else {
dep = external_resources[i].path;
}
@@ -929,6 +932,12 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p
if (p_add_types && !external_resources[i].type.is_empty()) {
dep += "::" + external_resources[i].type;
}
+ if (!fallback_path.is_empty()) {
+ if (!p_add_types) {
+ dep += "::"; // Ensure that path comes third, even if there is no type.
+ }
+ dep += "::" + fallback_path;
+ }
p_dependencies->push_back(dep);
}
@@ -1766,9 +1775,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::OBJECT: {
f->store_32(VARIANT_OBJECT);
Ref<Resource> res = p_property;
- if (res.is_null()) {
+ if (res.is_null() || res->get_meta(SNAME("_skip_save_"), false)) {
f->store_32(OBJECT_EMPTY);
- return; // don't save it
+ return; // Don't save it.
}
if (!res->is_built_in()) {
@@ -1933,7 +1942,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
case Variant::OBJECT: {
Ref<Resource> res = p_variant;
- if (res.is_null() || external_resources.has(res)) {
+ if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) {
return;
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index dc1de6b9ce..fcf4a727ca 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -394,6 +394,15 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String
return Ref<ResourceImporter>();
}
+void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) {
+ ERR_FAIL_COND(p_importer.is_null());
+ if (p_first_priority) {
+ importers.insert(0, p_importer);
+ } else {
+ importers.push_back(p_importer);
+ }
+}
+
void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers) {
for (int i = 0; i < importers.size(); i++) {
List<String> local_exts;
@@ -472,20 +481,13 @@ ResourceFormatImporter::ResourceFormatImporter() {
singleton = this;
}
+//////////////
+
void ResourceImporter::_bind_methods() {
BIND_ENUM_CONSTANT(IMPORT_ORDER_DEFAULT);
BIND_ENUM_CONSTANT(IMPORT_ORDER_SCENE);
}
-void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) {
- ERR_FAIL_COND(p_importer.is_null());
- if (p_first_priority) {
- importers.insert(0, p_importer);
- } else {
- importers.push_back(p_importer);
- }
-}
-
/////
Error ResourceFormatImporterSaver::set_uid(const String &p_path, ResourceUID::ID p_uid) {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index ac1870fe88..1fe662b1fa 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -239,15 +239,15 @@ ResourceLoader::LoadToken::~LoadToken() {
Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
load_nesting++;
- if (load_paths_stack.size()) {
+ if (load_paths_stack->size()) {
thread_load_mutex.lock();
- HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack[load_paths_stack.size() - 1]);
+ HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1));
if (E) {
E->value.sub_tasks.insert(p_path);
}
thread_load_mutex.unlock();
}
- load_paths_stack.push_back(p_path);
+ load_paths_stack->push_back(p_path);
// Try all loaders and pick the first match for the type hint
bool found = false;
@@ -263,7 +263,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
}
}
- load_paths_stack.resize(load_paths_stack.size() - 1);
+ load_paths_stack->resize(load_paths_stack->size() - 1);
load_nesting--;
if (!res.is_null()) {
@@ -296,8 +296,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
// Thread-safe either if it's the current thread or a brand new one.
CallQueue *mq_override = nullptr;
if (load_nesting == 0) {
+ load_paths_stack = memnew(Vector<String>);
+
if (!load_task.dependent_path.is_empty()) {
- load_paths_stack.push_back(load_task.dependent_path);
+ load_paths_stack->push_back(load_task.dependent_path);
}
if (!Thread::is_main_thread()) {
mq_override = memnew(CallQueue);
@@ -309,6 +311,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
}
// --
+ if (!Thread::is_main_thread()) {
+ set_current_thread_safe_for_nodes(true);
+ }
+
Ref<Resource> res = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
if (mq_override) {
mq_override->flush();
@@ -356,9 +362,11 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex.unlock();
- if (load_nesting == 0 && mq_override) {
- memdelete(mq_override);
- set_current_thread_safe_for_nodes(false);
+ if (load_nesting == 0) {
+ if (mq_override) {
+ memdelete(mq_override);
+ }
+ memdelete(load_paths_stack);
}
}
@@ -1167,7 +1175,7 @@ bool ResourceLoader::timestamp_on_load = false;
thread_local int ResourceLoader::load_nesting = 0;
thread_local WorkerThreadPool::TaskID ResourceLoader::caller_task_id = 0;
-thread_local Vector<String> ResourceLoader::load_paths_stack;
+thread_local Vector<String> *ResourceLoader::load_paths_stack;
template <>
thread_local uint32_t SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG>::count = 0;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 592befb603..2701caa3f4 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -182,7 +182,7 @@ private:
static thread_local int load_nesting;
static thread_local WorkerThreadPool::TaskID caller_task_id;
- static thread_local Vector<String> load_paths_stack;
+ static thread_local Vector<String> *load_paths_stack; // A pointer to avoid broken TLS implementations from double-running the destructor.
static SafeBinaryMutex<BINARY_MUTEX_TAG> thread_load_mutex;
static HashMap<String, ThreadLoadTask> thread_load_tasks;
static bool cleaning_tasks;
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 5c0a017bfc..958734addf 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -34,8 +34,6 @@
//#define DEBUG_XML
-VARIANT_ENUM_CAST(XMLParser::NodeType);
-
static inline bool _is_white_space(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index b96478c7a5..77df99a881 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -126,4 +126,6 @@ public:
~XMLParser();
};
+VARIANT_ENUM_CAST(XMLParser::NodeType);
+
#endif // XML_PARSER_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 1481dbc32e..6b0ecadc7f 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -397,7 +397,7 @@ void Basis::rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction)
real_t dot = p_start_direction.dot(p_end_direction);
dot = CLAMP(dot, -1.0f, 1.0f);
const real_t angle_rads = Math::acos(dot);
- set_axis_angle(axis, angle_rads);
+ *this = Basis(axis, angle_rads) * (*this);
}
}
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 76b3062944..f8456ec998 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -658,7 +658,7 @@ private:
Vector3 get_gd_normal(Face *p_face);
- bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack);
+ bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack);
public:
~ConvexHullInternal() {
@@ -1775,7 +1775,7 @@ real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) {
return p_amount;
}
-bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack) {
+bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack) {
Vector3 orig_shift = get_gd_normal(p_face) * -p_amount;
if (scaling[0] != 0) {
orig_shift[0] /= scaling[0];
diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h
index cf7ba8d48e..fc70724308 100644
--- a/core/math/delaunay_2d.h
+++ b/core/math/delaunay_2d.h
@@ -145,7 +145,7 @@ public:
// Filter out the triangles containing vertices of the bounding triangle.
int preserved_count = 0;
Triangle *triangles_ptrw = triangles.ptrw();
- for (int i = 0; i < triangles.size() - 1; i++) {
+ for (int i = 0; i < triangles.size(); i++) {
if (!(triangles[i].points[0] >= point_count || triangles[i].points[1] >= point_count || triangles[i].points[2] >= point_count)) {
triangles_ptrw[preserved_count] = triangles[i];
preserved_count++;
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 99694d7871..6b9bcea081 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -98,13 +98,11 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
Vector3 segment = p_dir;
real_t den = normal.dot(segment);
- //printf("den is %i\n",den);
if (Math::is_zero_approx(den)) {
return false;
}
real_t dist = (normal.dot(p_from) - d) / den;
- //printf("dist is %i\n",dist);
if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist
@@ -121,13 +119,11 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
Vector3 segment = p_begin - p_end;
real_t den = normal.dot(segment);
- //printf("den is %i\n",den);
if (Math::is_zero_approx(den)) {
return false;
}
real_t dist = (normal.dot(p_begin) - d) / den;
- //printf("dist is %i\n",dist);
if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) {
return false;
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 18f27ae4a4..5be9650b32 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -154,7 +154,6 @@ def generate_version(argcount, const=False, returns=False):
def run(target, source, env):
-
max_versions = 12
txt = """
@@ -165,7 +164,6 @@ def run(target, source, env):
"""
for i in range(max_versions + 1):
-
txt += "/* " + str(i) + " Arguments */\n\n"
txt += generate_version(i, False, False)
txt += generate_version(i, False, True)
diff --git a/core/object/object.cpp b/core/object/object.cpp
index d6937539c7..4d19a2c75b 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -836,14 +836,16 @@ void Object::set_script(const Variant &p_script) {
return;
}
+ Ref<Script> s = p_script;
+ ERR_FAIL_COND_MSG(s.is_null() && !p_script.is_null(), "Invalid parameter, it should be a reference to a valid script (or null).");
+
+ script = p_script;
+
if (script_instance) {
memdelete(script_instance);
script_instance = nullptr;
}
- script = p_script;
- Ref<Script> s = script;
-
if (!s.is_null()) {
if (s->can_instantiate()) {
OBJ_DEBUG_LOCK
@@ -1719,6 +1721,30 @@ uint32_t Object::get_edited_version() const {
}
#endif
+StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
+ // Only return the class name per the extension if it matches the given p_library.
+ if (_extension && _extension->library == p_library) {
+ return _extension->class_name;
+ }
+
+ // Extensions only have wrapper classes for classes exposed in ClassDB.
+ const StringName *class_name = _get_class_namev();
+ if (ClassDB::is_class_exposed(*class_name)) {
+ return *class_name;
+ }
+
+ // Find the nearest parent class that's exposed.
+ StringName parent_class = ClassDB::get_parent_class(*class_name);
+ while (parent_class != StringName()) {
+ if (ClassDB::is_class_exposed(parent_class)) {
+ return parent_class;
+ }
+ parent_class = ClassDB::get_parent_class(parent_class);
+ }
+
+ return SNAME("Object");
+}
+
void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
// This is only meant to be used on creation by the binder.
ERR_FAIL_COND(_instance_bindings != nullptr);
diff --git a/core/object/object.h b/core/object/object.h
index 6f626b0ed0..a3e9d025ea 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -800,17 +800,7 @@ public:
return *_class_name_ptr;
}
- _FORCE_INLINE_ const StringName &get_class_name_for_extension(const GDExtension *p_library) const {
- // Only return the class name per the extension if it matches the given p_library.
- if (_extension && _extension->library == p_library) {
- return _extension->class_name;
- }
- // Otherwise, return the name of the built-in class.
- if (unlikely(!_class_name_ptr)) {
- return *_get_class_namev();
- }
- return *_class_name_ptr;
- }
+ StringName get_class_name_for_extension(const GDExtension *p_library) const;
/* IAPI */
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 58706fb9a9..3386514706 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -242,8 +242,11 @@ public:
template <class T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
+ if (p_ptr == nullptr) {
+ return Ref<T>();
+ }
// p_ptr points to a RefCounted object
- return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr)));
+ return Ref<T>(const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr)));
}
typedef Ref<T> EncodeT;
@@ -259,8 +262,11 @@ struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
+ if (p_ptr == nullptr) {
+ return Ref<T>();
+ }
// p_ptr points to a RefCounted object
- return Ref<T>((T *)p_ptr);
+ return Ref<T>(*((T *const *)p_ptr));
}
};
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 71f40660f4..a8b0e426ae 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -34,7 +34,6 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
-#include "core/variant/typed_array.h"
#include <stdint.h>
@@ -43,7 +42,7 @@ int ScriptServer::_language_count = 0;
bool ScriptServer::scripting_enabled = true;
bool ScriptServer::reload_scripts_on_save = false;
-bool ScriptServer::languages_finished = false;
+SafeFlag ScriptServer::languages_finished; // Used until GH-76581 is fixed properly.
ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr;
void Script::_notification(int p_what) {
@@ -229,7 +228,7 @@ void ScriptServer::finish_languages() {
_languages[i]->finish();
}
global_classes_clear();
- languages_finished = true;
+ languages_finished.set();
}
void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
@@ -241,12 +240,18 @@ bool ScriptServer::is_reload_scripts_on_save_enabled() {
}
void ScriptServer::thread_enter() {
+ if (!languages_finished.is_set()) {
+ return;
+ }
for (int i = 0; i < _language_count; i++) {
_languages[i]->thread_enter();
}
}
void ScriptServer::thread_exit() {
+ if (!languages_finished.is_set()) {
+ return;
+ }
for (int i = 0; i < _language_count; i++) {
_languages[i]->thread_exit();
}
@@ -461,6 +466,52 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const
void ScriptLanguage::frame() {
}
+TypedArray<int> ScriptLanguage::CodeCompletionOption::get_option_characteristics(const String &p_base) {
+ // Return characacteristics of the match found by order of importance.
+ // Matches will be ranked by a lexicographical order on the vector returned by this function.
+ // The lower values indicate better matches and that they should go before in the order of appearance.
+ if (last_matches == matches) {
+ return charac;
+ }
+ charac.clear();
+ // Ensure base is not empty and at the same time that matches is not empty too.
+ if (p_base.length() == 0) {
+ last_matches = matches;
+ charac.push_back(location);
+ return charac;
+ }
+ charac.push_back(matches.size());
+ charac.push_back((matches[0].first == 0) ? 0 : 1);
+ charac.push_back(location);
+ const char32_t *target_char = &p_base[0];
+ int bad_case = 0;
+ for (const Pair<int, int> &match_segment : matches) {
+ const char32_t *string_to_complete_char = &display[match_segment.first];
+ for (int j = 0; j < match_segment.second; j++, string_to_complete_char++, target_char++) {
+ if (*string_to_complete_char != *target_char) {
+ bad_case++;
+ }
+ }
+ }
+ charac.push_back(bad_case);
+ charac.push_back(matches[0].first);
+ last_matches = matches;
+ return charac;
+}
+
+void ScriptLanguage::CodeCompletionOption::clear_characteristics() {
+ charac = TypedArray<int>();
+}
+
+TypedArray<int> ScriptLanguage::CodeCompletionOption::get_option_cached_characteristics() const {
+ // Only returns the cached value and warns if it was not updated since the last change of matches.
+ if (last_matches != matches) {
+ WARN_PRINT("Characteristics are not up to date.");
+ }
+
+ return charac;
+}
+
bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
if (script->is_placeholder_fallback_enabled()) {
return false;
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 696c9a94a5..2b685c77a3 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -35,6 +35,8 @@
#include "core/io/resource.h"
#include "core/templates/pair.h"
#include "core/templates/rb_map.h"
+#include "core/templates/safe_refcount.h"
+#include "core/variant/typed_array.h"
class ScriptLanguage;
template <typename T>
@@ -51,7 +53,7 @@ class ScriptServer {
static int _language_count;
static bool scripting_enabled;
static bool reload_scripts_on_save;
- static bool languages_finished;
+ static SafeFlag languages_finished; // Used until GH-76581 is fixed properly.
struct GlobalScriptClass {
StringName language;
@@ -96,7 +98,7 @@ public:
static void init_languages();
static void finish_languages();
- static bool are_languages_finished() { return languages_finished; }
+ static bool are_languages_finished() { return languages_finished.is_set(); }
};
class ScriptInstance;
@@ -305,8 +307,8 @@ public:
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
virtual bool overrides_external_editor() { return false; }
- /* Keep enum in Sync with: */
- /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
+ // Keep enums in sync with:
+ // scene/gui/code_edit.h - CodeEdit::CodeCompletionKind
enum CodeCompletionKind {
CODE_COMPLETION_KIND_CLASS,
CODE_COMPLETION_KIND_FUNCTION,
@@ -321,6 +323,7 @@ public:
CODE_COMPLETION_KIND_MAX
};
+ // scene/gui/code_edit.h - CodeEdit::CodeCompletionLocation
enum CodeCompletionLocation {
LOCATION_LOCAL = 0,
LOCATION_PARENT_MASK = 1 << 8,
@@ -336,6 +339,7 @@ public:
Ref<Resource> icon;
Variant default_value;
Vector<Pair<int, int>> matches;
+ Vector<Pair<int, int>> last_matches = { { -1, -1 } }; // This value correspond to an impossible match
int location = LOCATION_OTHER;
CodeCompletionOption() {}
@@ -346,6 +350,13 @@ public:
kind = p_kind;
location = p_location;
}
+
+ TypedArray<int> get_option_characteristics(const String &p_base);
+ void clear_characteristics();
+ TypedArray<int> get_option_cached_characteristics() const;
+
+ private:
+ TypedArray<int> charac;
};
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 79cf712119..1a0ec29479 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -651,7 +651,7 @@ public:
#ifdef TOOLS_ENABLED
Ref<Script> script = get_script();
- if (script->is_valid() && pcount > 0) {
+ if (script.is_valid() && pcount > 0) {
p_list->push_back(script->get_class_category());
}
#endif // TOOLS_ENABLED
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 077929351e..f04961c760 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -80,14 +80,14 @@ bool UndoRedo::_redo(bool p_execute) {
return true;
}
-void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
+void UndoRedo::create_action(const String &p_name, MergeMode p_mode, bool p_backward_undo_ops) {
uint64_t ticks = OS::get_singleton()->get_ticks_msec();
if (action_level == 0) {
_discard_redo();
// Check if the merge operation is valid
- if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) {
+ if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].backward_undo_ops == p_backward_undo_ops && actions[actions.size() - 1].last_tick + 800 > ticks) {
current_action = actions.size() - 2;
if (p_mode == MERGE_ENDS) {
@@ -108,12 +108,18 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
actions.write[actions.size() - 1].last_tick = ticks;
+ // Revert reverse from previous commit.
+ if (actions[actions.size() - 1].backward_undo_ops) {
+ actions.write[actions.size() - 1].undo_ops.reverse();
+ }
+
merge_mode = p_mode;
merging = true;
} else {
Action new_action;
new_action.name = p_name;
new_action.last_tick = ticks;
+ new_action.backward_undo_ops = p_backward_undo_ops;
actions.push_back(new_action);
merge_mode = MERGE_DISABLE;
@@ -292,6 +298,10 @@ void UndoRedo::commit_action(bool p_execute) {
merging = false;
}
+ if (actions[actions.size() - 1].backward_undo_ops) {
+ actions.write[actions.size() - 1].undo_ops.reverse();
+ }
+
committing++;
_redo(p_execute); // perform action
committing--;
@@ -302,6 +312,11 @@ void UndoRedo::commit_action(bool p_execute) {
}
void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
+ const int PREALLOCATE_ARGS_COUNT = 16;
+
+ LocalVector<const Variant *> args;
+ args.reserve(PREALLOCATE_ARGS_COUNT);
+
for (; E; E = E->next()) {
Operation &op = E->get();
@@ -337,12 +352,13 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
if (binds.is_empty()) {
method_callback(method_callback_ud, obj, op.name, nullptr, 0);
} else {
- const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+ args.clear();
+
for (int i = 0; i < binds.size(); i++) {
- args[i] = (const Variant *)&binds[i];
+ args.push_back(&binds[i]);
}
- method_callback(method_callback_ud, obj, op.name, args, binds.size());
+ method_callback(method_callback_ud, obj, op.name, args.ptr(), binds.size());
}
}
} break;
@@ -458,7 +474,7 @@ UndoRedo::~UndoRedo() {
}
void UndoRedo::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
+ ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "backward_undo_ops"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE), DEFVAL(false));
ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 5dc9f2966c..389d8714f7 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -58,7 +58,7 @@ private:
TYPE_REFERENCE
} type;
- bool force_keep_in_merge_ends;
+ bool force_keep_in_merge_ends = false;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
@@ -72,7 +72,8 @@ private:
String name;
List<Operation> do_ops;
List<Operation> undo_ops;
- uint64_t last_tick;
+ uint64_t last_tick = 0;
+ bool backward_undo_ops = false;
};
Vector<Action> actions;
@@ -102,7 +103,7 @@ protected:
static void _bind_methods();
public:
- void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
+ void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE, bool p_backward_undo_ops = false);
void add_do_method(const Callable &p_callable);
void add_undo_method(const Callable &p_callable);
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index afe6ecd1b3..5ec3e1a1a8 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -31,6 +31,7 @@
#include "worker_thread_pool.h"
#include "core/os/os.h"
+#include "core/os/thread_safe.h"
void WorkerThreadPool::Task::free_template_userdata() {
ERR_FAIL_COND(!template_userdata);
@@ -55,6 +56,8 @@ void WorkerThreadPool::_process_task(Task *p_task) {
Task *prev_low_prio_task = nullptr; // In case this is recursively called.
if (!use_native_low_priority_threads) {
+ // Tasks must start with this unset. They are free to set-and-forget otherwise.
+ set_current_thread_safe_for_nodes(false);
pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
task_mutex.lock();
@@ -367,7 +370,9 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) {
must_exit = true;
} else {
// Solve tasks while they are around.
+ bool safe_for_nodes_backup = is_current_thread_safe_for_nodes();
_process_task_queue();
+ set_current_thread_safe_for_nodes(safe_for_nodes_backup);
continue;
}
} else if (!use_native_low_priority_threads && task->low_priority) {
@@ -411,7 +416,7 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) {
WorkerThreadPool::GroupID WorkerThreadPool::_add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description) {
ERR_FAIL_COND_V(p_elements < 0, INVALID_TASK_ID);
if (p_tasks < 0) {
- p_tasks = threads.size();
+ p_tasks = MAX(1u, threads.size());
}
task_mutex.lock();
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 1e32e6e096..1a51624030 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -400,17 +400,38 @@ String keycode_get_string(Key p_code) {
return codestr;
}
-Key find_keycode(const String &p_code) {
+Key find_keycode(const String &p_codestr) {
+ Key keycode = Key::NONE;
+ Vector<String> code_parts = p_codestr.split("+");
+ if (code_parts.size() < 1) {
+ return keycode;
+ }
+
+ String last_part = code_parts[code_parts.size() - 1];
const _KeyCodeText *kct = &_keycodes[0];
while (kct->text) {
- if (p_code.nocasecmp_to(kct->text) == 0) {
- return kct->code;
+ if (last_part.nocasecmp_to(kct->text) == 0) {
+ keycode = kct->code;
+ break;
}
kct++;
}
- return Key::NONE;
+ for (int part = 0; part < code_parts.size() - 1; part++) {
+ String code_part = code_parts[part];
+ if (code_part.nocasecmp_to(find_keycode_name(Key::SHIFT)) == 0) {
+ keycode |= KeyModifierMask::SHIFT;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::CTRL)) == 0) {
+ keycode |= KeyModifierMask::CTRL;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::META)) == 0) {
+ keycode |= KeyModifierMask::META;
+ } else if (code_part.nocasecmp_to(find_keycode_name(Key::ALT)) == 0) {
+ keycode |= KeyModifierMask::ALT;
+ }
+ }
+
+ return keycode;
}
const char *find_keycode_name(Key p_keycode) {
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 84017e89a6..cf276dc49f 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -330,7 +330,7 @@ constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
String keycode_get_string(Key p_code);
bool keycode_has_unicode(Key p_keycode);
-Key find_keycode(const String &p_code);
+Key find_keycode(const String &p_codestr);
const char *find_keycode_name(Key p_keycode);
int keycode_get_count();
int keycode_get_value_by_index(int p_index);
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index b908b64d73..5e21490164 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -52,15 +52,7 @@ void MainLoop::_bind_methods() {
GDVIRTUAL_BIND(_finalize);
}
-void MainLoop::set_initialize_script(const Ref<Script> &p_initialize_script) {
- initialize_script = p_initialize_script;
-}
-
void MainLoop::initialize() {
- if (initialize_script.is_valid()) {
- set_script(initialize_script);
- }
-
GDVIRTUAL_CALL(_initialize);
}
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 36eeb35aad..90cad009b1 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -39,8 +39,6 @@
class MainLoop : public Object {
GDCLASS(MainLoop, Object);
- Ref<Script> initialize_script;
-
protected:
static void _bind_methods();
@@ -69,8 +67,6 @@ public:
virtual bool process(double p_time);
virtual void finalize();
- void set_initialize_script(const Ref<Script> &p_initialize_script);
-
MainLoop() {}
virtual ~MainLoop() {}
};
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 5704ef7a40..67423128a3 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -295,12 +295,14 @@ Error OS::shell_open(String p_uri) {
}
Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) {
- if (!p_path.begins_with("file://")) {
- p_path = String("file://") + p_path;
- }
- if (!p_path.ends_with("/")) {
+ p_path = p_path.trim_prefix("file://");
+
+ if (!DirAccess::dir_exists_absolute(p_path)) {
p_path = p_path.get_base_dir();
}
+
+ p_path = String("file://") + p_path;
+
return shell_open(p_path);
}
// implement these with the canvas?
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
deleted file mode 100644
index 34b417ae57..0000000000
--- a/core/os/threaded_array_processor.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**************************************************************************/
-/* threaded_array_processor.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef THREADED_ARRAY_PROCESSOR_H
-#define THREADED_ARRAY_PROCESSOR_H
-
-#include "core/os/os.h"
-#include "core/os/thread.h"
-#include "core/os/thread_safe.h"
-#include "core/templates/safe_refcount.h"
-
-template <class C, class U>
-struct ThreadArrayProcessData {
- uint32_t elements;
- SafeNumeric<uint32_t> index;
- C *instance;
- U userdata;
- void (C::*method)(uint32_t, U);
-
- void process(uint32_t p_index) {
- (instance->*method)(p_index, userdata);
- }
-};
-
-template <class T>
-void process_array_thread(void *ud) {
- T &data = *(T *)ud;
- while (true) {
- uint32_t index = data.index.increment();
- if (index >= data.elements) {
- break;
- }
- data.process(index);
- }
-}
-
-template <class C, class M, class U>
-void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
- ThreadArrayProcessData<C, U> data;
- data.method = p_method;
- data.instance = p_instance;
- data.userdata = p_userdata;
- data.index.set(0);
- data.elements = p_elements;
- data.process(0); //process first, let threads increment for next
-
- int thread_count = OS::get_singleton()->get_processor_count();
- Thread *threads = memnew_arr(Thread, thread_count);
-
- for (int i = 0; i < thread_count; i++) {
- threads[i].start(process_array_thread<ThreadArrayProcessData<C, U>>, &data);
- }
-
- for (int i = 0; i < thread_count; i++) {
- threads[i].wait_to_finish();
- }
- memdelete_arr(threads);
-}
-
-#endif // THREADED_ARRAY_PROCESSOR_H
diff --git a/core/os/time.cpp b/core/os/time.cpp
index 038e4adc03..bad5cc2e4f 100644
--- a/core/os/time.cpp
+++ b/core/os/time.cpp
@@ -52,9 +52,6 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = {
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
-VARIANT_ENUM_CAST(Month);
-VARIANT_ENUM_CAST(Weekday);
-
#define UNIX_TIME_TO_HMS \
uint8_t hour, minute, second; \
{ \
diff --git a/core/os/time.h b/core/os/time.h
index 19bc900aee..ccd2d92b8b 100644
--- a/core/os/time.h
+++ b/core/os/time.h
@@ -81,4 +81,7 @@ public:
virtual ~Time();
};
+VARIANT_ENUM_CAST(Month);
+VARIANT_ENUM_CAST(Weekday);
+
#endif // TIME_H
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index c276f20f99..12e6423724 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -62,6 +62,7 @@ static _FORCE_INLINE_ char32_t lower_case(char32_t c) {
const char CharString::_null = 0;
const char16_t Char16String::_null = 0;
const char32_t String::_null = 0;
+const char32_t String::_replacement_char = 0xfffd;
bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) {
const String &s = p_s;
@@ -307,7 +308,7 @@ void String::copy_from(const char *p_cstr) {
uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]);
if (c == 0 && i < len) {
print_unicode_error("NUL character", true);
- dst[i] = 0x20;
+ dst[i] = _replacement_char;
} else {
dst[i] = c;
}
@@ -340,7 +341,7 @@ void String::copy_from(const char *p_cstr, const int p_clip_to) {
uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]);
if (c == 0) {
print_unicode_error("NUL character", true);
- dst[i] = 0x20;
+ dst[i] = _replacement_char;
} else {
dst[i] = c;
}
@@ -373,17 +374,21 @@ void String::copy_from(const char32_t &p_char) {
print_unicode_error("NUL character", true);
return;
}
+
+ resize(2);
+
+ char32_t *dst = ptrw();
+
if ((p_char & 0xfffff800) == 0xd800) {
print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char));
- }
- if (p_char > 0x10ffff) {
+ dst[0] = _replacement_char;
+ } else if (p_char > 0x10ffff) {
print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char));
+ dst[0] = _replacement_char;
+ } else {
+ dst[0] = p_char;
}
- resize(2);
-
- char32_t *dst = ptrw();
- dst[0] = p_char;
dst[1] = 0;
}
@@ -439,14 +444,18 @@ void String::copy_from_unchecked(const char32_t *p_char, const int p_length) {
for (int i = 0; i < p_length; i++) {
if (p_char[i] == 0) {
print_unicode_error("NUL character", true);
- dst[i] = 0x20;
+ dst[i] = _replacement_char;
continue;
}
if ((p_char[i] & 0xfffff800) == 0xd800) {
print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char[i]));
+ dst[i] = _replacement_char;
+ continue;
}
if (p_char[i] > 0x10ffff) {
print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char[i]));
+ dst[i] = _replacement_char;
+ continue;
}
dst[i] = p_char[i];
}
@@ -538,7 +547,7 @@ String &String::operator+=(const char *p_str) {
uint8_t c = p_str[i] >= 0 ? p_str[i] : uint8_t(256 + p_str[i]);
if (c == 0 && i < rhs_len) {
print_unicode_error("NUL character", true);
- dst[i] = 0x20;
+ dst[i] = _replacement_char;
} else {
dst[i] = c;
}
@@ -568,17 +577,21 @@ String &String::operator+=(char32_t p_char) {
print_unicode_error("NUL character", true);
return *this;
}
+
+ const int lhs_len = length();
+ resize(lhs_len + 2);
+ char32_t *dst = ptrw();
+
if ((p_char & 0xfffff800) == 0xd800) {
print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char));
- }
- if (p_char > 0x10ffff) {
+ dst[lhs_len] = _replacement_char;
+ } else if (p_char > 0x10ffff) {
print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char));
+ dst[lhs_len] = _replacement_char;
+ } else {
+ dst[lhs_len] = p_char;
}
- const int lhs_len = length();
- resize(lhs_len + 2);
- char32_t *dst = ptrw();
- dst[lhs_len] = p_char;
dst[lhs_len + 1] = 0;
return *this;
@@ -1737,7 +1750,7 @@ Vector<uint8_t> String::hex_decode() const {
void String::print_unicode_error(const String &p_message, bool p_critical) const {
if (p_critical) {
- print_error(vformat("Unicode parsing error, some characters were replaced with spaces: %s", p_message));
+ print_error(vformat("Unicode parsing error, some characters were replaced with � (U+FFFD): %s", p_message));
} else {
print_error(vformat("Unicode parsing error: %s", p_message));
}
@@ -1757,7 +1770,7 @@ CharString String::ascii(bool p_allow_extended) const {
cs[i] = c;
} else {
print_unicode_error(vformat("Invalid unicode codepoint (%x), cannot represent as ASCII/Latin-1", (uint32_t)c));
- cs[i] = 0x20;
+ cs[i] = 0x20; // ascii doesn't have a replacement character like unicode, 0x1a is sometimes used but is kinda arcane
}
}
@@ -1897,13 +1910,13 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
unichar = (0xff >> 7) & c;
skip = 5;
} else {
- *(dst++) = 0x20;
+ *(dst++) = _replacement_char;
unichar = 0;
skip = 0;
}
} else {
if (c < 0x80 || c > 0xbf) {
- *(dst++) = 0x20;
+ *(dst++) = _replacement_char;
skip = 0;
} else {
unichar = (unichar << 6) | (c & 0x3f);
@@ -1912,15 +1925,15 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
if (unichar == 0) {
print_unicode_error("NUL character", true);
decode_failed = true;
- unichar = 0x20;
- }
- if ((unichar & 0xfffff800) == 0xd800) {
- print_unicode_error(vformat("Unpaired surrogate (%x)", unichar));
- decode_error = true;
- }
- if (unichar > 0x10ffff) {
- print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar));
- decode_error = true;
+ unichar = _replacement_char;
+ } else if ((unichar & 0xfffff800) == 0xd800) {
+ print_unicode_error(vformat("Unpaired surrogate (%x)", unichar), true);
+ decode_failed = true;
+ unichar = _replacement_char;
+ } else if (unichar > 0x10ffff) {
+ print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar), true);
+ decode_failed = true;
+ unichar = _replacement_char;
}
*(dst++) = unichar;
}
@@ -2014,7 +2027,11 @@ CharString String::utf8() const {
APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower lower middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
} else {
- APPEND_CHAR(0x20);
+ // the string is a valid UTF32, so it should never happen ...
+ print_unicode_error(vformat("Non scalar value (%x)", c), true);
+ APPEND_CHAR(uint32_t(0xe0 | ((_replacement_char >> 12) & 0x0f))); // Top 4 bits.
+ APPEND_CHAR(uint32_t(0x80 | ((_replacement_char >> 6) & 0x3f))); // Middle 6 bits.
+ APPEND_CHAR(uint32_t(0x80 | (_replacement_char & 0x3f))); // Bottom 6 bits.
}
}
#undef APPEND_CHAR
@@ -2187,7 +2204,9 @@ Char16String String::utf16() const {
APPEND_CHAR(uint32_t((c >> 10) + 0xd7c0)); // lead surrogate.
APPEND_CHAR(uint32_t((c & 0x3ff) | 0xdc00)); // trail surrogate.
} else {
- APPEND_CHAR(0x20);
+ // the string is a valid UTF32, so it should never happen ...
+ APPEND_CHAR(uint32_t((_replacement_char >> 10) + 0xd7c0));
+ APPEND_CHAR(uint32_t((_replacement_char & 0x3ff) | 0xdc00));
}
}
#undef APPEND_CHAR
@@ -4262,12 +4281,13 @@ String String::pad_zeros(int p_digits) const {
begin++;
}
- if (begin >= end) {
+ int zeros_to_add = p_digits - (end - begin);
+
+ if (zeros_to_add <= 0) {
return s;
+ } else {
+ return s.insert(begin, String("0").repeat(zeros_to_add));
}
-
- int zeros_to_add = p_digits - (end - begin);
- return s.insert(begin, String("0").repeat(zeros_to_add));
}
String String::trim_prefix(const String &p_prefix) const {
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 782ca47507..295625395d 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -183,6 +183,7 @@ struct StrRange {
class String {
CowData<char32_t> _cowdata;
static const char32_t _null;
+ static const char32_t _replacement_char;
void copy_from(const char *p_cstr);
void copy_from(const char *p_cstr, const int p_clip_to);
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index 9ccd7bb0bf..e2ffabdaf0 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -117,6 +117,7 @@ class RID_Alloc : public RID_AllocBase {
uint32_t free_element = free_index % elements_in_chunk;
uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF);
+ CRASH_COND_MSG(validator == 0x7FFFFFFF, "Overflow in RID validator");
uint64_t id = validator;
id <<= 32;
id |= free_index;
@@ -238,7 +239,7 @@ public:
uint32_t validator = uint32_t(id >> 32);
- bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
+ bool owned = (validator != 0x7FFFFFFF) && (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
if (THREAD_SAFE) {
spin_lock.unlock();
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index 378d1ff618..e493e50467 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -144,6 +144,18 @@ void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Varia
callable.callp(args, p_argcount + binds.size(), r_return_value, r_call_error);
}
+Error CallableCustomBind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));
+ for (int i = 0; i < p_argcount; i++) {
+ args[i] = (const Variant *)p_arguments[i];
+ }
+ for (int i = 0; i < binds.size(); i++) {
+ args[i + p_argcount] = (const Variant *)&binds[i];
+ }
+
+ return callable.rpcp(p_peer_id, args, p_argcount + binds.size(), r_call_error);
+}
+
CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) {
callable = p_callable;
binds = p_binds;
@@ -242,6 +254,16 @@ void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Var
callable.callp(p_arguments, p_argcount - argcount, r_return_value, r_call_error);
}
+Error CallableCustomUnbind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ if (argcount > p_argcount) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_call_error.argument = 0;
+ r_call_error.expected = argcount;
+ return ERR_UNCONFIGURED;
+ }
+ return callable.rpcp(p_peer_id, p_arguments, p_argcount - argcount, r_call_error);
+}
+
CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) {
callable = p_callable;
argcount = p_argcount;
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index b51076ad0f..5798797a3d 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -51,6 +51,7 @@ public:
virtual StringName get_method() const override;
virtual ObjectID get_object() const override;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
@@ -78,6 +79,7 @@ public:
virtual StringName get_method() const override;
virtual ObjectID get_object() const override;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+ virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override;
virtual const Callable *get_base_comparator() const override;
virtual int get_bound_arguments_count() const override;
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index 0429508cc5..f019273735 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -83,9 +83,16 @@ Variant &Dictionary::operator[](const Variant &p_key) {
if (unlikely(_p->read_only)) {
if (p_key.get_type() == Variant::STRING_NAME) {
const StringName *sn = VariantInternal::get_string_name(&p_key);
- *_p->read_only = _p->variant_map[sn->operator String()];
- } else {
+ const String &key = sn->operator String();
+ if (likely(_p->variant_map.has(key))) {
+ *_p->read_only = _p->variant_map[key];
+ } else {
+ *_p->read_only = Variant();
+ }
+ } else if (likely(_p->variant_map.has(p_key))) {
*_p->read_only = _p->variant_map[p_key];
+ } else {
+ *_p->read_only = Variant();
}
return *_p->read_only;
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index df1e524494..cbfb9cc257 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -159,7 +159,10 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
template <class T>
struct PtrToArg<T *> {
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
- return const_cast<T *>(reinterpret_cast<const T *>(p_ptr));
+ if (p_ptr == nullptr) {
+ return nullptr;
+ }
+ return const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr));
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
@@ -170,7 +173,10 @@ struct PtrToArg<T *> {
template <class T>
struct PtrToArg<const T *> {
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
- return reinterpret_cast<const T *>(p_ptr);
+ if (p_ptr == nullptr) {
+ return nullptr;
+ }
+ return *reinterpret_cast<T *const *>(p_ptr);
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h
index ea811daabf..9199b12845 100644
--- a/core/variant/native_ptr.h
+++ b/core/variant/native_ptr.h
@@ -53,36 +53,46 @@ struct GDExtensionPtr {
operator Variant() const { return uint64_t(data); }
};
-#define GDVIRTUAL_NATIVE_PTR(m_type) \
- template <> \
- struct GDExtensionConstPtr<const m_type> { \
- const m_type *data = nullptr; \
- GDExtensionConstPtr() {} \
- GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return "const " #m_type; } \
- operator const m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
- static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
- return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
- } \
- }; \
- template <> \
- struct GDExtensionPtr<m_type> { \
- m_type *data = nullptr; \
- GDExtensionPtr() {} \
- GDExtensionPtr(m_type *p_assign) { data = p_assign; } \
- static const char *get_name() { return #m_type; } \
- operator m_type *() const { return data; } \
- operator Variant() const { return uint64_t(data); } \
- }; \
- template <> \
- struct VariantCaster<GDExtensionPtr<m_type>> { \
- static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
- return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
- } \
+#define GDVIRTUAL_NATIVE_PTR(m_type) \
+ template <> \
+ struct GDExtensionConstPtr<const m_type> { \
+ const m_type *data = nullptr; \
+ GDExtensionConstPtr() {} \
+ GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return "const " #m_type; } \
+ operator const m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionConstPtr<const m_type>> { \
+ static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \
+ return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \
+ } \
+ }; \
+ template <> \
+ struct VariantInternalAccessor<GDExtensionConstPtr<const m_type>> { \
+ static _FORCE_INLINE_ const GDExtensionConstPtr<const m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionConstPtr<const m_type> *>(VariantInternal::get_int(v)); } \
+ static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr<const m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \
+ }; \
+ template <> \
+ struct GDExtensionPtr<m_type> { \
+ m_type *data = nullptr; \
+ GDExtensionPtr() {} \
+ GDExtensionPtr(m_type *p_assign) { data = p_assign; } \
+ static const char *get_name() { return #m_type; } \
+ operator m_type *() const { return data; } \
+ operator Variant() const { return uint64_t(data); } \
+ }; \
+ template <> \
+ struct VariantCaster<GDExtensionPtr<m_type>> { \
+ static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \
+ return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \
+ } \
+ }; \
+ template <> \
+ struct VariantInternalAccessor<GDExtensionPtr<m_type>> { \
+ static _FORCE_INLINE_ const GDExtensionPtr<m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionPtr<m_type> *>(VariantInternal::get_int(v)); } \
+ static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr<m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \
};
template <class T>
diff --git a/core/variant/variant.h b/core/variant/variant.h
index f694e59051..04c2fe2012 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -488,7 +488,7 @@ public:
Variant(const IPAddress &p_address);
#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \
- Variant(const m_enum &p_value) { \
+ Variant(m_enum p_value) { \
type = INT; \
_data._int = (int64_t)p_value; \
}
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 8013c1a32a..782053b613 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -502,7 +502,7 @@ public:
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::OBJECT:
- return v->_get_obj().obj;
+ return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
@@ -1541,7 +1541,7 @@ struct VariantTypeConstructor {
_FORCE_INLINE_ static void type_from_variant(void *r_value, void *p_variant) {
// r_value is provided by caller as uninitialized memory
- memnew_placement(r_value, T(VariantInternalAccessor<T>::get(reinterpret_cast<Variant *>(p_variant))));
+ memnew_placement(r_value, T(*reinterpret_cast<Variant *>(p_variant)));
}
};
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 33c285dc6d..aed83ac010 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -900,6 +900,39 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL);
register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL);
register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorNot<String>>(Variant::OP_NOT, Variant::STRING, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector2>>(Variant::OP_NOT, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector2i>>(Variant::OP_NOT, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Rect2>>(Variant::OP_NOT, Variant::RECT2, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Rect2i>>(Variant::OP_NOT, Variant::RECT2I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector3>>(Variant::OP_NOT, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector3i>>(Variant::OP_NOT, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Transform2D>>(Variant::OP_NOT, Variant::TRANSFORM2D, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector4>>(Variant::OP_NOT, Variant::VECTOR4, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Vector4i>>(Variant::OP_NOT, Variant::VECTOR4I, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Plane>>(Variant::OP_NOT, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Quaternion>>(Variant::OP_NOT, Variant::QUATERNION, Variant::NIL);
+ register_op<OperatorEvaluatorNot<::AABB>>(Variant::OP_NOT, Variant::AABB, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Basis>>(Variant::OP_NOT, Variant::BASIS, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Transform3D>>(Variant::OP_NOT, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Projection>>(Variant::OP_NOT, Variant::PROJECTION, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Color>>(Variant::OP_NOT, Variant::COLOR, Variant::NIL);
+ register_op<OperatorEvaluatorNot<StringName>>(Variant::OP_NOT, Variant::STRING_NAME, Variant::NIL);
+ register_op<OperatorEvaluatorNot<NodePath>>(Variant::OP_NOT, Variant::NODE_PATH, Variant::NIL);
+ register_op<OperatorEvaluatorNot<::RID>>(Variant::OP_NOT, Variant::RID, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Callable>>(Variant::OP_NOT, Variant::CALLABLE, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Signal>>(Variant::OP_NOT, Variant::SIGNAL, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Dictionary>>(Variant::OP_NOT, Variant::DICTIONARY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<Array>>(Variant::OP_NOT, Variant::ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedByteArray>>(Variant::OP_NOT, Variant::PACKED_BYTE_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedInt32Array>>(Variant::OP_NOT, Variant::PACKED_INT32_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedInt64Array>>(Variant::OP_NOT, Variant::PACKED_INT64_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedFloat32Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT32_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedFloat64Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT64_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedStringArray>>(Variant::OP_NOT, Variant::PACKED_STRING_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedVector2Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR2_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedVector3Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR3_ARRAY, Variant::NIL);
+ register_op<OperatorEvaluatorNot<PackedColorArray>>(Variant::OP_NOT, Variant::PACKED_COLOR_ARRAY, Variant::NIL);
register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN);
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index d2163cf92d..c11f726402 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -805,14 +805,14 @@ class OperatorEvaluatorNot {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
- *r_ret = !a;
+ *r_ret = a == A();
r_valid = true;
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
- *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == A();
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
- PtrToArg<bool>::encode(!PtrToArg<A>::convert(left));
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == A(), r_ret);
}
static Variant::Type get_return_type() { return Variant::BOOL; }
};
@@ -824,6 +824,11 @@ public:
_FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) {
int asize = array_a.size();
int bsize = array_b.size();
+
+ if (array_a.is_typed() && array_a.is_same_typed(array_b)) {
+ sum.set_typed(array_a.get_typed_builtin(), array_a.get_typed_class_name(), array_a.get_typed_script());
+ }
+
sum.resize(asize + bsize);
for (int i = 0; i < asize; i++) {
sum[i] = array_a[i];
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index a40fcfbd47..3320750994 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -865,12 +865,46 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
get_token(p_stream, token, line, r_err_str);
- if (token.type != TK_NUMBER) {
- r_err_str = "Expected number as argument";
+ // Permit empty RID.
+ if (token.type == TK_PARENTHESIS_CLOSE) {
+ value = RID();
+ return OK;
+ } else if (token.type != TK_NUMBER) {
+ r_err_str = "Expected number as argument or ')'";
return ERR_PARSE_ERROR;
}
- value = token.value;
+ value = RID::from_uint64(token.value);
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+ } else if (id == "Signal") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ // Load as empty.
+ value = Signal();
+
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+ } else if (id == "Callable") {
+ get_token(p_stream, token, line, r_err_str);
+ if (token.type != TK_PARENTHESIS_OPEN) {
+ r_err_str = "Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ // Load as empty.
+ value = Callable();
get_token(p_stream, token, line, r_err_str);
if (token.type != TK_PARENTHESIS_CLOSE) {
@@ -1832,6 +1866,24 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} break;
+ case Variant::RID: {
+ RID rid = p_variant;
+
+ if (rid == RID()) {
+ p_store_string_func(p_store_string_ud, "RID()");
+ } else {
+ p_store_string_func(p_store_string_ud, "RID(" + itos(rid.get_id()) + ")");
+ }
+ } break;
+
+ // Do not really store these, but ensure that assignments are not empty.
+ case Variant::SIGNAL: {
+ p_store_string_func(p_store_string_ud, "Signal()");
+ } break;
+ case Variant::CALLABLE: {
+ p_store_string_func(p_store_string_ud, "Callable()");
+ } break;
+
case Variant::OBJECT: {
Object *obj = p_variant.get_validated_object();
@@ -2129,6 +2181,8 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
} break;
default: {
+ ERR_PRINT("Unknown variant type");
+ return ERR_BUG;
}
}