summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp5
-rw-r--r--core/extension/gdextension.cpp47
-rw-r--r--core/extension/gdextension.h8
-rw-r--r--core/extension/gdextension_interface.cpp4
-rw-r--r--core/extension/gdextension_interface.h4
-rw-r--r--core/input/gamecontrollerdb.txt12
-rw-r--r--core/input/input.cpp119
-rw-r--r--core/input/input.h19
-rw-r--r--core/input/input_map.cpp18
-rw-r--r--core/input/input_map.h5
-rw-r--r--core/io/image.cpp2
-rw-r--r--core/io/marshalls.cpp6
-rw-r--r--core/io/resource.cpp4
-rw-r--r--core/io/resource.h1
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--core/io/resource_importer.h1
-rw-r--r--core/io/resource_loader.cpp7
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/math/geometry_2d.h8
-rw-r--r--core/object/class_db.cpp28
-rw-r--r--core/object/class_db.h3
-rw-r--r--core/object/object.cpp1
-rw-r--r--core/object/object.h2
-rw-r--r--core/object/script_language.cpp34
-rw-r--r--core/object/script_language.h7
-rw-r--r--core/object/script_language_extension.h3
-rw-r--r--core/object/undo_redo.cpp4
-rw-r--r--core/object/undo_redo.h2
-rw-r--r--core/object/worker_thread_pool.cpp9
-rw-r--r--core/object/worker_thread_pool.h1
-rw-r--r--core/os/os.cpp6
-rw-r--r--core/string/string_name.cpp2
-rw-r--r--core/string/ustring.cpp7
-rw-r--r--core/string/ustring.h2
-rw-r--r--core/variant/variant.cpp6
35 files changed, 280 insertions, 111 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index cbbfe3de75..93934f2320 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -852,8 +852,8 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
}
if (!p_custom_features.is_empty()) {
+ // Store how many properties are saved, add one for custom features, which must always go first.
file->store_32(count + 1);
- //store how many properties are saved, add one for custom featuers, which must always go first
String key = CoreStringNames::get_singleton()->_custom_features;
file->store_pascal_string(key);
@@ -870,7 +870,8 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
file->store_buffer(buff.ptr(), buff.size());
} else {
- file->store_32(count); //store how many properties are saved
+ // Store how many properties are saved.
+ file->store_32(count);
}
for (const KeyValue<String, List<String>> &E : p_props) {
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 26512d0c56..2bac1f6592 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -678,12 +678,11 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p
}
Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) {
- library_path = p_path;
-
String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path);
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
// If running on the editor on Windows, we copy the library and open the copy.
// This is so the original file isn't locked and can be updated by a compiler.
+ bool library_copied = false;
if (Engine::get_singleton()->is_editor_hint()) {
if (!FileAccess::exists(abs_path)) {
ERR_PRINT("GDExtension library not found: " + library_path);
@@ -705,6 +704,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
return ERR_CANT_CREATE;
}
FileAccess::set_hidden_attribute(copy_path, true);
+ library_copied = true;
// Save the copied path so it can be deleted later.
temp_lib_path = copy_path;
@@ -714,12 +714,20 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
}
#endif
- Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true);
+ Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &library_path);
if (err != OK) {
ERR_PRINT("GDExtension dynamic library not found: " + abs_path);
return err;
}
+#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
+ // If we copied the file, let's change the library path to point at the original,
+ // because that's what we want to check to see if it's changed.
+ if (library_copied) {
+ library_path = library_path.get_base_dir() + "\\" + p_path.get_file();
+ }
+#endif
+
void *entry_funcptr = nullptr;
err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false);
@@ -904,6 +912,8 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path,
return ERR_FILE_NOT_FOUND;
}
+ bool is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework");
+
if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
library_path = p_path.get_base_dir().path_join(library_path);
}
@@ -915,12 +925,12 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path,
#ifdef TOOLS_ENABLED
p_extension->set_reloadable(config->get_value("configuration", "reloadable", false) && Engine::get_singleton()->is_extension_reloading_enabled());
- p_extension->update_last_modified_time(MAX(
- FileAccess::get_modified_time(library_path),
- FileAccess::get_modified_time(p_path)));
+ p_extension->update_last_modified_time(
+ FileAccess::get_modified_time(p_path),
+ FileAccess::get_modified_time(library_path));
#endif
- err = p_extension->open_library(library_path, entry_symbol);
+ err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol);
if (err != OK) {
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
// If the DLL fails to load, make sure that temporary DLL copies are cleaned up.
@@ -959,13 +969,15 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
// object if one has already been loaded (even if caching is disabled at the resource
// loader level).
GDExtensionManager *manager = GDExtensionManager::get_singleton();
- Ref<GDExtension> lib = manager->get_extension(p_path);
- if (lib.is_null()) {
- Error err = load_gdextension_resource(p_path, lib);
- if (err != OK && r_error) {
- // Errors already logged in load_gdextension_resource().
- *r_error = err;
- }
+ if (manager->is_extension_loaded(p_path)) {
+ return manager->get_extension(p_path);
+ }
+
+ Ref<GDExtension> lib;
+ Error err = load_gdextension_resource(p_path, lib);
+ if (err != OK && r_error) {
+ // Errors already logged in load_gdextension_resource().
+ *r_error = err;
}
return lib;
}
@@ -988,10 +1000,13 @@ String GDExtensionResourceLoader::get_resource_type(const String &p_path) const
#ifdef TOOLS_ENABLED
bool GDExtension::has_library_changed() const {
- if (FileAccess::get_modified_time(get_path()) > last_modified_time) {
+ // Check only that the last modified time is different (rather than checking
+ // that it's newer) since some OS's (namely Windows) will preserve the modified
+ // time by default when copying files.
+ if (FileAccess::get_modified_time(get_path()) != resource_last_modified_time) {
return true;
}
- if (FileAccess::get_modified_time(library_path) > last_modified_time) {
+ if (FileAccess::get_modified_time(library_path) != library_last_modified_time) {
return true;
}
return false;
diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h
index bab3bcd198..0d20b8e50c 100644
--- a/core/extension/gdextension.h
+++ b/core/extension/gdextension.h
@@ -90,7 +90,8 @@ class GDExtension : public Resource {
int32_t level_initialized = -1;
#ifdef TOOLS_ENABLED
- uint64_t last_modified_time = 0;
+ uint64_t resource_last_modified_time = 0;
+ uint64_t library_last_modified_time = 0;
bool is_reloading = false;
Vector<GDExtensionMethodBind *> invalid_methods;
Vector<ObjectID> instance_bindings;
@@ -140,8 +141,9 @@ public:
void set_reloadable(bool p_reloadable) { reloadable = p_reloadable; }
bool has_library_changed() const;
- void update_last_modified_time(uint64_t p_last_modified_time) {
- last_modified_time = MAX(last_modified_time, p_last_modified_time);
+ void update_last_modified_time(uint64_t p_resource_last_modified_time, uint64_t p_library_last_modified_time) {
+ resource_last_modified_time = p_resource_last_modified_time;
+ library_last_modified_time = p_library_last_modified_time;
}
void track_instance_binding(Object *p_object);
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index d1b4e6a30f..e02e7aa701 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -159,9 +159,7 @@ public:
userdata = p_info->callable_userdata;
token = p_info->token;
- if (p_info->object != nullptr) {
- object = ((Object *)p_info->object)->get_instance_id();
- }
+ object = p_info->object_id;
call_func = p_info->call_func;
is_valid_func = p_info->is_valid_func;
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 240da6e073..d58f0226d8 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -392,7 +392,7 @@ typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_user
typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
typedef struct {
- /* Only `call_func` and `token` are strictly required, however, `object` should be passed if its not a static method.
+ /* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
*
* `token` should point to an address that uniquely identifies the GDExtension (for example, the
* `GDExtensionClassLibraryPtr` passed to the entry symbol function.
@@ -409,7 +409,7 @@ typedef struct {
void *callable_userdata;
void *token;
- GDExtensionObjectPtr object;
+ GDObjectInstanceID object_id;
GDExtensionCallableCustomCall call_func;
GDExtensionCallableCustomIsValid is_valid_func;
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 9a43c4e35d..77655e9b6a 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -414,6 +414,8 @@
03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows,
03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
@@ -582,6 +584,7 @@
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows,
@@ -643,7 +646,6 @@
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
@@ -772,6 +774,7 @@
03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows,
03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,
@@ -928,6 +931,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X,
030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X,
030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
+030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -979,6 +983,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X,
+0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X,
03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -1335,8 +1340,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
+03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1490,6 +1497,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
+0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
@@ -1639,6 +1647,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
@@ -1792,6 +1801,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android,
30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android,
32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 2d48bdd4cf..257452b3d8 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -695,53 +695,34 @@ 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];
- bool is_joypad_axis = jm.is_valid();
- bool is_pressed = false;
- if (!p_event->is_echo()) {
- if (p_event->is_action_pressed(E.key)) {
- bool is_joypad_axis_valid_zone_enter = false;
- if (is_joypad_axis) {
- if (!action.axis_pressed) {
- is_joypad_axis_valid_zone_enter = true;
- action.pressed++;
- action.axis_pressed = true;
- }
- } else {
- action.pressed++;
- }
- if (action.pressed == 1 && (is_joypad_axis_valid_zone_enter || !is_joypad_axis)) {
- action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
- }
- is_pressed = true;
- } else {
- bool is_released = true;
- if (is_joypad_axis) {
- if (action.axis_pressed) {
- action.axis_pressed = false;
- } else {
- is_released = false;
- }
- }
+ const int event_index = InputMap::get_singleton()->event_get_index(p_event, E.key);
+ if (event_index == -1) {
+ continue;
+ }
- if (is_released) {
- if (action.pressed == 1) {
- action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.released_process_frame = Engine::get_singleton()->get_process_frames();
- }
- action.pressed = MAX(action.pressed - 1, 0);
- }
+ Action &action = action_state[E.key];
+ if (!p_event->is_echo()) {
+ if (p_event->is_action_pressed(E.key)) {
+ if (!action.pressed) {
+ action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
- action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
- }
+ action.pressed |= ((uint64_t)1 << event_index);
+ } else {
+ action.pressed &= ~((uint64_t)1 << event_index);
+ action.pressed &= ~(1 << MAX_EVENT); // Always release the event from action_press() method.
- if (is_pressed || action.pressed == 0) {
- action.strength = p_event->get_action_strength(E.key);
- action.raw_strength = p_event->get_action_raw_strength(E.key);
+ if (!action.pressed) {
+ action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ }
+ _update_action_strength(action, MAX_EVENT, 0.0);
+ _update_action_raw_strength(action, MAX_EVENT, 0.0);
}
+ action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
}
+ _update_action_strength(action, event_index, p_event->get_action_strength(E.key));
+ _update_action_raw_strength(action, event_index, p_event->get_action_raw_strength(E.key));
}
if (event_dispatch_function) {
@@ -858,13 +839,13 @@ void Input::action_press(const StringName &p_action, float p_strength) {
// Create or retrieve existing action.
Action &action = action_state[p_action];
- action.pressed++;
- if (action.pressed == 1) {
+ if (!action.pressed) {
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
- action.strength = p_strength;
- action.raw_strength = p_strength;
+ action.pressed |= 1 << MAX_EVENT;
+ _update_action_strength(action, MAX_EVENT, p_strength);
+ _update_action_raw_strength(action, MAX_EVENT, p_strength);
action.exact = true;
}
@@ -872,13 +853,15 @@ void Input::action_release(const StringName &p_action) {
// Create or retrieve existing action.
Action &action = action_state[p_action];
- action.pressed--;
- if (action.pressed == 0) {
- action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ action.pressed = 0;
+ action.strength = 0.0;
+ action.raw_strength = 0.0;
+ action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ for (uint64_t i = 0; i <= MAX_EVENT; i++) {
+ action.strengths[i] = 0.0;
+ action.raw_strengths[i] = 0.0;
}
- action.strength = 0.0f;
- action.raw_strength = 0.0f;
action.exact = true;
}
@@ -1207,6 +1190,38 @@ void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) {
parse_input_event(ievent);
}
+void Input::_update_action_strength(Action &p_action, int p_event_index, float p_strength) {
+ ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
+
+ float old_strength = p_action.strengths[p_event_index];
+ p_action.strengths[p_event_index] = p_strength;
+
+ if (p_strength > p_action.strength) {
+ p_action.strength = p_strength;
+ } else if (Math::is_equal_approx(old_strength, p_action.strength)) {
+ p_action.strength = p_strength;
+ for (uint64_t i = 0; i <= MAX_EVENT; i++) {
+ p_action.strength = MAX(p_action.strength, p_action.strengths[i]);
+ }
+ }
+}
+
+void Input::_update_action_raw_strength(Action &p_action, int p_event_index, float p_strength) {
+ ERR_FAIL_INDEX(p_event_index, (int)MAX_EVENT + 1);
+
+ float old_strength = p_action.raw_strengths[p_event_index];
+ p_action.raw_strengths[p_event_index] = p_strength;
+
+ if (p_strength > p_action.raw_strength) {
+ p_action.raw_strength = p_strength;
+ } else if (Math::is_equal_approx(old_strength, p_action.raw_strength)) {
+ p_action.raw_strength = p_strength;
+ for (uint64_t i = 0; i <= MAX_EVENT; i++) {
+ p_action.raw_strength = MAX(p_action.raw_strength, p_action.raw_strengths[i]);
+ }
+ }
+}
+
Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) {
JoyEvent event;
diff --git a/core/input/input.h b/core/input/input.h
index bedc3fa0e3..dd613c4877 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -44,6 +44,8 @@ class Input : public Object {
static Input *singleton;
+ static constexpr uint64_t MAX_EVENT = 31;
+
public:
enum MouseMode {
MOUSE_MODE_VISIBLE,
@@ -103,11 +105,22 @@ private:
uint64_t pressed_process_frame = UINT64_MAX;
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
- int pressed = 0;
- bool axis_pressed = false;
+ uint64_t pressed = 0;
bool exact = true;
float strength = 0.0f;
float raw_strength = 0.0f;
+ LocalVector<float> strengths;
+ LocalVector<float> raw_strengths;
+
+ Action() {
+ strengths.resize(MAX_EVENT + 1);
+ raw_strengths.resize(MAX_EVENT + 1);
+
+ for (uint64_t i = 0; i <= MAX_EVENT; i++) {
+ strengths[i] = 0.0;
+ raw_strengths[i] = 0.0;
+ }
+ }
};
HashMap<StringName, Action> action_state;
@@ -227,6 +240,8 @@ private:
JoyAxis _get_output_axis(String output);
void _button_event(int p_device, JoyButton p_index, bool p_pressed);
void _axis_event(int p_device, JoyAxis p_axis, float p_value);
+ void _update_action_strength(Action &p_action, int p_event_index, float p_strength);
+ void _update_action_raw_strength(Action &p_action, int p_event_index, float p_strength);
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ddfde0e7cd..78b9ada884 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -127,16 +127,21 @@ List<StringName> InputMap::get_actions() const {
return actions;
}
-List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
+List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
+ int i = 0;
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
int device = E->get()->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
+ if (r_event_index) {
+ *r_event_index = i;
+ }
return E;
}
}
+ i++;
}
return nullptr;
@@ -179,6 +184,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
if (E) {
input_map[p_action].inputs.erase(E);
+
if (Input::get_singleton()->is_action_pressed(p_action)) {
Input::get_singleton()->action_release(p_action);
}
@@ -216,7 +222,13 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
return event_get_action_status(p_event, p_action, p_exact_match);
}
-bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength) const {
+int InputMap::event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
+ int index = -1;
+ event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index);
+ return index;
+}
+
+bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const {
HashMap<StringName, Action>::Iterator E = input_map.find(p_action);
ERR_FAIL_COND_V_MSG(!E, false, suggest_actions(p_action));
@@ -236,7 +248,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
return input_event_action->get_action() == p_action;
}
- List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength);
+ List<Ref<InputEvent>>::Element *event = _find_event(E->value, p_event, p_exact_match, r_pressed, r_strength, r_raw_strength, r_event_index);
return event != nullptr;
}
diff --git a/core/input/input_map.h b/core/input/input_map.h
index b4d5beacb3..6407ea489e 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -61,7 +61,7 @@ private:
HashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
HashMap<String, List<Ref<InputEvent>>> default_builtin_with_overrides_cache;
- List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
+ List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
TypedArray<InputEvent> _action_get_events(const StringName &p_action);
TypedArray<StringName> _get_actions();
@@ -86,7 +86,8 @@ public:
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
- bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
+ int event_get_index(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
+ bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr, int *r_event_index = nullptr) const;
const HashMap<StringName, Action> &get_action_map() const;
void load_from_project_settings();
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 15d0182dfc..ce08b417a8 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -3773,7 +3773,7 @@ void Image::fix_alpha_edges() {
}
int closest_dist = max_dist;
- uint8_t closest_color[3];
+ uint8_t closest_color[3] = { 0 };
int from_x = MAX(0, j - max_radius);
int to_x = MIN(width - 1, j + max_radius);
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 79e4b207d4..3d384d9345 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -1621,8 +1621,10 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
encode_uint32(datalen, buf);
buf += 4;
const uint8_t *r = data.ptr();
- memcpy(buf, &r[0], datalen * datasize);
- buf += datalen * datasize;
+ if (r) {
+ memcpy(buf, &r[0], datalen * datasize);
+ buf += datalen * datasize;
+ }
}
r_len += 4 + datalen * datasize;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index e0d42a274a..64fa597a67 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -90,6 +90,10 @@ String Resource::get_path() const {
return path_cache;
}
+void Resource::set_path_cache(const String &p_path) {
+ path_cache = p_path;
+}
+
String Resource::generate_scene_unique_id() {
// Generate a unique enough hash, but still user-readable.
// If it's not unique it does not matter because the saver will try again.
diff --git a/core/io/resource.h b/core/io/resource.h
index a9b1a88f6b..610c2150db 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -103,6 +103,7 @@ public:
virtual void set_path(const String &p_path, bool p_take_over = false);
String get_path() const;
+ void set_path_cache(const String &p_path); // Set raw path without involving resource cache.
_FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); }
static String generate_scene_unique_id();
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index ea97e5ecce..2a33f723dc 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -774,6 +774,8 @@ Error ResourceLoaderBinary::load() {
res = Ref<Resource>(r);
if (!path.is_empty() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it
+ } else if (!path.is_resource_file()) {
+ r->set_path_cache(path);
}
r->set_scene_unique_id(id);
}
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 0089544caa..e17644058a 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -136,6 +136,7 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const = 0;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const = 0;
+ virtual void handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {}
virtual String get_option_group_file() const { return String(); }
virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) = 0;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index f7915261af..b1ebdff91f 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -341,6 +341,8 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
if (load_task.resource.is_valid()) {
if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
load_task.resource->set_path(load_task.local_path);
+ } else if (!load_task.local_path.is_resource_file()) {
+ load_task.resource->set_path_cache(load_task.local_path);
}
if (load_task.xl_remapped) {
@@ -1053,8 +1055,9 @@ void ResourceLoader::clear_thread_load_tasks() {
thread_load_mutex.lock();
}
- for (KeyValue<String, LoadToken *> &E : user_load_tokens) {
- memdelete(E.value);
+ while (user_load_tokens.begin()) {
+ // User load tokens remove themselves from the map on destruction.
+ memdelete(user_load_tokens.begin()->value);
}
user_load_tokens.clear();
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index 216fc24fff..edff3e1f14 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -35,6 +35,8 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+// These constants are off by 1, causing the 'z' and '9' characters never to be used.
+// This cannot be fixed without breaking compatibility; see GH-83843.
static constexpr uint32_t char_count = ('z' - 'a');
static constexpr uint32_t base = char_count + ('9' - '0');
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 0e5702e0af..b37fce9e9c 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -306,10 +306,12 @@ public:
Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points);
Vector<int> triangles;
+ triangles.resize(3 * tr.size());
+ int *ptr = triangles.ptrw();
for (int i = 0; i < tr.size(); i++) {
- triangles.push_back(tr[i].points[0]);
- triangles.push_back(tr[i].points[1]);
- triangles.push_back(tr[i].points[2]);
+ *ptr++ = tr[i].points[0];
+ *ptr++ = tr[i].points[1];
+ *ptr++ = tr[i].points[2];
}
return triangles;
}
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index c594f4a9b4..bf1bd0de93 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -98,9 +98,24 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
p_classes->push_back(E.key);
}
- p_classes->sort();
+ p_classes->sort_custom<StringName::AlphCompare>();
}
+#ifdef TOOLS_ENABLED
+void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
+ OBJTYPE_RLOCK;
+
+ for (const KeyValue<StringName, ClassInfo> &E : classes) {
+ if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
+ continue;
+ }
+ p_classes->push_back(E.key);
+ }
+
+ p_classes->sort_custom<StringName::AlphCompare>();
+}
+#endif
+
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
OBJTYPE_RLOCK;
@@ -165,8 +180,8 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
}
uint32_t ClassDB::get_api_hash(APIType p_api) {
- OBJTYPE_RLOCK;
#ifdef DEBUG_METHODS_ENABLED
+ OBJTYPE_WLOCK;
if (api_hashes_cache.has(p_api)) {
return api_hashes_cache[p_api];
@@ -175,7 +190,9 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG));
List<StringName> class_list;
- ClassDB::get_class_list(&class_list);
+ for (const KeyValue<StringName, ClassInfo> &E : classes) {
+ class_list.push_back(E.key);
+ }
// Must be alphabetically sorted for hash to compute.
class_list.sort_custom<StringName::AlphCompare>();
@@ -859,8 +876,8 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_
}
void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) {
- OBJTYPE_RLOCK;
#ifdef DEBUG_METHODS_ENABLED
+ OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@@ -871,6 +888,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St
Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) {
#ifdef DEBUG_METHODS_ENABLED
+ OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL_V(type, Vector<Error>());
@@ -1415,6 +1433,8 @@ void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) {
}
void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) {
+ OBJTYPE_WLOCK;
+
ClassInfo *type = classes.getptr(p_class);
if (!type) {
ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'.");
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 5c2c59d508..7a4ee1afa4 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -251,6 +251,9 @@ public:
}
static void get_class_list(List<StringName> *p_classes);
+#ifdef TOOLS_ENABLED
+ static void get_extensions_class_list(List<StringName> *p_classes);
+#endif
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static StringName get_parent_class_nocheck(const StringName &p_class);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 2e5b897bce..40df13849b 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -198,6 +198,7 @@ bool Object::_predelete() {
notification(NOTIFICATION_PREDELETE, true);
if (_predelete_ok) {
_class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
+ notification(NOTIFICATION_PREDELETE_CLEANUP, true);
}
return _predelete_ok;
}
diff --git a/core/object/object.h b/core/object/object.h
index a444db0f70..f3c387594b 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -801,6 +801,8 @@ public:
NOTIFICATION_POSTINITIALIZE = 0,
NOTIFICATION_PREDELETE = 1,
NOTIFICATION_EXTENSION_RELOADED = 2,
+ // Internal notification to send after NOTIFICATION_PREDELETE, not bound to scripting.
+ NOTIFICATION_PREDELETE_CLEANUP = 3,
};
/* TYPE API */
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 011f4203ea..2bdbfb5ad1 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -39,10 +39,11 @@
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
+bool ScriptServer::languages_ready = false;
+Mutex ScriptServer::languages_mutex;
bool ScriptServer::scripting_enabled = true;
bool ScriptServer::reload_scripts_on_save = false;
-SafeFlag ScriptServer::languages_finished; // Used until GH-76581 is fixed properly.
ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr;
void Script::_notification(int p_what) {
@@ -160,12 +161,13 @@ bool ScriptServer::is_scripting_enabled() {
}
ScriptLanguage *ScriptServer::get_language(int p_idx) {
+ MutexLock lock(languages_mutex);
ERR_FAIL_INDEX_V(p_idx, _language_count, nullptr);
-
return _languages[p_idx];
}
Error ScriptServer::register_language(ScriptLanguage *p_language) {
+ MutexLock lock(languages_mutex);
ERR_FAIL_NULL_V(p_language, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(_language_count >= MAX_LANGUAGES, ERR_UNAVAILABLE, "Script languages limit has been reach, cannot register more.");
for (int i = 0; i < _language_count; i++) {
@@ -179,6 +181,8 @@ Error ScriptServer::register_language(ScriptLanguage *p_language) {
}
Error ScriptServer::unregister_language(const ScriptLanguage *p_language) {
+ MutexLock lock(languages_mutex);
+
for (int i = 0; i < _language_count; i++) {
if (_languages[i] == p_language) {
_language_count--;
@@ -219,17 +223,31 @@ void ScriptServer::init_languages() {
}
}
- for (int i = 0; i < _language_count; i++) {
- _languages[i]->init();
+ {
+ MutexLock lock(languages_mutex);
+
+ for (int i = 0; i < _language_count; i++) {
+ _languages[i]->init();
+ }
+
+ languages_ready = true;
}
}
void ScriptServer::finish_languages() {
+ MutexLock lock(languages_mutex);
+
for (int i = 0; i < _language_count; i++) {
_languages[i]->finish();
}
global_classes_clear();
- languages_finished.set();
+
+ languages_ready = false;
+}
+
+bool ScriptServer::are_languages_initialized() {
+ MutexLock lock(languages_mutex);
+ return languages_ready;
}
void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
@@ -241,7 +259,8 @@ bool ScriptServer::is_reload_scripts_on_save_enabled() {
}
void ScriptServer::thread_enter() {
- if (!languages_finished.is_set()) {
+ MutexLock lock(languages_mutex);
+ if (!languages_ready) {
return;
}
for (int i = 0; i < _language_count; i++) {
@@ -250,7 +269,8 @@ void ScriptServer::thread_enter() {
}
void ScriptServer::thread_exit() {
- if (!languages_finished.is_set()) {
+ MutexLock lock(languages_mutex);
+ if (!languages_ready) {
return;
}
for (int i = 0; i < _language_count; i++) {
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 3e4041d173..85e64c8d62 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -52,9 +52,11 @@ class ScriptServer {
static ScriptLanguage *_languages[MAX_LANGUAGES];
static int _language_count;
+ static bool languages_ready;
+ static Mutex languages_mutex;
+
static bool scripting_enabled;
static bool reload_scripts_on_save;
- static SafeFlag languages_finished; // Used until GH-76581 is fixed properly.
struct GlobalScriptClass {
StringName language;
@@ -98,8 +100,7 @@ public:
static void init_languages();
static void finish_languages();
-
- static bool are_languages_finished() { return languages_finished.is_set(); }
+ static bool are_languages_initialized();
};
class PlaceHolderScriptInstance;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 5f3a70cad8..00ab1cd6c0 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -313,6 +313,9 @@ public:
ERR_CONTINUE(!err.has("message"));
ScriptError serr;
+ if (err.has("path")) {
+ serr.path = err["path"];
+ }
serr.line = err["line"];
serr.column = err["column"];
serr.message = err["message"];
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index a8f2ac5bfe..1d0dff526d 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -463,6 +463,10 @@ bool UndoRedo::has_redo() const {
return (current_action + 1) < actions.size();
}
+bool UndoRedo::is_merging() const {
+ return merging;
+}
+
uint64_t UndoRedo::get_version() const {
return version;
}
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 74a6bea732..b3a3322e4b 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -131,6 +131,8 @@ public:
bool has_undo() const;
bool has_redo() const;
+ bool is_merging() const;
+
uint64_t get_version() const;
void set_commit_notify_callback(CommitNotifyCallback p_callback, void *p_ud);
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 2fcd0867e6..784acadab4 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -30,6 +30,7 @@
#include "worker_thread_pool.h"
+#include "core/object/script_language.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"
@@ -60,6 +61,14 @@ void WorkerThreadPool::_process_task(Task *p_task) {
set_current_thread_safe_for_nodes(false);
pool_thread_index = thread_ids[Thread::get_caller_id()];
ThreadData &curr_thread = threads[pool_thread_index];
+ // Since the WorkerThreadPool is started before the script server,
+ // its pre-created threads can't have ScriptServer::thread_enter() called on them early.
+ // Therefore, we do it late at the first opportunity, so in case the task
+ // about to be run uses scripting, guarantees are held.
+ if (!curr_thread.ready_for_scripting && ScriptServer::are_languages_initialized()) {
+ ScriptServer::thread_enter();
+ curr_thread.ready_for_scripting = true;
+ }
task_mutex.lock();
p_task->pool_thread_index = pool_thread_index;
if (low_priority) {
diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h
index d4d9387765..f323a979f7 100644
--- a/core/object/worker_thread_pool.h
+++ b/core/object/worker_thread_pool.h
@@ -106,6 +106,7 @@ private:
uint32_t index;
Thread thread;
Task *current_low_prio_task = nullptr;
+ bool ready_for_scripting = false;
};
TightLocalVector<ThreadData> threads;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 991b179e1f..c7390f14ff 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -490,6 +490,12 @@ bool OS::has_feature(const String &p_feature) {
}
#endif
+#if defined(IOS_SIMULATOR)
+ if (p_feature == "simulator") {
+ return true;
+ }
+#endif
+
if (_check_internal_feature_support(p_feature)) {
return true;
}
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 5a8df07410..658297d805 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -122,7 +122,7 @@ void StringName::unref() {
if (_data && _data->refcount.unref()) {
MutexLock lock(mutex);
- if (_data->static_count.get() > 0) {
+ if (CoreGlobals::leak_reporting_enabled && _data->static_count.get() > 0) {
if (_data->cname) {
ERR_PRINT("BUG: Unreferenced static string to 0: " + String(_data->cname));
} else {
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 9be7c04158..60e2d539f8 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -4699,11 +4699,16 @@ String String::property_name_encode() const {
static const char32_t invalid_node_name_characters[] = { '.', ':', '@', '/', '\"', UNIQUE_NODE_PREFIX[0], 0 };
-String String::get_invalid_node_name_characters() {
+String String::get_invalid_node_name_characters(bool p_allow_internal) {
// Do not use this function for critical validation.
String r;
const char32_t *c = invalid_node_name_characters;
while (*c) {
+ if (p_allow_internal && *c == '@') {
+ c++;
+ continue;
+ }
+
if (c != invalid_node_name_characters) {
r += " ";
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index f45392eee1..897b06fc6d 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -437,7 +437,7 @@ public:
String property_name_encode() const;
// node functions
- static String get_invalid_node_name_characters();
+ static String get_invalid_node_name_characters(bool p_allow_internal = false);
String validate_node_name() const;
String validate_identifier() const;
String validate_filename() const;
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 09fb34e7c1..4c0212075b 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -1291,7 +1291,13 @@ void Variant::zero() {
break;
default:
+ Type prev_type = type;
this->clear();
+ if (type != prev_type) {
+ // clear() changes type to NIL, so it needs to be restored.
+ Callable::CallError ce;
+ Variant::construct(prev_type, *this, nullptr, 0, ce);
+ }
break;
}
}