diff options
36 files changed, 174 insertions, 63 deletions
diff --git a/SConstruct b/SConstruct index 8e9a536bdc..f3331f3b0d 100644 --- a/SConstruct +++ b/SConstruct @@ -700,12 +700,11 @@ if env.msvc: else: env.Append(LINKFLAGS=["/DEBUG:NONE"]) - if env["optimize"] == "speed": + if env["optimize"].startswith("speed"): env.Append(CCFLAGS=["/O2"]) env.Append(LINKFLAGS=["/OPT:REF"]) - elif env["optimize"] == "speed_trace": - env.Append(CCFLAGS=["/O2"]) - env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"]) + if env["optimize"] == "speed_trace": + env.Append(LINKFLAGS=["/OPT:NOICF"]) elif env["optimize"] == "size": env.Append(CCFLAGS=["/O1"]) env.Append(LINKFLAGS=["/OPT:REF"]) @@ -716,7 +715,13 @@ else: # Adding dwarf-4 explicitly makes stacktraces work with clang builds, # otherwise addr2line doesn't understand them env.Append(CCFLAGS=["-gdwarf-4"]) - if env.dev_build: + if methods.using_emcc(env): + # Emscripten only produces dwarf symbols when using "-g3". + env.Append(CCFLAGS=["-g3"]) + # Emscripten linker needs debug symbols options too. + env.Append(LINKFLAGS=["-gdwarf-4"]) + env.Append(LINKFLAGS=["-g3"]) + elif env.dev_build: env.Append(CCFLAGS=["-g3"]) else: env.Append(CCFLAGS=["-g2"]) @@ -731,17 +736,25 @@ else: else: env.Append(LINKFLAGS=["-s"]) + # Linker needs optimization flags too, at least for Emscripten. + # For other toolchains, this _may_ be useful for LTO too to disambiguate. + if env["optimize"] == "speed": env.Append(CCFLAGS=["-O3"]) + env.Append(LINKFLAGS=["-O3"]) # `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. elif env["optimize"] == "speed_trace": env.Append(CCFLAGS=["-O2"]) + env.Append(LINKFLAGS=["-O2"]) elif env["optimize"] == "size": env.Append(CCFLAGS=["-Os"]) + env.Append(LINKFLAGS=["-Os"]) elif env["optimize"] == "debug": env.Append(CCFLAGS=["-Og"]) + env.Append(LINKFLAGS=["-Og"]) elif env["optimize"] == "none": env.Append(CCFLAGS=["-O0"]) + env.Append(LINKFLAGS=["-O0"]) # Needs to happen after configure to handle "auto". if env["lto"] != "none": diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index eac1a66be7..e59f79fcc8 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -329,9 +329,9 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { String path = p_value; if (path.begins_with("*")) { autoload.is_singleton = true; - autoload.path = path.substr(1); + autoload.path = path.substr(1).simplify_path(); } else { - autoload.path = path; + autoload.path = path.simplify_path(); } add_autoload(autoload); } else if (p_name.operator String().begins_with("global_group/")) { diff --git a/doc/classes/PhysicsPointQueryParameters2D.xml b/doc/classes/PhysicsPointQueryParameters2D.xml index 521e584173..642e87947a 100644 --- a/doc/classes/PhysicsPointQueryParameters2D.xml +++ b/doc/classes/PhysicsPointQueryParameters2D.xml @@ -24,6 +24,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsPointQueryParameters3D.xml b/doc/classes/PhysicsPointQueryParameters3D.xml index 1cbc11bd03..a53300c78d 100644 --- a/doc/classes/PhysicsPointQueryParameters3D.xml +++ b/doc/classes/PhysicsPointQueryParameters3D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)"> The position being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml index 3d69e092f6..a9738b4690 100644 --- a/doc/classes/PhysicsRayQueryParameters2D.xml +++ b/doc/classes/PhysicsRayQueryParameters2D.xml @@ -36,6 +36,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="from" type="Vector2" setter="set_from" getter="get_from" default="Vector2(0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsRayQueryParameters3D.xml b/doc/classes/PhysicsRayQueryParameters3D.xml index b203b8f555..175b594fb0 100644 --- a/doc/classes/PhysicsRayQueryParameters3D.xml +++ b/doc/classes/PhysicsRayQueryParameters3D.xml @@ -36,6 +36,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="from" type="Vector3" setter="set_from" getter="get_from" default="Vector3(0, 0, 0)"> The starting point of the ray being queried for, in global coordinates. diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 915d94a54c..3687a4dc5a 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject2D.get_rid] to get the [RID] associated with a [CollisionObject2D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index eba2b8287f..f05322f1ab 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -20,6 +20,7 @@ </member> <member name="exclude" type="RID[]" setter="set_exclude" getter="get_exclude" default="[]"> The list of object [RID]s that will be excluded from collisions. Use [method CollisionObject3D.get_rid] to get the [RID] associated with a [CollisionObject3D]-derived node. + [b]Note:[/b] The returned array is copied and any changes to it will not update the original property value. To update the value you need to modify the returned array, and then assign it to the property again. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 9a0f2f18fa..72ab186036 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -423,8 +423,8 @@ EditorExport::EditorExport() { save_timer->set_one_shot(true); save_timer->connect("timeout", callable_mp(this, &EditorExport::_save)); - _export_presets_updated = "export_presets_updated"; - _export_presets_runnable_updated = "export_presets_runnable_updated"; + _export_presets_updated = StringName("export_presets_updated", true); + _export_presets_runnable_updated = StringName("export_presets_runnable_updated", true); singleton = this; set_process(true); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index 3e94310c83..2b2ce42b9b 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -1968,6 +1968,7 @@ void EditorFileDialog::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "name"), defaults.name, &EditorFileDialog::set_option_name, &EditorFileDialog::get_option_name); base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &EditorFileDialog::set_option_values, &EditorFileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &EditorFileDialog::set_option_default, &EditorFileDialog::get_option_default); + PropertyListHelper::register_base_helper(&base_property_helper); } void EditorFileDialog::set_show_hidden_files(bool p_show) { diff --git a/main/main.cpp b/main/main.cpp index 060b3fe2f6..32eb32142d 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -60,6 +60,7 @@ #include "platform/register_platform_apis.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" +#include "scene/property_list_helper.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" #include "scene/theme/theme_db.h" @@ -793,6 +794,7 @@ void Main::test_cleanup() { ResourceLoader::remove_custom_loaders(); ResourceSaver::remove_custom_savers(); + PropertyListHelper::clear_base_helpers(); #ifdef TOOLS_ENABLED GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR); @@ -4246,6 +4248,7 @@ void Main::cleanup(bool p_force) { ResourceLoader::remove_custom_loaders(); ResourceSaver::remove_custom_savers(); + PropertyListHelper::clear_base_helpers(); // Flush before uninitializing the scene, but delete the MessageQueue as late as possible. message_queue->flush(); diff --git a/methods.py b/methods.py index 99c47ca077..b0f7df9ab2 100644 --- a/methods.py +++ b/methods.py @@ -268,7 +268,7 @@ def get_version_info(module_version_string="", silent=False): if os.path.exists(".git"): try: version_info["git_timestamp"] = subprocess.check_output( - ["git", "log", "-1", "--pretty=format:%ct", githash] + ["git", "log", "-1", "--pretty=format:%ct", "--no-show-signature", githash] ).decode("utf-8") except (subprocess.CalledProcessError, OSError): # `git` not found in PATH. @@ -648,6 +648,7 @@ def detect_visual_c_compiler_version(tools_env): def find_visual_c_batch_file(env): + # TODO: We should investigate if we can avoid relying on SCons internals here. from SCons.Tool.MSCommon.vc import find_batch_file, find_vc_pdir, get_default_version, get_host_target msvc_version = get_default_version(env) @@ -661,10 +662,11 @@ def find_visual_c_batch_file(env): if env.scons_version < (4, 6, 0): return find_batch_file(env, msvc_version, host_platform, target_platform)[0] - # Scons 4.6.0+ removed passing env, so we need to get the product_dir ourselves first, + # SCons 4.6.0+ removed passing env, so we need to get the product_dir ourselves first, # then pass that as the last param instead of env as the first param as before. - # We should investigate if we can avoid relying on SCons internals here. - product_dir = find_vc_pdir(env, msvc_version) + # Param names need to be explicit, as they were shuffled around in SCons 4.8.0. + product_dir = find_vc_pdir(msvc_version=msvc_version, env=env) + return find_batch_file(msvc_version, host_platform, target_platform, product_dir)[0] diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a1ea94667d..433f767f1e 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -413,7 +413,7 @@ Error GDScriptParser::parse_binary(const Vector<uint8_t> &p_binary, const String } tokenizer = buffer_tokenizer; - script_path = p_script_path; + script_path = p_script_path.simplify_path(); current = tokenizer->scan(); // Avoid error or newline as the first token. // The latter can mess with the parser when opening files filled exclusively with comments and newlines. diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 5d1805696d..912367764b 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -550,9 +550,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a return _get_default_variant_for_data_type(return_type); } if (argument_types[i].kind == GDScriptDataType::BUILTIN) { - Variant arg; - Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err); - memnew_placement(&stack[i + 3], Variant(arg)); + if (argument_types[i].builtin_type == Variant::ARRAY && argument_types[i].has_container_element_type(0)) { + const GDScriptDataType &arg_type = argument_types[i].container_element_types[0]; + Array array(p_args[i]->operator Array(), arg_type.builtin_type, arg_type.native_type, arg_type.script_type); + memnew_placement(&stack[i + 3], Variant(array)); + } else { + Variant variant; + Variant::construct(argument_types[i].builtin_type, variant, &p_args[i], 1, r_err); + if (unlikely(r_err.error)) { + r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].builtin_type; + call_depth--; + return _get_default_variant_for_data_type(return_type); + } + memnew_placement(&stack[i + 3], Variant(variant)); + } } else { memnew_placement(&stack[i + 3], Variant(*p_args[i])); } diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd new file mode 100644 index 0000000000..13f2c3b956 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.gd @@ -0,0 +1,7 @@ +# GH-93990 + +func test_param(array: Array[String]) -> void: + print(array.get_typed_builtin() == TYPE_STRING) + +func test() -> void: + test_param(PackedStringArray()) diff --git a/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out new file mode 100644 index 0000000000..55482c2b52 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/typed_array_implicit_cast_param.out @@ -0,0 +1,2 @@ +GDTEST_OK +true diff --git a/platform/ios/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm index 8b614662b7..4067701a41 100644 --- a/platform/ios/keyboard_input_view.mm +++ b/platform/ios/keyboard_input_view.mm @@ -149,23 +149,18 @@ return; } + NSString *substringToDelete = nil; if (self.previousSelectedRange.length == 0) { - // We are deleting all text before cursor if no range was selected. - // This way any inserted or changed text will be updated. - NSString *substringToDelete = [self.previousText substringToIndex:self.previousSelectedRange.location]; - [self deleteText:substringToDelete.length]; + // Get previous text to delete. + substringToDelete = [self.previousText substringToIndex:self.previousSelectedRange.location]; } else { - // If text was previously selected - // we are sending only one `backspace`. - // It will remove all text from text input. + // If text was previously selected we are sending only one `backspace`. It will remove all text from text input. [self deleteText:1]; } - NSString *substringToEnter; - + NSString *substringToEnter = nil; if (self.selectedRange.length == 0) { - // If previous cursor had a selection - // we have to calculate an inserted text. + // If previous cursor had a selection we have to calculate an inserted text. if (self.previousSelectedRange.length != 0) { NSInteger rangeEnd = self.selectedRange.location + self.selectedRange.length; NSInteger rangeStart = MIN(self.previousSelectedRange.location, self.selectedRange.location); @@ -187,7 +182,18 @@ substringToEnter = [self.text substringWithRange:self.selectedRange]; } - [self enterText:substringToEnter]; + NSInteger skip = 0; + if (substringToDelete != nil) { + for (NSInteger i = 0; i < MIN([substringToDelete length], [substringToEnter length]); i++) { + if ([substringToDelete characterAtIndex:i] == [substringToEnter characterAtIndex:i]) { + skip++; + } else { + break; + } + } + [self deleteText:[substringToDelete length] - skip]; // Delete changed part of previous text. + } + [self enterText:[substringToEnter substringFromIndex:skip]]; // Enter changed part of new text. self.previousText = self.text; self.previousSelectedRange = self.selectedRange; diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 3534c1afee..a67428b9a4 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -374,6 +374,12 @@ void JoypadLinux::open_joypad(const char *p_path) { name = namebuf; } + for (const String &word : name.to_lower().split(" ")) { + if (banned_words.has(word)) { + return; + } + } + if (ioctl(fd, EVIOCGID, &inpid) < 0) { close(fd); return; diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 26a9908d4e..bf24d8e5a5 100644 --- a/platform/linuxbsd/joypad_linux.h +++ b/platform/linuxbsd/joypad_linux.h @@ -94,6 +94,21 @@ private: Vector<String> attached_devices; + // List of lowercase words that will prevent the controller from being recognized if its name matches. + // This is done to prevent trackpads, graphics tablets and motherboard LED controllers from being + // recognized as controllers (and taking up controller ID slots as a result). + // Only whole words are matched within the controller name string. The match is case-insensitive. + const Vector<String> banned_words = { + "touchpad", // Matches e.g. "SynPS/2 Synaptics TouchPad", "Sony Interactive Entertainment DualSense Wireless Controller Touchpad" + "trackpad", + "clickpad", + "keyboard", // Matches e.g. "PG-90215 Keyboard", "Usb Keyboard Usb Keyboard Consumer Control" + "mouse", // Matches e.g. "Mouse passthrough" + "pen", // Matches e.g. "Wacom One by Wacom S Pen" + "finger", // Matches e.g. "Wacom HID 495F Finger" + "led", // Matches e.g. "ASRock LED Controller" + }; + static void monitor_joypads_thread_func(void *p_user); void monitor_joypads_thread_run(); diff --git a/scene/2d/parallax_2d.cpp b/scene/2d/parallax_2d.cpp index b3586a1da0..9dd9d4a376 100644 --- a/scene/2d/parallax_2d.cpp +++ b/scene/2d/parallax_2d.cpp @@ -31,6 +31,7 @@ #include "parallax_2d.h" #include "core/config/project_settings.h" +#include "scene/main/viewport.h" void Parallax2D::_notification(int p_what) { switch (p_what) { @@ -72,7 +73,11 @@ void Parallax2D::_validate_property(PropertyInfo &p_property) const { void Parallax2D::_camera_moved(const Transform2D &p_transform, const Point2 &p_screen_offset, const Point2 &p_adj_screen_pos) { if (!ignore_camera_scroll) { - set_screen_offset(p_adj_screen_pos); + if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) { + set_screen_offset((p_adj_screen_pos + Vector2(0.5, 0.5)).floor()); + } else { + set_screen_offset(p_adj_screen_pos); + } } } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index d1f1c97ca2..48ade1e5cc 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -996,6 +996,7 @@ TileMap::TileMap() { base_property_helper.register_property(PropertyInfo(Variant::INT, "z_index"), defaults->get_z_index(), &TileMap::set_layer_z_index, &TileMap::get_layer_z_index); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "navigation_enabled"), defaults->is_navigation_enabled(), &TileMap::set_layer_navigation_enabled, &TileMap::is_layer_navigation_enabled); base_property_helper.register_property(PropertyInfo(Variant::PACKED_INT32_ARRAY, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Vector<int>(), &TileMap::_set_layer_tile_data, &TileMap::_get_tile_map_data_using_compatibility_format); + PropertyListHelper::register_base_helper(&base_property_helper); memdelete(defaults); } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index c9372525bd..8047369ab1 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -1350,6 +1350,7 @@ void FileDialog::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "name"), defaults.name, &FileDialog::set_option_name, &FileDialog::get_option_name); base_property_helper.register_property(PropertyInfo(Variant::PACKED_STRING_ARRAY, "values"), defaults.values, &FileDialog::set_option_values, &FileDialog::get_option_values); base_property_helper.register_property(PropertyInfo(Variant::INT, "default"), defaults.default_idx, &FileDialog::set_option_default, &FileDialog::get_option_default); + PropertyListHelper::register_base_helper(&base_property_helper); } void FileDialog::set_show_hidden_files(bool p_show) { diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 933b4df6e3..bf16c0699e 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1905,6 +1905,7 @@ void ItemList::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &ItemList::set_item_icon, &ItemList::get_item_icon); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "selectable"), defaults.selectable, &ItemList::set_item_selectable, &ItemList::is_item_selectable); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &ItemList::set_item_disabled, &ItemList::is_item_disabled); + PropertyListHelper::register_base_helper(&base_property_helper); } ItemList::ItemList() { diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 998f99b2f9..e99187d283 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -198,6 +198,7 @@ void MenuButton::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void MenuButton::set_disable_shortcuts(bool p_disabled) { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index da15b44bdc..a1425fb847 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -577,6 +577,7 @@ void OptionButton::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id, &OptionButton::_dummy_setter, &OptionButton::get_item_id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &OptionButton::_dummy_setter, &OptionButton::is_item_disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator, &OptionButton::_dummy_setter, &OptionButton::is_item_separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void OptionButton::set_disable_shortcuts(bool p_disabled) { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 7f795ea710..f62421061b 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -2824,6 +2824,7 @@ void PopupMenu::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), defaults.id, &PopupMenu::set_item_id, &PopupMenu::get_item_id); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &PopupMenu::set_item_disabled, &PopupMenu::is_item_disabled); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "separator"), defaults.separator, &PopupMenu::set_item_as_separator, &PopupMenu::is_item_separator); + PropertyListHelper::register_base_helper(&base_property_helper); } void PopupMenu::popup(const Rect2i &p_bounds) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8ffa0f8c63..5ef02bf19d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2098,7 +2098,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { handled = true; } if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) { - vscroll->scroll(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size)); + vscroll->scroll(theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) { @@ -4947,10 +4947,10 @@ void RichTextLabel::append_text(const String &p_bbcode) { tag_stack.push_front("outline_size"); } else if (bbcode_name == "fade") { - int start_index = 0; + int start_index = brk_pos; OptionMap::Iterator start_option = bbcode_options.find("start"); if (start_option) { - start_index = start_option->value.to_int(); + start_index += start_option->value.to_int(); } int length = 10; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index ddc757c452..1ae18f5728 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -1873,6 +1873,7 @@ void TabBar::_bind_methods() { base_property_helper.register_property(PropertyInfo(Variant::STRING, "tooltip"), defaults.tooltip, &TabBar::set_tab_tooltip, &TabBar::get_tab_tooltip); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), defaults.icon, &TabBar::set_tab_icon, &TabBar::get_tab_icon); base_property_helper.register_property(PropertyInfo(Variant::BOOL, "disabled"), defaults.disabled, &TabBar::set_tab_disabled, &TabBar::is_tab_disabled); + PropertyListHelper::register_base_helper(&base_property_helper); } TabBar::TabBar() { diff --git a/scene/property_list_helper.cpp b/scene/property_list_helper.cpp index ce258ee8c3..f840aaa759 100644 --- a/scene/property_list_helper.cpp +++ b/scene/property_list_helper.cpp @@ -30,6 +30,19 @@ #include "property_list_helper.h" +Vector<PropertyListHelper *> PropertyListHelper::base_helpers; // static + +void PropertyListHelper::clear_base_helpers() { // static + for (PropertyListHelper *helper : base_helpers) { + helper->clear(); + } + base_helpers.clear(); +} + +void PropertyListHelper::register_base_helper(PropertyListHelper *p_helper) { // static + base_helpers.push_back(p_helper); +} + const PropertyListHelper::Property *PropertyListHelper::_get_property(const String &p_property, int *r_index) const { const Vector<String> components = p_property.rsplit("/", true, 1); if (components.size() < 2 || !components[0].begins_with(prefix)) { @@ -176,9 +189,8 @@ bool PropertyListHelper::property_get_revert(const String &p_property, Variant & return false; } -PropertyListHelper::~PropertyListHelper() { - // No object = it's the main helper. Do a cleanup. - if (!object && is_initialized()) { +void PropertyListHelper::clear() { + if (is_initialized()) { memdelete(array_length_getter); for (const KeyValue<String, Property> &E : property_list) { @@ -187,5 +199,6 @@ PropertyListHelper::~PropertyListHelper() { memdelete(E.value.getter); } } + property_list.clear(); } } diff --git a/scene/property_list_helper.h b/scene/property_list_helper.h index 6bc65f6e3e..1ab923e76d 100644 --- a/scene/property_list_helper.h +++ b/scene/property_list_helper.h @@ -42,6 +42,8 @@ class PropertyListHelper { MethodBind *getter = nullptr; }; + static Vector<PropertyListHelper *> base_helpers; + String prefix; MethodBind *array_length_getter = nullptr; HashMap<String, Property> property_list; @@ -53,6 +55,9 @@ class PropertyListHelper { int _call_array_length_getter() const; public: + static void clear_base_helpers(); + static void register_base_helper(PropertyListHelper *p_helper); + void set_prefix(const String &p_prefix); template <typename G> void set_array_length_getter(G p_array_length_getter) { @@ -83,7 +88,7 @@ public: bool property_can_revert(const String &p_property) const; bool property_get_revert(const String &p_property, Variant &r_value) const; - ~PropertyListHelper(); + void clear(); }; #endif // PROPERTY_LIST_HELPER_H diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 0dc6d16050..7ab150c141 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -741,6 +741,7 @@ void AudioStreamRandomizer::_bind_methods() { base_property_helper.set_array_length_getter(&AudioStreamRandomizer::get_streams_count); base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), defaults.stream, &AudioStreamRandomizer::set_stream, &AudioStreamRandomizer::get_stream); base_property_helper.register_property(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), defaults.weight, &AudioStreamRandomizer::set_stream_probability_weight, &AudioStreamRandomizer::get_stream_probability_weight); + PropertyListHelper::register_base_helper(&base_property_helper); } AudioStreamRandomizer::AudioStreamRandomizer() { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 0d83264bfb..af190207db 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -1018,11 +1018,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Draw Sky } - // rendering effects - if (ce_has_pre_transparent) { - _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); - } - if (merge_transparent_pass) { if (render_list[RENDER_LIST_ALPHA].element_info.size() > 0) { // transparent pass @@ -1058,6 +1053,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass + // rendering effects + if (ce_has_pre_transparent) { + _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); + } + if (scene_state.used_screen_texture) { // Copy screen texture to backbuffer so we can read from it _render_buffers_copy_screen_texture(p_render_data); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index f5e0b811a2..0b1595d988 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -39,6 +39,8 @@ #define HAS_WARNING(flag) (warning_flags & flag) +int ShaderLanguage::instance_counter = 0; + String ShaderLanguage::get_operator_text(Operator p_op) { static const char *op_names[OP_MAX] = { "==", "!=", @@ -10812,17 +10814,16 @@ ShaderLanguage::ShaderLanguage() { nodes = nullptr; completion_class = TAG_GLOBAL; - int idx = 0; - while (builtin_func_defs[idx].name) { - if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) { - const StringName &name = StringName(builtin_func_defs[idx].name); - - if (!global_func_set.has(name)) { - global_func_set.insert(name); + if (instance_counter == 0) { + int idx = 0; + while (builtin_func_defs[idx].name) { + if (builtin_func_defs[idx].tag == SubClassTag::TAG_GLOBAL) { + global_func_set.insert(builtin_func_defs[idx].name); } + idx++; } - idx++; } + instance_counter++; #ifdef DEBUG_ENABLED warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants); @@ -10837,5 +10838,8 @@ ShaderLanguage::ShaderLanguage() { ShaderLanguage::~ShaderLanguage() { clear(); - global_func_set.clear(); + instance_counter--; + if (instance_counter == 0) { + global_func_set.clear(); + } } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index edac819a1e..076bd8def4 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -800,6 +800,8 @@ public: static bool is_control_flow_keyword(String p_keyword); static void get_builtin_funcs(List<String> *r_keywords); + static int instance_counter; + struct BuiltInInfo { DataType type = TYPE_VOID; bool constant = false; diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index a9bc2e9b99..f8c5ef279d 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -93,9 +93,9 @@ void test_rotation(Vector3 deg_original_euler, EulerOrder rot_order) { Basis res = to_rotation.inverse() * rotation_from_computed_euler; - CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Fail due to X %s\n", String(res.get_column(0))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Fail due to Y %s\n", String(res.get_column(1))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_column(2))).utf8().ptr()); + CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Fail due to X %s\n", String(res.get_column(0)))); + CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Fail due to Y %s\n", String(res.get_column(1)))); + CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Fail due to Z %s\n", String(res.get_column(2)))); // Double check `to_rotation` decomposing with XYZ rotation order. const Vector3 euler_xyz_from_rotation = to_rotation.get_euler(EulerOrder::XYZ); @@ -103,13 +103,13 @@ void test_rotation(Vector3 deg_original_euler, EulerOrder rot_order) { res = to_rotation.inverse() * rotation_from_xyz_computed_euler; - CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to X %s\n", String(res.get_column(0))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Y %s\n", String(res.get_column(1))).utf8().ptr()); - CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Z %s\n", String(res.get_column(2))).utf8().ptr()); + CHECK_MESSAGE((res.get_column(0) - Vector3(1.0, 0.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to X %s\n", String(res.get_column(0)))); + CHECK_MESSAGE((res.get_column(1) - Vector3(0.0, 1.0, 0.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Y %s\n", String(res.get_column(1)))); + CHECK_MESSAGE((res.get_column(2) - Vector3(0.0, 0.0, 1.0)).length() <= 0.1, vformat("Double check with XYZ rot order failed, due to Z %s\n", String(res.get_column(2)))); - INFO(vformat("Rotation order: %s\n.", get_rot_order_name(rot_order)).utf8().ptr()); - INFO(vformat("Original Rotation: %s\n", String(deg_original_euler)).utf8().ptr()); - INFO(vformat("Quaternion to rotation order: %s\n", String(rad2deg(euler_from_rotation))).utf8().ptr()); + INFO(vformat("Rotation order: %s\n.", get_rot_order_name(rot_order))); + INFO(vformat("Original Rotation: %s\n", String(deg_original_euler))); + INFO(vformat("Quaternion to rotation order: %s\n", String(rad2deg(euler_from_rotation)))); } TEST_CASE("[Basis] Euler conversions") { diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h index 358bbc08a3..c1aa39031d 100644 --- a/tests/core/object/test_class_db.h +++ b/tests/core/object/test_class_db.h @@ -405,7 +405,7 @@ void validate_argument(const Context &p_context, const ExposedClass &p_class, co err_msg += " " + type_error_msg; } - TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data()); + TEST_COND(!arg_defval_assignable_to_type, err_msg); } } @@ -590,7 +590,7 @@ void add_exposed_classes(Context &r_context) { exposed_class.name, method.name); TEST_FAIL_COND_WARN( (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free"), - warn_msg.utf8().get_data()); + warn_msg); } else if (return_info.type == Variant::INT && return_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) { method.return_type.name = return_info.class_name; @@ -720,7 +720,7 @@ void add_exposed_classes(Context &r_context) { "Signal name conflicts with %s: '%s.%s.", method_conflict ? "method" : "property", class_name, signal.name); TEST_FAIL_COND((method_conflict || exposed_class.find_method_by_name(signal.name)), - warn_msg.utf8().get_data()); + warn_msg); exposed_class.signals_.push_back(signal); } |