diff options
50 files changed, 271 insertions, 196 deletions
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml index de8339bf1b..add5fa8154 100644 --- a/.github/workflows/web_builds.yml +++ b/.github/workflows/web_builds.yml @@ -6,7 +6,7 @@ on: env: # Used for the cache key. Add version suffix to force clean build. GODOT_BASE_BRANCH: master - SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no + SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes EM_VERSION: 3.1.59 EM_CACHE_FOLDER: "emsdk-cache" diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 04c81b9ddf..1e32c87c01 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -581,48 +581,6 @@ License: Apache-2.0 See the License for the specific language governing permissions and limitations under the License. -License: Bitstream Vera Fonts Copyright - Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a - trademark of Bitstream, Inc. - . - Permission is hereby granted, free of charge, to any person obtaining a copy of - the fonts accompanying this license ("Fonts") and associated documentation - files (the "Font Software"), to reproduce and distribute the Font Software, - including without limitation the rights to use, copy, merge, publish, - distribute, and/or sell copies of the Font Software, and to permit persons to - whom the Font Software is furnished to do so, subject to the following - conditions: - . - The above copyright and trademark notices and this permission notice shall be - included in all copies of one or more of the Font Software typefaces. - . - The Font Software may be modified, altered, or added to, and in particular the - designs of glyphs or characters in the Fonts may be modified and additional - glyphs or characters may be added to the Fonts, only if the fonts are renamed - to names not containing either the words "Bitstream" or the word "Vera". - . - This License becomes null and void to the extent applicable to Fonts or Font - Software that has been modified and is distributed under the "Bitstream Vera" - names. - . - The Font Software may be sold as part of a larger software package but no copy - of one or more of the Font Software typefaces may be sold by itself. - . - THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, - TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, - SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO - USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. - . - Except as contained in this notice, the names of GNOME, the GNOME Foundation, - and Bitstream Inc., shall not be used in advertising or otherwise to promote - the sale, use or other dealings in this Font Software without prior written - authorization from the GNOME Foundation or Bitstream Inc., respectively. For - further information, contact: fonts at gnome dot org. - License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h index b824044b82..5afdb884f6 100644 --- a/core/variant/variant_construct.h +++ b/core/variant/variant_construct.h @@ -153,11 +153,14 @@ public: class VariantConstructorObject { public: static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); if (p_args[0]->get_type() == Variant::NIL) { + VariantInternal::clear(&r_ret); + VariantTypeChanger<Object *>::change(&r_ret); VariantInternal::object_assign_null(&r_ret); r_error.error = Callable::CallError::CALL_OK; } else if (p_args[0]->get_type() == Variant::OBJECT) { + VariantInternal::clear(&r_ret); + VariantTypeChanger<Object *>::change(&r_ret); VariantInternal::object_assign(&r_ret, p_args[0]); r_error.error = Callable::CallError::CALL_OK; } else { @@ -169,6 +172,7 @@ public: static inline void validated_construct(Variant *r_ret, const Variant **p_args) { VariantInternal::clear(r_ret); + VariantTypeChanger<Object *>::change(r_ret); VariantInternal::object_assign(r_ret, p_args[0]); } static void ptr_construct(void *base, const void **p_args) { @@ -198,11 +202,13 @@ public: } VariantInternal::clear(&r_ret); + VariantTypeChanger<Object *>::change(&r_ret); VariantInternal::object_assign_null(&r_ret); } static inline void validated_construct(Variant *r_ret, const Variant **p_args) { VariantInternal::clear(r_ret); + VariantTypeChanger<Object *>::change(r_ret); VariantInternal::object_assign_null(r_ret); } static void ptr_construct(void *base, const void **p_args) { diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 3731b8dcf1..bd0e05f8e0 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -694,7 +694,7 @@ <method name="sort"> <return type="void" /> <description> - Sorts the array in ascending order. The final order is dependent on the "less than" ([code]>[/code]) comparison between elements. + Sorts the array in ascending order. The final order is dependent on the "less than" ([code]<[/code]) comparison between elements. [codeblocks] [gdscript] var numbers = [10, 5, 2.5, 8] diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b66e5bc091..d63c71a351 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -1074,7 +1074,7 @@ If [code]true[/code], allows scrolling past the end of the file. </member> <member name="text_editor/behavior/navigation/smooth_scrolling" type="bool" setter="" getter=""> - If [code]true[/code], allows scrolling in sub-line intervals and enables a smooth scrolling animation when using the mouse wheel to scroll. + If [code]true[/code], enables a smooth scrolling animation when using the mouse wheel to scroll. See [member text_editor/behavior/navigation/v_scroll_speed] for the speed of this animation. [b]Note:[/b] [member text_editor/behavior/navigation/smooth_scrolling] currently behaves poorly in projects where [member ProjectSettings.physics/common/physics_ticks_per_second] has been increased significantly from its default value ([code]60[/code]). In this case, it is recommended to disable this setting. </member> <member name="text_editor/behavior/navigation/stay_in_script_editor_on_node_selected" type="bool" setter="" getter=""> @@ -1087,7 +1087,7 @@ If [code]true[/code], uses the characters in [code]`!"#$%&'()*+,-./:;<=>?@[\]^`{|}~[/code], the Unicode General Punctuation table, and the Unicode CJK Punctuation table as word separators for word navigation and operations. If [code]false[/code], a subset of these characters are used and does not include the characters [code]<>$~^=+|[/code]. This is in addition to custom characters if [member text_editor/behavior/navigation/use_custom_word_separators] is also enabled. These characters are used to determine where a word stops. Word navigation and operations include double-clicking on a word or holding [kbd]Ctrl[/kbd] ([kbd]Cmd[/kbd] on macOS) while pressing [kbd]left[/kbd], [kbd]right[/kbd], [kbd]backspace[/kbd], or [kbd]delete[/kbd]. </member> <member name="text_editor/behavior/navigation/v_scroll_speed" type="int" setter="" getter=""> - The number of pixels to scroll with every mouse wheel increment. Higher values make the script scroll by faster when using the mouse wheel. + The speed of scrolling in lines per second when [member text_editor/behavior/navigation/smooth_scrolling] is [code]true[/code]. Higher values make the script scroll by faster when using the mouse wheel. [b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster. </member> <member name="text_editor/completion/add_node_path_literals" type="bool" setter="" getter=""> diff --git a/doc/classes/InputEventShortcut.xml b/doc/classes/InputEventShortcut.xml index 3c698fd4fb..414dd7e8ce 100644 --- a/doc/classes/InputEventShortcut.xml +++ b/doc/classes/InputEventShortcut.xml @@ -4,7 +4,7 @@ Represents a triggered keyboard [Shortcut]. </brief_description> <description> - InputEventShortcut is a special event that can be received in [method Node._unhandled_key_input]. It is typically sent by the editor's Command Palette to trigger actions, but can also be sent manually using [method Viewport.push_input]. + InputEventShortcut is a special event that can be received in [method Node._input], [method Node._shortcut_input], and [method Node._unhandled_input]. It is typically sent by the editor's Command Palette to trigger actions, but can also be sent manually using [method Viewport.push_input]. </description> <tutorials> </tutorials> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index bae5fe1205..77baef9d08 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -156,7 +156,7 @@ <param index="0" name="group" type="StringName" /> <param index="1" name="notification" type="int" /> <description> - Calls [method Object.notification] with the given [param notification] to all nodes inside this tree added to the [param group]. See also [method call_group] and [method set_group]. + Calls [method Object.notification] with the given [param notification] to all nodes inside this tree added to the [param group]. See also [url=$DOCS_URL/tutorials/best_practices/godot_notifications.html]Godot notifications[/url] and [method call_group] and [method set_group]. [b]Note:[/b] This method acts immediately on all selected nodes at once, which may cause stuttering in some performance-intensive situations. </description> </method> diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index b6636ca576..14188a42a0 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -43,6 +43,7 @@ #include "editor/inspector_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/themes/editor_scale.h" +#include "scene/3d/mesh_instance_3d.h" #include "scene/animation/animation_player.h" #include "scene/animation/tween.h" #include "scene/gui/check_box.h" @@ -5120,16 +5121,7 @@ void AnimationTrackEditor::_new_track_property_selected(const String &p_name) { Animation::InterpolationType interp_type = Animation::INTERPOLATION_LINEAR; bool loop_wrap = true; _fetch_value_track_options(full_path, &update_mode, &interp_type, &loop_wrap); - if (adding_track_type == Animation::TYPE_VALUE) { - undo_redo->create_action(TTR("Add Track")); - undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); - undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), full_path); - undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", animation->get_track_count(), interp_type); - undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", animation->get_track_count(), loop_wrap); - undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", animation->get_track_count(), update_mode); - undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count()); - undo_redo->commit_action(); - } else { + if (adding_track_type == Animation::TYPE_BEZIER) { Vector<String> subindices; { // Hack. @@ -5157,6 +5149,24 @@ void AnimationTrackEditor::_new_track_property_selected(const String &p_name) { undo_redo->add_undo_method(animation.ptr(), "remove_track", base_track); } undo_redo->commit_action(); + } else { + bool is_blend_shape = adding_track_type == Animation::TYPE_BLEND_SHAPE; + if (is_blend_shape) { + PackedStringArray split = p_name.split("/"); + if (!split.is_empty()) { + full_path = String(adding_track_path) + ":" + split[split.size() - 1]; + } + } + undo_redo->create_action(TTR("Add Track")); + undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); + undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), full_path); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", animation->get_track_count(), interp_type); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", animation->get_track_count(), loop_wrap); + if (!is_blend_shape) { + undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", animation->get_track_count(), update_mode); + } + undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count()); + undo_redo->commit_action(); } } @@ -5249,7 +5259,16 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { id.value = base->get_scale(); } break; - case Animation::TYPE_BLEND_SHAPE: + case Animation::TYPE_BLEND_SHAPE: { + MeshInstance3D *base = Object::cast_to<MeshInstance3D>(node); + + if (!base) { + EditorNode::get_singleton()->show_warning(TTR("Track is not of type MeshInstance3D, can't insert key")); + return; + } + + id.value = base->get_blend_shape_value(base->find_blend_shape_by_name(id.path.get_subname(0))); + } break; case Animation::TYPE_VALUE: { NodePath bp; _find_hint_for_track(p_track, bp, &id.value); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cb647ffc35..8b6d316dd1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3407,8 +3407,7 @@ void EditorNode::_discard_changes(const String &p_str) { } args.push_back("--project-manager"); - Error err = OS::get_singleton()->create_instance(args); - ERR_FAIL_COND(err); + OS::get_singleton()->set_restart_on_exit(true, args); } break; case RELOAD_CURRENT_PROJECT: { restart_editor(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f9be1b08d9..1afe2ddda7 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1796,7 +1796,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { bool symmetric = m->is_alt_pressed(); Rect2 local_rect = ci->_edit_get_rect(); - real_t aspect = local_rect.get_size().y / local_rect.get_size().x; + real_t aspect = local_rect.has_area() ? (local_rect.get_size().y / local_rect.get_size().x) : (local_rect.get_size().y + 1.0) / (local_rect.get_size().x + 1.0); Point2 current_begin = local_rect.get_position(); Point2 current_end = local_rect.get_position() + local_rect.get_size(); Point2 max_begin = (symmetric) ? (current_begin + current_end - ci->_edit_get_minimum_size()) / 2.0 : current_end - ci->_edit_get_minimum_size(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 72eea8a27e..bd720cde93 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1575,7 +1575,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { } else { Node *node_owner = node->get_owner(); if (node == edited_scene || node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) { - if (selection_results.has(node)) { + if (!selection_results.has(node)) { selection_results.append(node); } break; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d7b88511d9..9d1576cdf2 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -412,7 +412,7 @@ void ShaderEditorPlugin::_close_builtin_shaders_from_scene(const String &p_scene void ShaderEditorPlugin::_resource_saved(Object *obj) { // May have been renamed on save. for (EditedShader &edited_shader : edited_shaders) { - if (edited_shader.shader.ptr() == obj) { + if (edited_shader.shader.ptr() == obj || edited_shader.shader_inc.ptr() == obj) { _update_shader_list(); return; } diff --git a/main/main.cpp b/main/main.cpp index c7c0c08fad..e42469b51b 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2634,10 +2634,12 @@ Error Main::setup2(bool p_show_boot_logo) { } } - if (prefer_wayland) { - display_driver = "wayland"; - } else { - display_driver = "default"; + if (display_driver.is_empty()) { + if (prefer_wayland) { + display_driver = "wayland"; + } else { + display_driver = "default"; + } } } } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 13707de12a..d8b44a558f 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1901,7 +1901,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui case GDScriptParser::Node::MATCH: { const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s); - codegen.start_block(); // Add an extra block, since the binding pattern and @special variables belong to the branch scope. + codegen.start_block(); // Add an extra block, since @special locals belong to the match scope. // Evaluate the match expression. GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype(), codegen.script)); @@ -1939,7 +1939,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui const GDScriptParser::MatchBranchNode *branch = match->branches[j]; - codegen.start_block(); // Create an extra block around for binds. + codegen.start_block(); // Add an extra block, since binds belong to the match branch scope. // Add locals in block before patterns, so temporaries don't use the stack address for binds. List<GDScriptCodeGenerator::Address> branch_locals = _add_block_locals(codegen, branch->block); @@ -1991,13 +1991,15 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui _clear_block_locals(codegen, branch_locals); - codegen.end_block(); // Get out of extra block. + codegen.end_block(); // Get out of extra block for binds. } // End all nested `if`s. for (int j = 0; j < match->branches.size(); j++) { gen->write_endif(); } + + codegen.end_block(); // Get out of extra block for match's @special locals. } break; case GDScriptParser::Node::IF: { const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s); @@ -2031,7 +2033,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui case GDScriptParser::Node::FOR: { const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s); - codegen.start_block(); // Add an extra block, since the iterator and @special variables belong to the loop scope. + // Add an extra block, since the iterator and @special locals belong to the loop scope. + // Also we use custom logic to clear block locals. + codegen.start_block(); GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype(), codegen.script)); @@ -2064,11 +2068,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui _clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit. - codegen.end_block(); // Get out of extra block. + codegen.end_block(); // Get out of extra block for loop iterator, @special locals, and custom locals clearing. } break; case GDScriptParser::Node::WHILE: { const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s); + codegen.start_block(); // Add an extra block, since we use custom logic to clear block locals. + gen->start_while_condition(); GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition); @@ -2095,6 +2101,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui gen->write_endwhile(); _clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit. + + codegen.end_block(); // Get out of extra block for custom locals clearing. } break; case GDScriptParser::Node::BREAK: { gen->write_break(); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 28a030e492..822fc412b4 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -402,7 +402,9 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> } const Variant &var = gl_array[E.value]; - if (Object *obj = var) { + bool freed = false; + const Object *obj = var.get_validated_object_with_check(freed); + if (obj && !freed) { if (Object::cast_to<GDScriptNativeClass>(obj)) { continue; } diff --git a/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.gd b/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.gd new file mode 100644 index 0000000000..3724c8c713 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/90086 + +class MyObj: + var obj: WeakRef + +func test(): + var obj_1 = MyObj.new() + var obj_2 = MyObj.new() + obj_1.obj = obj_2 diff --git a/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.out b/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.out new file mode 100644 index 0000000000..dfca5b1eca --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/errors/invalid_property_assignment.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: test() +>> runtime/errors/invalid_property_assignment.gd +>> 9 +>> Invalid assignment of property or key 'obj' with value of type 'RefCounted (MyObj)' on a base object of type 'RefCounted (MyObj)'. diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd index c774ebf83c..df639a7b4d 100644 --- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd +++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd @@ -1,6 +1,5 @@ # GH-77666 - -func test(): +func test_exit_if(): var ref := RefCounted.new() print(ref.get_reference_count()) @@ -8,3 +7,20 @@ func test(): var _temp := ref print(ref.get_reference_count()) + +# GH-94654 +func test_exit_while(): + var slots_data := [] + + while true: + @warning_ignore("confusable_local_declaration") + var slot = 42 + slots_data.append(slot) + break + + var slot: int = slots_data[0] + print(slot) + +func test(): + test_exit_if() + test_exit_while() diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out index 04b4638adf..164eb24963 100644 --- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out +++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out @@ -1,3 +1,4 @@ GDTEST_OK 1 1 +42 diff --git a/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.gd b/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.gd new file mode 100644 index 0000000000..e1aba83507 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.gd @@ -0,0 +1,11 @@ +# https://github.com/godotengine/godot/issues/90086 + +class MyObj: + var obj : WeakRef + +func test(): + var obj_1 = MyObj.new() + var obj_2 = MyObj.new() + assert(obj_2.get_reference_count() == 1) + obj_1.set(&"obj", obj_2) + assert(obj_2.get_reference_count() == 1) diff --git a/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.out b/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/set_does_not_leak.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index f70e440781..ec3ea9bcae 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -57,7 +57,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_minor, String *r_err = nullptr) { if (!FileAccess::exists(p_path)) { if (r_err) { - *r_err = TTR("Path does not contain a Blender installation."); + *r_err = TTR("Path does not point to a valid executable."); } return false; } @@ -67,14 +67,14 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino Error err = OS::get_singleton()->execute(p_path, args, &pipe); if (err != OK) { if (r_err) { - *r_err = TTR("Can't execute Blender binary."); + *r_err = TTR("Couldn't run Blender executable."); } return false; } int bl = pipe.find("Blender "); if (bl == -1) { if (r_err) { - *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s."), p_path); + *r_err = vformat(TTR("Unexpected --version output from Blender executable at: %s."), p_path); } return false; } @@ -83,7 +83,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino int pp = pipe.find("."); if (pp == -1) { if (r_err) { - *r_err = TTR("Path supplied lacks a Blender binary."); + *r_err = vformat(TTR("Couldn't extract version information from Blender executable at: %s."), p_path); } return false; } @@ -91,7 +91,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino r_major = v.to_int(); if (r_major < 3) { if (r_err) { - *r_err = TTR("This Blender installation is too old for this importer (not 3.0+)."); + *r_err = vformat(TTR("Found Blender version %d.x, which is too old for this importer (3.0+ is required)."), r_major); } return false; } @@ -392,9 +392,9 @@ void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path if (_test_blender_path(p_path, &error)) { success = true; if (auto_detected_path == p_path) { - error = TTR("Path to Blender installation is valid (Autodetected)."); + error = TTR("Path to Blender executable is valid (Autodetected)."); } else { - error = TTR("Path to Blender installation is valid."); + error = TTR("Path to Blender executable is valid."); } } } @@ -490,11 +490,15 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { if (!configure_blender_dialog) { configure_blender_dialog = memnew(ConfirmationDialog); configure_blender_dialog->set_title(TTR("Configure Blender Importer")); - configure_blender_dialog->set_flag(Window::FLAG_BORDERLESS, true); // Avoid closing accidentally . + configure_blender_dialog->set_flag(Window::FLAG_BORDERLESS, true); // Avoid closing accidentally. configure_blender_dialog->set_close_on_escape(false); + String select_exec_label = TTR("Blender 3.0+ is required to import '.blend' files.\nPlease provide a valid path to a Blender executable."); +#ifdef MACOS_ENABLED + select_exec_label += "\n" + TTR("On macOS, this should be the `Contents/MacOS/blender` file within the Blender `.app` folder."); +#endif VBoxContainer *vb = memnew(VBoxContainer); - vb->add_child(memnew(Label(TTR("Blender 3.0+ is required to import '.blend' files.\nPlease provide a valid path to a Blender installation:")))); + vb->add_child(memnew(Label(select_exec_label))); HBoxContainer *hb = memnew(HBoxContainer); @@ -528,8 +532,8 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() { browse_dialog = memnew(EditorFileDialog); browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); - browse_dialog->connect("dir_selected", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_select_install)); + browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + browse_dialog->connect("file_selected", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_select_install)); EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 50bf56d832..f5b64ff81b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -869,7 +869,7 @@ namespace Godot } /// <summary> - /// Multiplies each component of the <see cref="Vector2"/> + /// Divides each component of the <see cref="Vector2"/> /// by the given <see cref="real_t"/>. /// </summary> /// <param name="vec">The dividend vector.</param> diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index a0da9019c6..5169b9417f 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -2323,7 +2323,8 @@ static bool has_valid_keystore_credentials(String &r_error_str, const String &p_ args.push_back(p_password); args.push_back("-alias"); args.push_back(p_username); - Error error = OS::get_singleton()->execute("keytool", args, &output, nullptr, true); + String keytool_path = EditorExportPlatformAndroid::get_keytool_path(); + Error error = OS::get_singleton()->execute(keytool_path, args, &output, nullptr, true); String keytool_error = "keytool error:"; bool valid = output.substr(0, keytool_error.length()) != keytool_error; diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index b91b023ce6..f5555289fd 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -301,7 +301,7 @@ task generateGodotTemplates { */ task generateDevTemplate { // add parameter to set symbols to true - gradle.startParameter.projectProperties += [doNotStrip: "true"] + project.ext.doNotStrip = "true" gradle.startParameter.excludedTaskNames += templateExcludedBuildTask() dependsOn = generateBuildTasks("template") diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index d6eb101a68..4a52e26373 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1735,7 +1735,7 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) { _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); @@ -1749,6 +1749,11 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, V rendering_device->screen_create(id); } #endif + + if (p_transient_parent != INVALID_WINDOW_ID) { + window_set_transient(id, p_transient_parent); + } + return id; } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 341ba5f079..0cbfbe51ef 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -438,7 +438,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID) override; virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index b4741dc08f..bd3c6af273 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -326,7 +326,7 @@ public: virtual Vector<int> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID) override; virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index da45391995..cd2d8a60ac 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -1714,7 +1714,7 @@ Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) { _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_vsync_mode, p_rect); @@ -1728,6 +1728,12 @@ DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, rendering_device->screen_create(id); } #endif + + window_set_exclusive(id, p_exclusive); + if (p_transient_parent != INVALID_WINDOW_ID) { + window_set_transient(id, p_transient_parent); + } + return id; } diff --git a/platform/web/detect.py b/platform/web/detect.py index 79485ea28a..bf75c2f9fc 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -227,6 +227,11 @@ def configure(env: "SConsEnvironment"): env.Append(LINKFLAGS=["-sDEFAULT_PTHREAD_STACK_SIZE=%sKB" % env["default_pthread_stack_size"]]) env.Append(LINKFLAGS=["-sPTHREAD_POOL_SIZE=8"]) env.Append(LINKFLAGS=["-sWASM_MEM_MAX=2048MB"]) + if not env["dlink_enabled"]: + # Workaround https://github.com/emscripten-core/emscripten/issues/21844#issuecomment-2116936414. + # Not needed (and potentially dangerous) when dlink_enabled=yes, since we set EXPORT_ALL=1 in that case. + env.Append(LINKFLAGS=["-sEXPORTED_FUNCTIONS=['__emscripten_thread_crashed','_main']"]) + elif env["proxy_to_pthread"]: print_warning('"threads=no" support requires "proxy_to_pthread=no", disabling proxy to pthread.') env["proxy_to_pthread"] = False diff --git a/platform/web/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js index 0b16b07261..66d0d3d79d 100644 --- a/platform/web/js/libs/library_godot_audio.js +++ b/platform/web/js/libs/library_godot_audio.js @@ -77,7 +77,7 @@ class Sample { * Creates a `Sample` based on the params. Will register it to the * `GodotAudio.samples` registry. * @param {SampleParams} params Base params - * @param {SampleOptions} [options={}] Optional params + * @param {SampleOptions} [options={{}}] Optional params * @returns {Sample} */ static create(params, options = {}) { @@ -98,8 +98,7 @@ class Sample { /** * `Sample` constructor. * @param {SampleParams} params Base params - * @param {SampleOptions} [options={}] Optional params - * @constructor + * @param {SampleOptions} [options={{}}] Optional params */ constructor(params, options = {}) { /** @type {string} */ @@ -154,7 +153,7 @@ class Sample { if (this._audioBuffer == null) { throw new Error('couldn\'t duplicate a null audioBuffer'); } - /** @type {Float32Array[]} */ + /** @type {Array<Float32Array>} */ const channels = new Array(this._audioBuffer.numberOfChannels); for (let i = 0; i < this._audioBuffer.numberOfChannels; i++) { const channel = new Float32Array(this._audioBuffer.getChannelData(i)); @@ -189,7 +188,6 @@ class SampleNodeBus { /** * `SampleNodeBus` constructor. * @param {Bus} bus The bus related to the new `SampleNodeBus`. - * @constructor */ constructor(bus) { const NUMBER_OF_WEB_CHANNELS = 6; @@ -413,8 +411,7 @@ class SampleNode { /** * @param {SampleNodeParams} params Base params - * @param {SampleNodeOptions} [options={}] Optional params - * @constructor + * @param {SampleNodeOptions} [options={{}}] Optional params */ constructor(params, options = {}) { /** @type {string} */ @@ -441,7 +438,7 @@ class SampleNode { this._sampleNodeBuses = new Map(); /** @type {AudioBufferSourceNode | null} */ this._source = GodotAudio.ctx.createBufferSource(); - /** @type {AudioBufferSourceNode["onended"]} */ + this._onended = null; this.setPlaybackRate(options.playbackRate ?? 44100); @@ -558,7 +555,7 @@ class SampleNode { /** * Sets the volumes of the `SampleNode` for each buses passed in parameters. - * @param {Bus[]} buses + * @param {Array<Bus>} buses * @param {Float32Array} volumes */ setVolumes(buses, volumes) { @@ -818,7 +815,6 @@ class Bus { /** * `Bus` constructor. - * @constructor */ constructor() { /** @type {Set<SampleNode>} */ @@ -985,7 +981,6 @@ class Bus { GodotAudio.buses = GodotAudio.buses.filter((v) => v !== this); } - /** @type {Bus["prototype"]["_syncSampleNodes"]} */ _syncSampleNodes() { const sampleNodes = Array.from(this._sampleNodes); for (let i = 0; i < sampleNodes.length; i++) { @@ -1086,7 +1081,7 @@ const _GodotAudio = { // `Bus` class /** * Registry of `Bus`es. - * @type {Bus[]} + * @type {Array<Bus>} */ buses: null, /** @@ -1309,7 +1304,7 @@ const _GodotAudio = { /** * Triggered when a sample node volumes need to be updated. * @param {string} playbackObjectId Id of the sample playback - * @param {number[]} busIndexes Indexes of the buses that need to be updated + * @param {Array<number>} busIndexes Indexes of the buses that need to be updated * @param {Float32Array} volumes Array of the volumes * @returns {void} */ diff --git a/platform/windows/detect.py b/platform/windows/detect.py index bfbf7d3ebc..b4830c5908 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -589,7 +589,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): "libEGL.windows." + env["arch"] + prebuilt_lib_extra_suffix, "libGLES.windows." + env["arch"] + prebuilt_lib_extra_suffix, ] - LIBS += ["dxgi", "d3d9", "d3d11", "synchronization"] + LIBS += ["dxgi", "d3d9", "d3d11"] env.Prepend(CPPPATH=["#thirdparty/angle/include"]) if env["target"] in ["editor", "template_debug"]: @@ -817,7 +817,7 @@ def configure_mingw(env: "SConsEnvironment"): "ANGLE.windows." + env["arch"], ] ) - env.Append(LIBS=["dxgi", "d3d9", "d3d11", "synchronization"]) + env.Append(LIBS=["dxgi", "d3d9", "d3d11"]) env.Prepend(CPPPATH=["#thirdparty/angle/include"]) env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index ae8d1cace0..020ef0c31b 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1306,10 +1306,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons return INVALID_WINDOW_ID; } -DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) { _THREAD_SAFE_METHOD_ - WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); + WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_exclusive, p_transient_parent); ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); WindowData &wd = windows[window_id]; @@ -5326,7 +5326,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const } } -DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) { DWORD dwExStyle; DWORD dwStyle; @@ -5376,6 +5376,18 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowID id = window_id_counter; { + WindowData *wd_transient_parent = nullptr; + HWND owner_hwnd = nullptr; + if (p_transient_parent != INVALID_WINDOW_ID && !windows.has(p_transient_parent)) { + ERR_PRINT("Condition \"!windows.has(p_transient_parent)\" is true."); + p_transient_parent = INVALID_WINDOW_ID; + } else { + wd_transient_parent = &windows[p_transient_parent]; + if (p_exclusive) { + owner_hwnd = wd_transient_parent->hWnd; + } + } + WindowData &wd = windows[id]; wd.hWnd = CreateWindowExW( @@ -5386,7 +5398,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.top, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, - nullptr, + owner_hwnd, nullptr, hInstance, // tunnel the WindowData we need to handle creation message @@ -5408,6 +5420,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, wd.pre_fs_valid = true; } + wd.exclusive = p_exclusive; + if (wd_transient_parent) { + wd.transient_parent = p_transient_parent; + wd_transient_parent->transient_children.insert(id); + } + if (is_dark_mode_supported() && dark_title_available) { BOOL value = is_dark_mode(); ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); @@ -6063,7 +6081,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win window_position = scr_rect.position + (scr_rect.size - p_resolution) / 2; } - WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 650f0412ea..7b259def14 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -517,7 +517,7 @@ class DisplayServerWindows : public DisplayServer { uint64_t time_since_popup = 0; Ref<Image> icon; - WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent); WindowID window_id_counter = MAIN_WINDOW_ID; RBMap<WindowID, WindowData> windows; @@ -652,7 +652,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID) override; virtual void show_window(WindowID p_window) override; virtual void delete_sub_window(WindowID p_window) override; diff --git a/platform/windows/gl_manager_windows_native.cpp b/platform/windows/gl_manager_windows_native.cpp index f74aa4ced7..8590c46d12 100644 --- a/platform/windows/gl_manager_windows_native.cpp +++ b/platform/windows/gl_manager_windows_native.cpp @@ -243,7 +243,7 @@ void GLManagerNative_Windows::_nvapi_setup_profile() { } } - NVDRS_SETTING ogl_thread_control_setting = { 0 }; + NVDRS_SETTING ogl_thread_control_setting = {}; ogl_thread_control_setting.version = NVDRS_SETTING_VER; ogl_thread_control_setting.settingId = OGL_THREAD_CONTROL_ID; ogl_thread_control_setting.settingType = NVDRS_DWORD_TYPE; @@ -259,7 +259,7 @@ void GLManagerNative_Windows::_nvapi_setup_profile() { return; } - NVDRS_SETTING vrr_mode_setting = { 0 }; + NVDRS_SETTING vrr_mode_setting = {}; vrr_mode_setting.version = NVDRS_SETTING_VER; vrr_mode_setting.settingId = VRR_MODE_ID; vrr_mode_setting.settingType = NVDRS_DWORD_TYPE; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 59ebf38253..a27da73b89 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -138,15 +138,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; - bool is_just_looped = false; - // 1. Progress for AnimationNode. + bool will_end = Animation::is_greater_or_equal_approx(cur_time + cur_delta, cur_len); if (cur_loop_mode != Animation::LOOP_NONE) { if (cur_loop_mode == Animation::LOOP_LINEAR) { if (!Math::is_zero_approx(cur_len)) { - if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) { - is_just_looped = true; // Don't break with negative timescale since remain will not be 0. - } cur_time = Math::fposmod(cur_time, cur_len); } backward = false; @@ -156,7 +152,6 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe backward = !backward; } else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) { backward = !backward; - is_just_looped = true; // Don't break with negative timescale since remain will not be 0. } cur_time = Math::pingpong(cur_time, cur_len); } @@ -190,7 +185,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe nti.position = cur_time; nti.delta = cur_delta; nti.loop_mode = cur_loop_mode; - nti.is_just_looped = is_just_looped; + nti.will_end = will_end; // 3. Progress for Animation. double prev_playback_time = prev_time + start_offset; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index ecf4054e23..c3c5399a6b 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -804,7 +804,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St pi.weight = 0; current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Don't process first node if not necessary, insteads process next node. - _transition_to_next_recursive(tree, p_state_machine, p_test_only); + _transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only); } // Check current node existence. @@ -881,7 +881,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St } // Find next and see when to transition. - bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_test_only) || current == AnimationNodeStateMachine::END_NODE; + bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only) || current == AnimationNodeStateMachine::END_NODE; // Predict remaining time. if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) { @@ -899,10 +899,11 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St return current_nti; } -bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) { +bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only) { _reset_request_for_fading_from = false; AnimationMixer::PlaybackInfo pi; + pi.delta = p_delta; NextInfo next; Vector<StringName> transition_path; transition_path.push_back(current); diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index b58ff4d224..648e96b138 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -306,7 +306,7 @@ class AnimationNodeStateMachinePlayback : public Resource { AnimationNode::NodeTimeInfo _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; - bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only); + bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only); NextInfo _find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const; Ref<AnimationNodeStateMachineTransition> _check_group_transition(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const AnimationNodeStateMachine::Transition &p_transition, Ref<AnimationNodeStateMachine> &r_state_machine, bool &r_bypass) const; bool _can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 69287478db..c5a6a99d07 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -46,9 +46,9 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { } } - r_list->push_back(PropertyInfo(Variant::FLOAT, current_length, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); - r_list->push_back(PropertyInfo(Variant::FLOAT, current_position, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); - r_list->push_back(PropertyInfo(Variant::FLOAT, current_delta, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::FLOAT, current_length, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::FLOAT, current_position, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::FLOAT, current_delta, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_READ_ONLY)); } Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 6698427233..aa497ff1d6 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -74,7 +74,7 @@ public: // Needs internally to estimate remain time, the previous frame values are not retained. Animation::LoopMode loop_mode = Animation::LOOP_NONE; - bool is_just_looped = false; // For breaking loop, it is true when just looped. + bool will_end = false; // For breaking loop, it is true when just looped. bool is_infinity = false; // For unpredictable state machine's end. bool is_looping() { @@ -84,7 +84,7 @@ public: if ((is_looping() && !p_break_loop) || is_infinity) { return HUGE_LENGTH; } - if (p_break_loop && is_just_looped) { + if (is_looping() && p_break_loop && will_end) { return 0; } double remain = length - position; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3f1b9fc981..8a1a531c92 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -6863,9 +6863,9 @@ void TextEdit::_bind_methods() { ADD_GROUP("Scroll", "scroll_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_smooth"), "set_smooth_scroll_enabled", "is_smooth_scroll_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_v_scroll_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_v_scroll_speed", "get_v_scroll_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_v_scroll_speed", PROPERTY_HINT_NONE, "suffix:lines/s"), "set_v_scroll_speed", "get_v_scroll_speed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_past_end_of_file"), "set_scroll_past_end_of_file_enabled", "is_scroll_past_end_of_file_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical", PROPERTY_HINT_NONE, "suffix:px"), "set_v_scroll", "get_v_scroll"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical", PROPERTY_HINT_NONE, "suffix:lines"), "set_v_scroll", "get_v_scroll"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal", PROPERTY_HINT_NONE, "suffix:px"), "set_h_scroll", "get_h_scroll"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_fit_content_height"), "set_fit_content_height_enabled", "is_fit_content_height_enabled"); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index d409efbfab..e5873f0e9a 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -631,7 +631,7 @@ void Window::_make_window() { window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_WITH_KEYBOARD_FOCUS) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_WITH_KEYBOARD_FOCUS) - size) / 2, size); } - window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect); + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect, is_in_edited_scene_root() ? false : exclusive, transient_parent ? transient_parent->window_id : DisplayServer::INVALID_WINDOW_ID); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id); DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); @@ -639,18 +639,8 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_title(tr_title, window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); - if (is_in_edited_scene_root()) { - DisplayServer::get_singleton()->window_set_exclusive(window_id, false); - } else { - DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); - } - _update_window_size(); - if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id); - } - if (transient_parent) { for (const Window *E : transient_children) { if (E->window_id != DisplayServer::INVALID_WINDOW_ID) { diff --git a/servers/audio_server.h b/servers/audio_server.h index 84c091e320..fd6cdb451e 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -329,7 +329,7 @@ private: friend class AudioDriver; void _driver_process(int p_frames, int32_t *p_buffer); - LocalVector<Ref<AudioStreamPlayback>> sample_playback_list; + LocalVector<Ref<AudioSamplePlayback>> sample_playback_list; protected: static void _bind_methods(); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index d362a4073a..5451057645 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -570,7 +570,7 @@ int DisplayServer::get_screen_from_rect(const Rect2 &p_rect) const { return pos_screen; } -DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) { ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); } diff --git a/servers/display_server.h b/servers/display_server.h index 8c7e92fdc3..d0fe76faff 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -396,7 +396,7 @@ public: WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH), }; - virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID); virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 60422c16cc..a5277479ca 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -85,7 +85,7 @@ public: Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); } - WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override { return 0; } + WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID) override { return 0; } void show_window(WindowID p_id) override {} void delete_sub_window(WindowID p_id) override {} diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index a4ee33ecc0..2542f2eed7 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -1286,6 +1286,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene break; } if (function->arguments[j].tex_argument_check) { + if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) { + is_screen_texture = true; + } else if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) { + is_depth_texture = true; + } else if (function->arguments[j].tex_hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) { + is_normal_roughness_texture = true; + } sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat); found = true; break; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 745dcf5392..10c1158d95 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -4761,7 +4761,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi return false; } -bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) { +bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat, ShaderNode::Uniform::Hint p_hint) { for (int i = 0; i < shader->vfunctions.size(); i++) { if (shader->vfunctions[i].name == p_name) { ERR_FAIL_INDEX_V(p_argument, shader->vfunctions[i].function->arguments.size(), false); @@ -4770,20 +4770,21 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(const Str _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other)."), p_argument, String(p_name))); return false; } else if (arg->tex_argument_check) { - //was checked, verify that filter and repeat are the same - if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) { + // Was checked, verify that filter, repeat, and hint are the same. + if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat && arg->tex_hint == p_hint) { return true; } else { - _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter or repeat setting."), p_argument, String(p_name))); + _set_error(vformat(RTR("Sampler argument %d of function '%s' called more than once using textures that differ in either filter, repeat, or texture hint setting."), p_argument, String(p_name))); return false; } } else { arg->tex_argument_check = true; arg->tex_argument_filter = p_filter; arg->tex_argument_repeat = p_repeat; + arg->tex_hint = p_hint; for (KeyValue<StringName, HashSet<int>> &E : arg->tex_argument_connect) { for (const int &F : E.value) { - if (!_propagate_function_call_sampler_uniform_settings(E.key, F, p_filter, p_repeat)) { + if (!_propagate_function_call_sampler_uniform_settings(E.key, F, p_filter, p_repeat, p_hint)) { return false; } } @@ -5583,7 +5584,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } //propagate - if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) { + if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat, u->hint)) { return nullptr; } } else if (p_function_info.built_ins.has(varname)) { @@ -7411,6 +7412,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } tk = _get_token(); + } else { + _set_expected_error("("); + return ERR_PARSE_ERROR; } } } else { @@ -9520,6 +9524,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f _set_error(RTR("Array size mismatch.")); return ERR_PARSE_ERROR; } + } else { + _set_expected_error("("); + return ERR_PARSE_ERROR; } array_size = constant.array_size; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index bc0aa0558a..40f524ec9d 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -578,42 +578,6 @@ public: Node(NODE_TYPE_STRUCT) {} }; - struct FunctionNode : public Node { - struct Argument { - ArgumentQualifier qualifier; - StringName name; - DataType type; - StringName struct_name; - DataPrecision precision; - //for passing textures as arguments - bool tex_argument_check; - TextureFilter tex_argument_filter; - TextureRepeat tex_argument_repeat; - bool tex_builtin_check; - StringName tex_builtin; - bool is_const; - int array_size; - - HashMap<StringName, HashSet<int>> tex_argument_connect; - }; - - StringName name; - DataType return_type = TYPE_VOID; - StringName return_struct_name; - DataPrecision return_precision = PRECISION_DEFAULT; - int return_array_size = 0; - Vector<Argument> arguments; - BlockNode *body = nullptr; - bool can_discard = false; - - virtual DataType get_datatype() const override { return return_type; } - virtual String get_datatype_name() const override { return String(return_struct_name); } - virtual int get_array_size() const override { return return_array_size; } - - FunctionNode() : - Node(NODE_TYPE_FUNCTION) {} - }; - struct ShaderNode : public Node { struct Constant { StringName name; @@ -722,6 +686,43 @@ public: Node(NODE_TYPE_SHADER) {} }; + struct FunctionNode : public Node { + struct Argument { + ArgumentQualifier qualifier; + StringName name; + DataType type; + StringName struct_name; + DataPrecision precision; + //for passing textures as arguments + bool tex_argument_check; + TextureFilter tex_argument_filter; + TextureRepeat tex_argument_repeat; + bool tex_builtin_check; + StringName tex_builtin; + ShaderNode::Uniform::Hint tex_hint; + bool is_const; + int array_size; + + HashMap<StringName, HashSet<int>> tex_argument_connect; + }; + + StringName name; + DataType return_type = TYPE_VOID; + StringName return_struct_name; + DataPrecision return_precision = PRECISION_DEFAULT; + int return_array_size = 0; + Vector<Argument> arguments; + BlockNode *body = nullptr; + bool can_discard = false; + + virtual DataType get_datatype() const override { return return_type; } + virtual String get_datatype_name() const override { return String(return_struct_name); } + virtual int get_array_size() const override { return return_array_size; } + + FunctionNode() : + Node(NODE_TYPE_FUNCTION) {} + }; + struct UniformOrderComparator { _FORCE_INLINE_ bool operator()(const Pair<StringName, int> &A, const Pair<StringName, int> &B) const { return A.second < B.second; @@ -1122,7 +1123,7 @@ private: bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function = nullptr); bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr); - bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); + bool _propagate_function_call_sampler_uniform_settings(const StringName &p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat, ShaderNode::Uniform::Hint p_hint); bool _propagate_function_call_sampler_builtin_reference(const StringName &p_name, int p_argument, const StringName &p_builtin); bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); bool _check_node_constness(const Node *p_node) const; diff --git a/tests/scene/test_graph_node.h b/tests/scene/test_graph_node.h index bf6cc9be09..7973ac1444 100644 --- a/tests/scene/test_graph_node.h +++ b/tests/scene/test_graph_node.h @@ -48,8 +48,10 @@ TEST_CASE("[GraphNode][SceneTree]") { test_node->add_child(test_child); // Test. - CHECK_NOTHROW_MESSAGE(test_node->remove_child(test_child)); + test_node->remove_child(test_child); + CHECK(test_node->get_child_count(false) == 0); + memdelete(test_child); memdelete(test_node); } } |