diff options
85 files changed, 594 insertions, 258 deletions
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index ed4ef01012..666b10d016 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -19,13 +19,6 @@ jobs: steps: - uses: actions/checkout@v3 - # Azure repositories are not reliable, we need to prevent azure giving us packages. - - name: Make apt sources.list use the default Ubuntu repositories - run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f misc/ci/sources.list /etc/apt/sources.list - sudo apt-get update - - name: Set up Java 11 uses: actions/setup-java@v3 with: diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index bfda7c72f8..46a9228616 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -74,16 +74,13 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Linux dependencies - shell: bash + # Need newer mesa for lavapipe to work properly. + - name: Linux dependencies for tests + if: ${{ matrix.proj-test }} run: | - # Azure repositories are not reliable, we need to prevent azure giving us packages. - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f misc/ci/sources.list /etc/apt/sources.list + sudo add-apt-repository ppa:kisak/kisak-mesa sudo apt-get update - # The actual dependencies - sudo apt-get install build-essential pkg-config libgl1-mesa-dev libglu-dev \ - xvfb wget unzip llvm + sudo apt-get install -qq mesa-vulkan-drivers - name: Setup Godot build cache uses: ./.github/actions/godot-cache @@ -138,16 +135,6 @@ jobs: ${{ matrix.bin }} --doctool --headless 2>&1 > /dev/null || true git diff --color --exit-code && ! git ls-files --others --exclude-standard | sed -e 's/^/New doc file missing in PR: /' | grep 'xml$' - # Download, unzip and setup SwiftShader library - # See https://github.com/godotengine/regression-test-project/releases/tag/_ci-deps for details - - name: Download SwiftShader - if: ${{ matrix.tests }} - run: | - wget https://github.com/godotengine/regression-test-project/releases/download/_ci-deps/swiftshader-ubuntu20.04-20211002.zip - unzip swiftshader-ubuntu20.04-20211002.zip - curr="$(pwd)/libvk_swiftshader.so" - sed -i "s|PATH_TO_CHANGE|$curr|" vk_swiftshader_icd.json - # Test 3.x -> 4.x project converter - name: Test project converter if: ${{ matrix.proj-conv }} @@ -155,7 +142,7 @@ jobs: mkdir converter_test cd converter_test touch project.godot - ../${{ matrix.bin }} --headless --audio-driver Dummy --validate-conversion-3to4 + ../${{ matrix.bin }} --headless --validate-conversion-3to4 cd .. rm converter_test -rf @@ -171,7 +158,7 @@ jobs: - name: Open and close editor (Vulkan) if: ${{ matrix.proj-test }} run: | - VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true + xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true misc/scripts/check_ci_log.py sanitizers_log.txt - name: Open and close editor (GLES3) @@ -184,7 +171,7 @@ jobs: - name: Run project if: ${{ matrix.proj-test }} run: | - VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run ${{ matrix.bin }} 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true + xvfb-run ${{ matrix.bin }} 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true misc/scripts/check_ci_log.py sanitizers_log.txt # Checkout godot-cpp diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index eece270dd9..a3722e19ce 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -13,17 +13,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 - # Azure repositories are not reliable, we need to prevent Azure giving us packages. - - name: Make apt sources.list use the default Ubuntu repositories + - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f misc/ci/sources.list /etc/apt/sources.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main" sudo apt-get update - - - name: Install dependencies - run: | sudo apt-get install -qq dos2unix clang-format-15 libxml2-utils python3-pip moreutils sudo update-alternatives --remove-all clang-format || true sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 diff --git a/.gitignore b/.gitignore index ca96220570..e9beb26e7e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ misc/hooks/pre-commit-custom-* ############################# # Buildsystem -bin/ +bin *.gen.* compile_commands.json platform/windows/godot_res.res diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 876a09beff..9593afc2fb 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -37,7 +37,6 @@ #include <stddef.h> #include <stdint.h> -#include <stdio.h> #ifndef __cplusplus typedef uint32_t char32_t; diff --git a/core/input/input.cpp b/core/input/input.cpp index 2e886f9093..071d9ba648 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -533,6 +533,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em touch_event->set_pressed(mb->is_pressed()); touch_event->set_position(mb->get_position()); touch_event->set_double_tap(mb->is_double_click()); + touch_event->set_device(InputEvent::DEVICE_ID_EMULATION); event_dispatch_function(touch_event); } } @@ -557,6 +558,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em drag_event->set_pen_inverted(mm->get_pen_inverted()); drag_event->set_pressure(mm->get_pressure()); drag_event->set_velocity(get_last_mouse_velocity()); + drag_event->set_device(InputEvent::DEVICE_ID_EMULATION); event_dispatch_function(drag_event); } @@ -592,7 +594,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em Ref<InputEventMouseButton> button_event; button_event.instantiate(); - button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); + button_event->set_device(InputEvent::DEVICE_ID_EMULATION); button_event->set_position(st->get_position()); button_event->set_global_position(st->get_position()); button_event->set_pressed(st->is_pressed()); @@ -623,7 +625,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em Ref<InputEventMouseMotion> motion_event; motion_event.instantiate(); - motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); + motion_event->set_device(InputEvent::DEVICE_ID_EMULATION); motion_event->set_tilt(sd->get_tilt()); motion_event->set_pen_inverted(sd->get_pen_inverted()); motion_event->set_pressure(sd->get_pressure()); @@ -832,7 +834,7 @@ void Input::ensure_touch_mouse_raised() { Ref<InputEventMouseButton> button_event; button_event.instantiate(); - button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); + button_event->set_device(InputEvent::DEVICE_ID_EMULATION); button_event->set_position(mouse_pos); button_event->set_global_position(mouse_pos); button_event->set_pressed(false); @@ -869,6 +871,7 @@ void Input::set_default_cursor_shape(CursorShape p_shape) { mm.instantiate(); mm->set_position(mouse_pos); mm->set_global_position(mouse_pos); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); parse_input_event(mm); } diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 5a9ec74184..7c4642a8a5 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -34,7 +34,7 @@ #include "core/input/shortcut.h" #include "core/os/keyboard.h" -const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1; +const int InputEvent::DEVICE_ID_EMULATION = -1; const int InputEvent::DEVICE_ID_INTERNAL = -2; void InputEvent::set_device(int p_device) { diff --git a/core/input/input_event.h b/core/input/input_event.h index 797761b208..eff8d479db 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -59,7 +59,7 @@ protected: static void _bind_methods(); public: - static const int DEVICE_ID_TOUCH_MOUSE; + static const int DEVICE_ID_EMULATION; static const int DEVICE_ID_INTERNAL; void set_device(int p_device); diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 2e1adb9167..d156c35343 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -225,6 +225,9 @@ void Array::assign(const Array &p_array) { _p->array = p_array._p->array; return; } + if (typed.type == Variant::OBJECT || source_typed.type == Variant::OBJECT) { + ERR_FAIL_MSG(vformat(R"(Cannot assign contents of "Array[%s]" to "Array[%s]".)", Variant::get_type_name(source_typed.type), Variant::get_type_name(typed.type))); + } Vector<Variant> array; array.resize(size); diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h index 796b66dc77..ad679db9d0 100644 --- a/core/variant/container_type_validate.h +++ b/core/variant/container_type_validate.h @@ -41,34 +41,26 @@ struct ContainerTypeValidate { const char *where = "container"; _FORCE_INLINE_ bool can_reference(const ContainerTypeValidate &p_type) const { - if (type == p_type.type) { - if (type != Variant::OBJECT) { - return true; //nothing else to check - } - } else { + if (type != p_type.type) { return false; + } else if (type != Variant::OBJECT) { + return true; } - //both are object - - if ((class_name != StringName()) != (p_type.class_name != StringName())) { - return false; //both need to have class or none - } - - if (class_name != p_type.class_name) { - if (!ClassDB::is_parent_class(p_type.class_name, class_name)) { - return false; - } - } - - if (script.is_null() != p_type.script.is_null()) { + if (class_name == StringName()) { + return true; + } else if (p_type.class_name == StringName()) { + return false; + } else if (class_name != p_type.class_name && !ClassDB::is_parent_class(p_type.class_name, class_name)) { return false; } - if (script != p_type.script) { - if (!p_type.script->inherits_script(script)) { - return false; - } + if (script.is_null()) { + return true; + } else if (p_type.script.is_null()) { + return false; + } else if (script != p_type.script && !p_type.script->inherits_script(script)) { + return false; } return true; diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index bc65e6013b..4dd83c0d9f 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -187,9 +187,24 @@ </member> </members> <signals> + <signal name="animation_node_removed"> + <param index="0" name="object_id" type="int" /> + <param index="1" name="name" type="String" /> + <description> + Emitted by nodes that inherit from this class and that have an internal tree when one of their nodes removes. The nodes that emit this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], [AnimationNodeStateMachine], and [AnimationNodeBlendTree]. + </description> + </signal> + <signal name="animation_node_renamed"> + <param index="0" name="object_id" type="int" /> + <param index="1" name="old_name" type="String" /> + <param index="2" name="new_name" type="String" /> + <description> + Emitted by nodes that inherit from this class and that have an internal tree when one of their node names changes. The nodes that emit this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], [AnimationNodeStateMachine], and [AnimationNodeBlendTree]. + </description> + </signal> <signal name="tree_changed"> <description> - Emitted by nodes that inherit from this class and that have an internal tree when one of their nodes changes. The nodes that emit this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], [AnimationNodeStateMachine], and [AnimationNodeBlendTree]. + Emitted by nodes that inherit from this class and that have an internal tree when one of their nodes changes. The nodes that emit this signal are [AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], [AnimationNodeStateMachine], [AnimationNodeBlendTree] and [AnimationNodeTransition]. </description> </signal> </signals> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index d74ddba369..7d7925d61e 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -144,11 +144,11 @@ </method> <method name="_has_point" qualifiers="virtual const"> <return type="bool" /> - <param index="0" name="position" type="Vector2" /> + <param index="0" name="point" type="Vector2" /> <description> - Virtual method to be implemented by the user. Returns whether the given [param position] is inside this control. + Virtual method to be implemented by the user. Returns whether the given [param point] is inside this control. If not overridden, default behavior is checking if the point is within control's Rect. - [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. + [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]Rect2(Vector2.ZERO, size).has_point(point)[/code]. </description> </method> <method name="_make_custom_tooltip" qualifiers="virtual const"> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 6f4a7fc13d..55ba1f4f0c 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1325,6 +1325,7 @@ <param index="1" name="window_id" type="int" default="0" /> <description> Sets the maximum size of the window specified by [param window_id] in pixels. Normally, the user will not be able to drag the window to make it smaller than the specified size. See also [method window_get_max_size]. + [b]Note:[/b] It's recommended to change this value using [member Window.max_size] instead. [b]Note:[/b] Using third-party tools, it is possible for users to disable window geometry restrictions and therefore bypass this limit. </description> </method> @@ -1334,6 +1335,7 @@ <param index="1" name="window_id" type="int" default="0" /> <description> Sets the minimum size for the given window to [param min_size] (in pixels). Normally, the user will not be able to drag the window to make it larger than the specified size. See also [method window_get_min_size]. + [b]Note:[/b] It's recommended to change this value using [member Window.min_size] instead. [b]Note:[/b] By default, the main window has a minimum size of [code]Vector2i(64, 64)[/code]. This prevents issues that can arise when the window is resized to a near-zero size. [b]Note:[/b] Using third-party tools, it is possible for users to disable window geometry restrictions and therefore bypass this limit. </description> @@ -1403,6 +1405,7 @@ +-------------+ +-------+ [/codeblock] See also [method window_get_position] and [method window_set_size]. + [b]Note:[/b] It's recommended to change this value using [member Window.position] instead. </description> </method> <method name="window_set_rect_changed_callback"> @@ -1419,6 +1422,7 @@ <param index="1" name="window_id" type="int" default="0" /> <description> Sets the size of the given window to [param size] (in pixels). See also [method window_get_size] and [method window_get_position]. + [b]Note:[/b] It's recommended to change this value using [member Window.size] instead. </description> </method> <method name="window_set_title"> @@ -1427,6 +1431,7 @@ <param index="1" name="window_id" type="int" default="0" /> <description> Sets the title of the given window to [param title]. + [b]Note:[/b] It's recommended to change this value using [member Window.title] instead. [b]Note:[/b] Avoid changing the window title every frame, as this can cause performance issues on certain window managers. Try to change the window title only a few times per second at most. </description> </method> @@ -1436,7 +1441,8 @@ <param index="1" name="parent_window_id" type="int" /> <description> Sets window transient parent. Transient window is will be destroyed with its transient parent and will return focus to their parent when closed. The transient window is displayed on top of a non-exclusive full-screen parent window. Transient windows can't enter full-screen mode. - Note that behavior might be different depending on the platform. + [b]Note:[/b] It's recommended to change this value using [member Window.transient] instead. + [b]Note:[/b] The behavior might be different depending on the platform. </description> </method> <method name="window_set_vsync_mode"> diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 138498220d..026f7467a8 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -311,6 +311,13 @@ uint64_t LightStorage::light_get_version(RID p_light) const { return light->version; } +uint32_t LightStorage::light_get_cull_mask(RID p_light) const { + const Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_COND_V(!light, 0); + + return light->cull_mask; +} + AABB LightStorage::light_get_aabb(RID p_light) const { const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, AABB()); diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index f6f7628a90..8e6480869b 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -239,13 +239,6 @@ public: return light->color; } - _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) { - const Light *light = light_owner.get_or_null(p_light); - ERR_FAIL_COND_V(!light, 0); - - return light->cull_mask; - } - _FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) { const Light *light = light_owner.get_or_null(p_light); return light->distance_fade; @@ -297,6 +290,7 @@ public: virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override; virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; } virtual uint64_t light_get_version(RID p_light) const override; + virtual uint32_t light_get_cull_mask(RID p_light) const override; /* LIGHT INSTANCE API */ diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 017e74fc4d..fedda6b260 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -585,6 +585,7 @@ public: virtual void decal_set_normal_fade(RID p_decal, float p_fade) override; virtual AABB decal_get_aabb(RID p_decal) const override; + virtual uint32_t decal_get_cull_mask(RID p_decal) const override { return 0; } virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index ba73a63245..2895aa9710 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -389,7 +389,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se size = texture->get_size(); - if (bool(object->call("is_region"))) { + if (bool(object->call("is_region_enabled"))) { size = Rect2(object->call("get_region_rect")).size; } @@ -479,7 +479,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in region.size = texture->get_size(); - if (bool(object->call("is_region"))) { + if (bool(object->call("is_region_enabled"))) { region = Rect2(object->call("get_region_rect")); } diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index f4d293e9f4..20a9e633a8 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -170,6 +170,10 @@ void ConnectDialog::_tree_node_selected() { _update_ok_enabled(); } +void ConnectDialog::_focus_currently_connected() { + tree->set_selected(source); +} + void ConnectDialog::_unbind_count_changed(double p_count) { for (Control *control : bind_controls) { BaseButton *b = Object::cast_to<BaseButton>(control); @@ -577,6 +581,8 @@ void ConnectDialog::init(const ConnectionData &p_cd, const PackedStringArray &p_ void ConnectDialog::popup_dialog(const String p_for_signal) { from_signal->set_text(p_for_signal); error_label->add_theme_color_override("font_color", error_label->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + filter_nodes->clear(); + if (!advanced->is_pressed()) { error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root())); } @@ -628,12 +634,28 @@ ConnectDialog::ConnectDialog() { tree = memnew(SceneTreeEditor(false)); tree->set_connecting_signal(true); tree->set_show_enabled_subscene(true); + tree->set_v_size_flags(Control::SIZE_FILL | Control::SIZE_EXPAND); tree->get_scene_tree()->connect("item_activated", callable_mp(this, &ConnectDialog::_item_activated)); tree->connect("node_selected", callable_mp(this, &ConnectDialog::_tree_node_selected)); tree->set_connect_to_script_mode(true); - Node *mc = vbc_left->add_margin_child(TTR("Connect to Script:"), tree, true); + HBoxContainer *hbc_filter = memnew(HBoxContainer); + + filter_nodes = memnew(LineEdit); + hbc_filter->add_child(filter_nodes); + filter_nodes->set_h_size_flags(Control::SIZE_FILL | Control::SIZE_EXPAND); + filter_nodes->set_placeholder(TTR("Filter Nodes")); + filter_nodes->set_clear_button_enabled(true); + filter_nodes->connect("text_changed", callable_mp(tree, &SceneTreeEditor::set_filter)); + + Button *focus_current = memnew(Button); + hbc_filter->add_child(focus_current); + focus_current->set_text(TTR("Go to Source")); + focus_current->connect("pressed", callable_mp(this, &ConnectDialog::_focus_currently_connected)); + + Node *mc = vbc_left->add_margin_child(TTR("Connect to Script:"), hbc_filter, false); connect_to_label = Object::cast_to<Label>(vbc_left->get_child(mc->get_index() - 1)); + vbc_left->add_child(tree); error_label = memnew(Label); error_label->set_text(TTR("Scene does not contain any script.")); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 277ea03cf7..e5375a3fc8 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -106,6 +106,7 @@ public: private: Label *connect_to_label = nullptr; LineEdit *from_signal = nullptr; + LineEdit *filter_nodes = nullptr; Node *source = nullptr; ConnectionData source_connection_data; StringName signal; @@ -142,6 +143,7 @@ private: void _item_activated(); void _text_submitted(const String &p_text); void _tree_node_selected(); + void _focus_currently_connected(); void _method_selected(); void _create_method_tree_items(const List<MethodInfo> &p_methods, TreeItem *p_parent_item); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index f6fe6c9f76..3adebb2f8e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2953,7 +2953,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } else if (export_template_manager->can_install_android_template()) { install_android_build_template->popup_centered(); } else { - custom_build_manage_templates->popup_centered(); + gradle_build_manage_templates->popup_centered(); } } } break; @@ -3043,7 +3043,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { #endif } break; case SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE: { - custom_build_manage_templates->hide(); + gradle_build_manage_templates->hide(); file_android_build_source->popup_centered_ratio(); } break; case SETTINGS_MANAGE_FEATURE_PROFILES: { @@ -5624,8 +5624,9 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { return; } - bottom_panel_updating = true; if (p_enable) { + bottom_panel_updating = true; + for (int i = 0; i < bottom_panel_items.size(); i++) { bottom_panel_items[i].button->set_pressed(i == p_idx); bottom_panel_items[i].control->set_visible(i == p_idx); @@ -5642,7 +5643,6 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { top_split->hide(); } bottom_panel_raise->show(); - } else { bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles"))); bottom_panel_items[p_idx].button->set_pressed(false); @@ -7706,12 +7706,12 @@ EditorNode::EditorNode() { save_confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current)); save_confirmation->connect("custom_action", callable_mp(this, &EditorNode::_discard_changes)); - custom_build_manage_templates = memnew(ConfirmationDialog); - custom_build_manage_templates->set_text(TTR("Android build template is missing, please install relevant templates.")); - custom_build_manage_templates->set_ok_button_text(TTR("Manage Templates")); - custom_build_manage_templates->add_button(TTR("Install from file"))->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE)); - custom_build_manage_templates->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SETTINGS_MANAGE_EXPORT_TEMPLATES)); - gui_base->add_child(custom_build_manage_templates); + gradle_build_manage_templates = memnew(ConfirmationDialog); + gradle_build_manage_templates->set_text(TTR("Android build template is missing, please install relevant templates.")); + gradle_build_manage_templates->set_ok_button_text(TTR("Manage Templates")); + gradle_build_manage_templates->add_button(TTR("Install from file"))->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE)); + gradle_build_manage_templates->connect("confirmed", callable_mp(this, &EditorNode::_menu_option).bind(SETTINGS_MANAGE_EXPORT_TEMPLATES)); + gui_base->add_child(gradle_build_manage_templates); file_android_build_source = memnew(EditorFileDialog); file_android_build_source->set_title(TTR("Select Android sources file")); @@ -7722,7 +7722,7 @@ EditorNode::EditorNode() { gui_base->add_child(file_android_build_source); install_android_build_template = memnew(ConfirmationDialog); - install_android_build_template->set_text(TTR("This will set up your project for custom Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote that in order to make custom builds instead of using pre-built APKs, the \"Use Custom Build\" option should be enabled in the Android export preset.")); + install_android_build_template->set_text(TTR("This will set up your project for gradle Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote that in order to make gradle builds instead of using pre-built APKs, the \"Use Gradle Build\" option should be enabled in the Android export preset.")); install_android_build_template->set_ok_button_text(TTR("Install")); install_android_build_template->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current)); gui_base->add_child(install_android_build_template); diff --git a/editor/editor_node.h b/editor/editor_node.h index 19a0e49a12..eefe45ca1f 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -398,7 +398,7 @@ private: PopupMenu *editor_layouts = nullptr; EditorLayoutsDialog *layout_dialog = nullptr; - ConfirmationDialog *custom_build_manage_templates = nullptr; + ConfirmationDialog *gradle_build_manage_templates = nullptr; ConfirmationDialog *install_android_build_template = nullptr; ConfirmationDialog *remove_android_build_template = nullptr; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index c9eae77b53..33bba90c70 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -4593,7 +4593,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ } break; case Variant::PACKED_STRING_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_STRING_ARRAY); + editor->setup(Variant::PACKED_STRING_ARRAY, p_hint_text); return editor; } break; case Variant::PACKED_VECTOR2_ARRAY: { diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index b96ac9dbcb..24cfa7ad7b 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -574,7 +574,7 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint // The format of p_hint_string is: // subType/subTypeHint:nextSubtype ... etc. - if (array_type == Variant::ARRAY && !p_hint_string.is_empty()) { + if (!p_hint_string.is_empty()) { int hint_subtype_separator = p_hint_string.find(":"); if (hint_subtype_separator >= 0) { String subtype_string = p_hint_string.substr(0, hint_subtype_separator); diff --git a/misc/ci/sources.list b/misc/ci/sources.list deleted file mode 100644 index 4d8f94f35c..0000000000 --- a/misc/ci/sources.list +++ /dev/null @@ -1,4 +0,0 @@ -deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index cafc7328e0..78e437b42a 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2471,30 +2471,27 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) { return; } - GDScriptParser::DataType awaiting_type; - if (p_await->to_await->type == GDScriptParser::Node::CALL) { reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true); - awaiting_type = p_await->to_await->get_datatype(); } else { reduce_expression(p_await->to_await); } - if (p_await->to_await->is_constant) { + GDScriptParser::DataType await_type = p_await->to_await->get_datatype(); + // We cannot infer the type of the result of waiting for a signal. + if (await_type.is_hard_type() && await_type.kind == GDScriptParser::DataType::BUILTIN && await_type.builtin_type == Variant::SIGNAL) { + await_type.kind = GDScriptParser::DataType::VARIANT; + await_type.type_source = GDScriptParser::DataType::UNDETECTED; + } else if (p_await->to_await->is_constant) { p_await->is_constant = p_await->to_await->is_constant; p_await->reduced_value = p_await->to_await->reduced_value; - - awaiting_type = p_await->to_await->get_datatype(); - } else { - awaiting_type.kind = GDScriptParser::DataType::VARIANT; - awaiting_type.type_source = GDScriptParser::DataType::UNDETECTED; } - - p_await->set_datatype(awaiting_type); + await_type.is_coroutine = false; + p_await->set_datatype(await_type); #ifdef DEBUG_ENABLED - awaiting_type = p_await->to_await->get_datatype(); - if (!(awaiting_type.has_no_type() || awaiting_type.is_coroutine || awaiting_type.builtin_type == Variant::SIGNAL)) { + GDScriptParser::DataType to_await_type = p_await->to_await->get_datatype(); + if (!(to_await_type.has_no_type() || to_await_type.is_coroutine || to_await_type.builtin_type == Variant::SIGNAL)) { parser->push_warning(p_await, GDScriptWarning::REDUNDANT_AWAIT); } #endif @@ -3020,7 +3017,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call); } else if (!is_self && base_type.is_meta_type && !is_static) { base_type.is_meta_type = false; // For `to_string()`. - push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call); + push_error(vformat(R"*(Cannot call non-static function "%s()" on a class directly. Make an instance instead.)*", p_call->function_name), p_call); } else if (is_self && !is_static) { mark_lambda_use_self(); } @@ -4567,16 +4564,6 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo base_script = base_script->get_base_script(); } - // If the base is a script, it might be trying to access members of the Script class itself. - if (p_base_type.is_meta_type && !p_is_constructor && (p_base_type.kind == GDScriptParser::DataType::SCRIPT || p_base_type.kind == GDScriptParser::DataType::CLASS)) { - MethodInfo info; - StringName script_class = p_base_type.kind == GDScriptParser::DataType::SCRIPT ? p_base_type.script_type->get_class_name() : StringName(GDScript::get_class_static()); - - if (ClassDB::get_method_info(script_class, function_name, &info)) { - return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); - } - } - if (p_is_constructor) { // Native types always have a default constructor. r_return_type = p_base_type; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 46cd4b0d55..210550a674 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -591,7 +591,6 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) { const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); - if (subscript->is_attribute) { // May be static built-in method call. if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { @@ -615,7 +614,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else { class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type; } - if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { + if (!subscript->base->is_constant && ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { MethodBind *method = ClassDB::get_method(class_name, call->function_name); if (_can_use_ptrcall(method, arguments)) { // Exact arguments, use ptrcall. diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 4e7d278aab..8cfd48b52b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -977,7 +977,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, } break; case GDScriptParser::ClassNode::Member::SIGNAL: - if (p_only_functions || outer) { + if (p_only_functions || outer || p_static) { continue; } option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); @@ -1033,6 +1033,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } + + List<MethodInfo> signals; + scr->get_script_signal_list(&signals); + for (const MethodInfo &E : signals) { + int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); + r_result.insert(option.display, option); + } } HashMap<StringName, Variant> constants; scr->get_constants(&constants); @@ -1041,14 +1049,6 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location); r_result.insert(option.display, option); } - - List<MethodInfo> signals; - scr->get_script_signal_list(&signals); - for (const MethodInfo &E : signals) { - int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name); - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); - r_result.insert(option.display, option); - } } List<MethodInfo> methods; @@ -1093,14 +1093,6 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base r_result.insert(option.display, option); } - List<MethodInfo> signals; - ClassDB::get_signal_list(type, &signals); - for (const MethodInfo &E : signals) { - int location = p_recursion_depth + _get_signal_location(type, StringName(E.name)); - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); - r_result.insert(option.display, option); - } - if (!base_type.is_meta_type || Engine::get_singleton()->has_singleton(type)) { List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); @@ -1115,6 +1107,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); r_result.insert(option.display, option); } + + List<MethodInfo> signals; + ClassDB::get_signal_list(type, &signals); + for (const MethodInfo &E : signals) { + int location = p_recursion_depth + _get_signal_location(type, StringName(E.name)); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); + r_result.insert(option.display, option); + } } } @@ -2031,6 +2031,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.script_path = script; r_type.type.class_type = parser->get_parser()->get_tree(); + r_type.type.is_meta_type = true; r_type.type.is_constant = false; r_type.type.kind = GDScriptParser::DataType::CLASS; r_type.value = Variant(); @@ -2142,6 +2143,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::CLASS; r_type.type.class_type = member.m_class; + r_type.type.is_meta_type = true; return true; case GDScriptParser::ClassNode::Member::GROUP: return false; // No-op, but silences warnings. diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 2ec7f77201..0a1a64cb59 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3619,7 +3619,7 @@ bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node *p_node) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, R"("@onready" annotation can only be applied to class variables.)"); - if (head && !ClassDB::is_parent_class(head->get_datatype().native_type, SNAME("Node"))) { + if (current_class && !ClassDB::is_parent_class(current_class->get_datatype().native_type, SNAME("Node"))) { push_error(R"("@onready" can only be used in classes that inherit "Node".)", p_annotation); } @@ -3697,6 +3697,13 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.type = Variant::DICTIONARY; return true; + } else if (export_type.builtin_type == Variant::PACKED_STRING_ARRAY) { + String hint_prefix = itos(Variant::STRING) + "/" + itos(variable->export_info.hint); + variable->export_info.hint = PROPERTY_HINT_TYPE_STRING; + variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string; + variable->export_info.type = Variant::PACKED_STRING_ARRAY; + + return true; } } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.gd b/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.gd new file mode 100644 index 0000000000..c787d9e50e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.gd @@ -0,0 +1,4 @@ +signal my_signal() + +func test(): + var _a := await my_signal diff --git a/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.out b/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.out new file mode 100644 index 0000000000..8f8744ad7e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/await_signal_no_infer.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot infer the type of "_a" variable because the value doesn't have a set type. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.gd b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.gd new file mode 100644 index 0000000000..966d2b0aa2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.gd @@ -0,0 +1,5 @@ +const TestClass = preload("gdscript_duplicate_class.notest.gd") + +func test(): + # (TestClass as GDScript).duplicate() exists + TestClass.duplicate() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.out b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.out new file mode 100644 index 0000000000..b2c7fec86e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot call non-static function "duplicate()" on a class directly. Make an instance instead. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate_class.notest.gd b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate_class.notest.gd new file mode 100644 index 0000000000..61510e14cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/gdscript_duplicate_class.notest.gd @@ -0,0 +1 @@ +extends Node diff --git a/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.gd b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.gd new file mode 100644 index 0000000000..1639bbbd52 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.gd @@ -0,0 +1,7 @@ +extends Node + +class Inner extends RefCounted: + @onready var nope = 0 + +func test(): + print("Cannot use @onready without a Node base") diff --git a/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.out b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.out new file mode 100644 index 0000000000..8088d28329 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node_inner_class.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +"@onready" can only be used in classes that inherit "Node". diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.gd b/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.gd new file mode 100644 index 0000000000..9d8cfc7f99 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.gd @@ -0,0 +1,15 @@ +func coroutine() -> int: + @warning_ignore("redundant_await") + await 0 + return 1 + +func not_coroutine() -> int: + return 2 + +func test(): + var a := await coroutine() + @warning_ignore("redundant_await") + var b := await not_coroutine() + @warning_ignore("redundant_await") + var c := await 3 + prints(a, b, c) diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.out b/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.out new file mode 100644 index 0000000000..2920e2ce9c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_type_inference.out @@ -0,0 +1,2 @@ +GDTEST_OK +1 2 3 diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.gd new file mode 100644 index 0000000000..030daf502c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.gd @@ -0,0 +1,6 @@ +const TestClass = preload("gdscript_duplicate_class.notest.gd") + +func test(): + # TestClass.duplicate() fails + @warning_ignore("return_value_discarded") + (TestClass as GDScript).duplicate() diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.out b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate_class.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate_class.notest.gd new file mode 100644 index 0000000000..61510e14cd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_duplicate_class.notest.gd @@ -0,0 +1 @@ +extends Node diff --git a/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.gd b/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.gd new file mode 100644 index 0000000000..1ac03c2181 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.gd @@ -0,0 +1,7 @@ +extends RefCounted + +func test(): + print("ok") + +class Inner extends Node: + @onready var okay = 0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.out b/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.out new file mode 100644 index 0000000000..1b47ed10dc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/onready_on_inner_class_with_non_node_outer.out @@ -0,0 +1,2 @@ +GDTEST_OK +ok diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd index e1e6134fd4..092ae49d00 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd @@ -201,4 +201,10 @@ func test(): assert(typed_enums.get_typed_builtin() == TYPE_INT) + var a := A.new() + var typed_natives: Array[RefCounted] = [a] + var typed_scripts = Array(typed_natives, TYPE_OBJECT, "RefCounted", A) + assert(typed_scripts[0] == a) + + print('ok') diff --git a/modules/gdscript/tests/scripts/parser/features/super_class_check.gd b/modules/gdscript/tests/scripts/parser/features/super_class_check.gd new file mode 100644 index 0000000000..edfc45a8d8 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/super_class_check.gd @@ -0,0 +1,13 @@ +# https://github.com/godotengine/godot/issues/71994 + +func test(): + pass + +class A extends RefCounted: + pass + +class B extends A: + # Parsing `duplicate()` here would throw this error: + # Parse Error: The function signature doesn't match the parent. Parent signature is "duplicate(bool = default) -> Resource". + func duplicate(): + pass diff --git a/modules/gdscript/tests/scripts/parser/features/super_class_check.out b/modules/gdscript/tests/scripts/parser/features/super_class_check.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/super_class_check.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/runtime/features/static_duplicate.gd b/modules/gdscript/tests/scripts/runtime/features/static_duplicate.gd new file mode 100644 index 0000000000..418501dcc5 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/static_duplicate.gd @@ -0,0 +1,19 @@ +const PreloadClass = preload("static_duplicate_preload.notest.gd") +const PreloadClassAlias = PreloadClass + +func test(): + var dup_preload_one = PreloadClass.duplicate() + print(dup_preload_one == Vector2.ONE) + + var dup_preload_two = (PreloadClass as GDScript).duplicate() + print(dup_preload_two is GDScript) + + var dup_preload_alias_one = PreloadClassAlias.duplicate() + print(dup_preload_alias_one == Vector2.ONE) + + var dup_preload_alias_two = (PreloadClassAlias as GDScript).duplicate() + print(dup_preload_alias_two is GDScript) + + var PreloadClassAsGDScript = PreloadClass as GDScript + var dup_preload_class_as_gdscript_one = PreloadClassAsGDScript.duplicate() + print(dup_preload_class_as_gdscript_one is GDScript) diff --git a/modules/gdscript/tests/scripts/runtime/features/static_duplicate.out b/modules/gdscript/tests/scripts/runtime/features/static_duplicate.out new file mode 100644 index 0000000000..34cd5c7652 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/static_duplicate.out @@ -0,0 +1,9 @@ +GDTEST_OK +preload duplicate +true +true +preload duplicate +true +true +preload duplicate +false diff --git a/modules/gdscript/tests/scripts/runtime/features/static_duplicate_preload.notest.gd b/modules/gdscript/tests/scripts/runtime/features/static_duplicate_preload.notest.gd new file mode 100644 index 0000000000..291ffc2c0b --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/static_duplicate_preload.notest.gd @@ -0,0 +1,5 @@ +extends RefCounted + +static func duplicate() -> Vector2: + print("preload duplicate") + return Vector2.ONE diff --git a/modules/gltf/editor/editor_import_blend_runner.cpp b/modules/gltf/editor/editor_import_blend_runner.cpp index c203a91834..659a60e6a1 100644 --- a/modules/gltf/editor/editor_import_blend_runner.cpp +++ b/modules/gltf/editor/editor_import_blend_runner.cpp @@ -181,7 +181,18 @@ Error EditorImportBlendRunner::start_blender(const String &p_python_script, bool Error EditorImportBlendRunner::do_import(const Dictionary &p_options) { if (is_using_rpc()) { - return do_import_rpc(p_options); + Error err = do_import_rpc(p_options); + if (err != OK) { + // Retry without using RPC (slow, but better than the import failing completely). + if (err == ERR_CONNECTION_ERROR) { + // Disable RPC if the connection could not be established. + print_error(vformat("Failed to connect to Blender via RPC, switching to direct imports of .blend files. Check your proxy and firewall settings, then RPC can be re-enabled by changing the editor setting `filesystem/import/blender/rpc_port` to %d.", rpc_port)); + EditorSettings::get_singleton()->set_manually("filesystem/import/blender/rpc_port", 0); + rpc_port = 0; + } + err = do_import_direct(p_options); + } + return err; } else { return do_import_direct(p_options); } diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 8cc2b1eb97..fdd2fed836 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -800,6 +800,12 @@ bool EditorExportPlatformAndroid::_has_manage_external_storage_permission(const return p_permissions.find("android.permission.MANAGE_EXTERNAL_STORAGE") != -1; } +bool EditorExportPlatformAndroid::_uses_vulkan() { + String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile"); + bool uses_vulkan = (current_renderer == "forward_plus" || current_renderer == "mobile") && GLOBAL_GET("rendering/rendering_device/driver.android") == "vulkan"; + return uses_vulkan; +} + void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) { const char **aperms = android_perms; while (*aperms) { @@ -854,7 +860,7 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres } } - manifest_text += _get_xr_features_tag(p_preset); + manifest_text += _get_xr_features_tag(p_preset, _uses_vulkan()); manifest_text += _get_application_tag(p_preset, _has_read_write_storage_permission(perms)); manifest_text += "</manifest>\n"; String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")); @@ -1057,9 +1063,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p Vector<bool> feature_required_list; Vector<int> feature_versions; - String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile"); - bool has_vulkan = current_renderer == "forward_plus" || current_renderer == "mobile"; - if (has_vulkan) { + if (_uses_vulkan()) { // Require vulkan hardware level 1 support feature_names.push_back("android.hardware.vulkan.level"); feature_required_list.push_back(true); @@ -1698,12 +1702,12 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_build/use_custom_build"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); // Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465). // This implies doing validation that the string is a proper int. - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_MIN_SDK_VERSION)), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_MIN_SDK_VERSION)), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "")); Vector<PluginConfigAndroid> plugins_configs = get_plugins(); for (int i = 0; i < plugins_configs.size(); i++) { @@ -2128,11 +2132,11 @@ String EditorExportPlatformAndroid::get_apksigner_path(int p_target_sdk, bool p_ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; - const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build"); + const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build"); // Look for export templates (first official, and if defined custom templates). - if (!custom_build_enabled) { + if (!gradle_build_enabled) { String template_err; bool dvalid = false; bool rvalid = false; @@ -2239,7 +2243,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito valid = false; } - String target_sdk_version = p_preset->get("custom_build/target_sdk"); + String target_sdk_version = p_preset->get("gradle_build/target_sdk"); if (!target_sdk_version.is_valid_int()) { target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION); } @@ -2263,7 +2267,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { String err; bool valid = true; - const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build"); + const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build"); // Validate the project configuration. bool apk_expansion = p_preset->get("apk_expansion/enable"); @@ -2292,11 +2296,11 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit err += etc_error; } - // Ensure that `Use Custom Build` is enabled if a plugin is selected. + // Ensure that `Use Gradle Build` is enabled if a plugin is selected. String enabled_plugins_names = PluginConfigAndroid::get_plugins_names(get_enabled_plugins(p_preset)); - if (!enabled_plugins_names.is_empty() && !custom_build_enabled) { + if (!enabled_plugins_names.is_empty() && !gradle_build_enabled) { valid = false; - err += TTR("\"Use Custom Build\" must be enabled to use the plugins."); + err += TTR("\"Use Gradle Build\" must be enabled to use the plugins."); err += "\n"; } @@ -2304,9 +2308,9 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit int xr_mode_index = p_preset->get("xr_features/xr_mode"); int hand_tracking = p_preset->get("xr_features/hand_tracking"); int passthrough_mode = p_preset->get("xr_features/passthrough"); - if (xr_mode_index == XR_MODE_OPENXR && !custom_build_enabled) { + if (xr_mode_index == XR_MODE_OPENXR && !gradle_build_enabled) { valid = false; - err += TTR("OpenXR requires \"Use Custom Build\" to be enabled"); + err += TTR("OpenXR requires \"Use Gradle Build\" to be enabled"); err += "\n"; } @@ -2324,20 +2328,20 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit } } - if (int(p_preset->get("custom_build/export_format")) == EXPORT_FORMAT_AAB && - !custom_build_enabled) { + if (int(p_preset->get("gradle_build/export_format")) == EXPORT_FORMAT_AAB && + !gradle_build_enabled) { valid = false; - err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."); + err += TTR("\"Export AAB\" is only valid when \"Use Gradle Build\" is enabled."); err += "\n"; } // Check the min sdk version. - String min_sdk_str = p_preset->get("custom_build/min_sdk"); + String min_sdk_str = p_preset->get("gradle_build/min_sdk"); int min_sdk_int = DEFAULT_MIN_SDK_VERSION; if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do. - if (!custom_build_enabled) { + if (!gradle_build_enabled) { valid = false; - err += TTR("\"Min SDK\" can only be overridden when \"Use Custom Build\" is enabled."); + err += TTR("\"Min SDK\" can only be overridden when \"Use Gradle Build\" is enabled."); err += "\n"; } if (!min_sdk_str.is_valid_int()) { @@ -2355,12 +2359,12 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit } // Check the target sdk version. - String target_sdk_str = p_preset->get("custom_build/target_sdk"); + String target_sdk_str = p_preset->get("gradle_build/target_sdk"); int target_sdk_int = DEFAULT_TARGET_SDK_VERSION; if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do. - if (!custom_build_enabled) { + if (!gradle_build_enabled) { valid = false; - err += TTR("\"Target SDK\" can only be overridden when \"Use Custom Build\" is enabled."); + err += TTR("\"Target SDK\" can only be overridden when \"Use Gradle Build\" is enabled."); err += "\n"; } if (!target_sdk_str.is_valid_int()) { @@ -2384,13 +2388,12 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit } String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile"); - bool uses_vulkan = current_renderer == "forward_plus" || current_renderer == "mobile"; if (current_renderer == "forward_plus") { // Warning only, so don't override `valid`. err += vformat(TTR("The \"%s\" renderer is designed for Desktop devices, and is not suitable for Android devices."), current_renderer); err += "\n"; } - if (uses_vulkan && min_sdk_int < VULKAN_MIN_SDK_VERSION) { + if (_uses_vulkan() && min_sdk_int < VULKAN_MIN_SDK_VERSION) { // Warning only, so don't override `valid`. err += vformat(TTR("\"Min SDK\" should be greater or equal to %d for the \"%s\" renderer."), VULKAN_MIN_SDK_VERSION, current_renderer); err += "\n"; @@ -2481,12 +2484,12 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP } Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) { - int export_format = int(p_preset->get("custom_build/export_format")); + int export_format = int(p_preset->get("gradle_build/export_format")); String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK"; String release_keystore = p_preset->get("keystore/release"); String release_username = p_preset->get("keystore/release_user"); String release_password = p_preset->get("keystore/release_password"); - String target_sdk_version = p_preset->get("custom_build/target_sdk"); + String target_sdk_version = p_preset->get("gradle_build/target_sdk"); if (!target_sdk_version.is_valid_int()) { target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION); } @@ -2663,7 +2666,7 @@ String EditorExportPlatformAndroid::join_abis(const Vector<EditorExportPlatformA } Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - int export_format = int(p_preset->get("custom_build/export_format")); + int export_format = int(p_preset->get("gradle_build/export_format")); bool should_sign = p_preset->get("package/signed"); return export_project_helper(p_preset, p_debug, p_path, export_format, should_sign, p_flags); } @@ -2676,7 +2679,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP EditorProgress ep("export", TTR("Exporting for Android"), 105, true); - bool use_custom_build = bool(p_preset->get("custom_build/use_custom_build")); + bool use_gradle_build = bool(p_preset->get("gradle_build/use_gradle_build")); bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); bool apk_expansion = p_preset->get("apk_expansion/enable"); Vector<ABI> enabled_abis = get_enabled_abis(p_preset); @@ -2686,7 +2689,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP print_verbose("- export path: " + p_path); print_verbose("- export format: " + itos(export_format)); print_verbose("- sign build: " + bool_to_string(should_sign)); - print_verbose("- custom build enabled: " + bool_to_string(use_custom_build)); + print_verbose("- gradle build enabled: " + bool_to_string(use_gradle_build)); print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion)); print_verbose("- enabled abis: " + join_abis(enabled_abis, ",", false)); print_verbose("- export filter: " + itos(p_preset->get_export_filter())); @@ -2726,14 +2729,14 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return ERR_UNCONFIGURED; } - if (use_custom_build) { - print_verbose("Starting custom build..."); + if (use_gradle_build) { + print_verbose("Starting gradle build..."); //test that installed build version is alright { print_verbose("Checking build version..."); Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::READ); if (f.is_null()) { - add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Trying to build from a gradle built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); return ERR_UNCONFIGURED; } String version = f->get_line().strip_edges(); @@ -2803,11 +2806,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP String package_name = get_package_name(p_preset->get("package/unique_name")); String version_code = itos(p_preset->get("version/code")); String version_name = p_preset->get("version/name"); - String min_sdk_version = p_preset->get("custom_build/min_sdk"); + String min_sdk_version = p_preset->get("gradle_build/min_sdk"); if (!min_sdk_version.is_valid_int()) { min_sdk_version = itos(DEFAULT_MIN_SDK_VERSION); } - String target_sdk_version = p_preset->get("custom_build/target_sdk"); + String target_sdk_version = p_preset->get("gradle_build/target_sdk"); if (!target_sdk_version.is_valid_int()) { target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION); } @@ -2933,7 +2936,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return ERR_CANT_CREATE; } - print_verbose("Successfully completed Android custom build."); + print_verbose("Successfully completed Android gradle build."); return OK; } // This is the start of the Legacy build system diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index bff769fcba..337a0228d0 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -74,7 +74,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Vector<PluginConfigAndroid> plugins; String last_plugin_names; - uint64_t last_custom_build_time = 0; + uint64_t last_gradle_build_time = 0; SafeFlag plugins_changed; Mutex plugins_lock; Vector<Device> devices; @@ -172,6 +172,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { static Vector<ABI> get_enabled_abis(const Ref<EditorExportPreset> &p_preset); + static bool _uses_vulkan(); + public: typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); @@ -213,14 +215,14 @@ public: inline bool is_clean_build_required(Vector<PluginConfigAndroid> enabled_plugins) { String plugin_names = PluginConfigAndroid::get_plugins_names(enabled_plugins); - bool first_build = last_custom_build_time == 0; + bool first_build = last_gradle_build_time == 0; bool have_plugins_changed = false; if (!first_build) { have_plugins_changed = plugin_names != last_plugin_names; if (!have_plugins_changed) { for (int i = 0; i < enabled_plugins.size(); i++) { - if (enabled_plugins.get(i).last_updated > last_custom_build_time) { + if (enabled_plugins.get(i).last_updated > last_gradle_build_time) { have_plugins_changed = true; break; } @@ -228,7 +230,7 @@ public: } } - last_custom_build_time = OS::get_singleton()->get_unix_time(); + last_gradle_build_time = OS::get_singleton()->get_unix_time(); last_plugin_names = plugin_names; return have_plugins_changed || first_build; diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 7eb595f48d..b889d58199 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -166,7 +166,7 @@ Error store_string_at_path(const String &p_path, const String &p_data) { // This method will only be called as an input to export_project_files. // It is used by the export_project_files method to save all the asset files into the gradle project. // It's functionality mirrors that of the method save_apk_file. -// This method will be called ONLY when custom build is enabled. +// This method will be called ONLY when gradle build is enabled. Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) { CustomExportData *export_data = static_cast<CustomExportData *>(p_userdata); String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/"); @@ -254,7 +254,7 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) { return manifest_screen_sizes; } -String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) { +String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_vulkan) { String manifest_xr_features; int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); bool uses_xr = xr_mode_index == XR_MODE_OPENXR; @@ -274,9 +274,7 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) { } } - String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile"); - bool has_vulkan = current_renderer == "forward_plus" || current_renderer == "mobile"; - if (has_vulkan) { + if (p_uses_vulkan) { manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vulkan.level\" android:required=\"true\" android:version=\"1\" />\n"; } return manifest_xr_features; diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index fe5888e11c..8a885a0d12 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -104,7 +104,7 @@ Error store_string_at_path(const String &p_path, const String &p_data); // This method will only be called as an input to export_project_files. // It is used by the export_project_files method to save all the asset files into the gradle project. // It's functionality mirrors that of the method save_apk_file. -// This method will be called ONLY when custom build is enabled. +// This method will be called ONLY when gradle build is enabled. Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); // Creates strings.xml files inside the gradle project for different locales. @@ -116,7 +116,7 @@ String _get_gles_tag(); String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset); -String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset); +String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_vulkan); String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr); diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 63b10e62b1..01b148aeef 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -50,7 +50,7 @@ dependencies { } else if (rootProject.findProject(":godot:lib")) { implementation project(":godot:lib") } else { - // Custom build mode. In this scenario this project is the only one around and the Godot + // Godot gradle build mode. In this scenario this project is the only one around and the Godot // library is available through the pre-generated godot-lib.*.aar android archive files. debugImplementation fileTree(dir: 'libs/debug', include: ['*.jar', '*.aar']) devImplementation fileTree(dir: 'libs/dev', include: ['*.jar', '*.aar']) @@ -153,7 +153,7 @@ android { debug { // Signing and zip-aligning are skipped for prebuilt builds, but - // performed for custom builds. + // performed for Godot gradle builds. zipAlignEnabled shouldZipAlign() if (shouldSign()) { signingConfig signingConfigs.debug @@ -165,7 +165,7 @@ android { dev { initWith debug // Signing and zip-aligning are skipped for prebuilt builds, but - // performed for custom builds. + // performed for Godot gradle builds. zipAlignEnabled shouldZipAlign() if (shouldSign()) { signingConfig signingConfigs.debug @@ -176,7 +176,7 @@ android { release { // Signing and zip-aligning are skipped for prebuilt builds, but - // performed for custom builds. + // performed for Godot gradle builds. zipAlignEnabled shouldZipAlign() if (shouldSign()) { signingConfig signingConfigs.release diff --git a/platform/android/java/app/gradle.properties b/platform/android/java/app/gradle.properties index 0ad8e611ca..d9f79b6818 100644 --- a/platform/android/java/app/gradle.properties +++ b/platform/android/java/app/gradle.properties @@ -1,5 +1,5 @@ -# Godot custom build Gradle settings. -# These properties apply when running custom build from the Godot editor. +# Godot gradle build settings. +# These properties apply when running a gradle build from the Godot editor. # NOTE: This should be kept in sync with 'godot/platform/android/java/gradle.properties' except # where otherwise specified. diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle index ba53aefe7f..b4524a3f60 100644 --- a/platform/android/java/app/settings.gradle +++ b/platform/android/java/app/settings.gradle @@ -1,4 +1,4 @@ -// This is the root directory of the Godot custom build. +// This is the root directory of the Godot Android gradle build. pluginManagement { apply from: 'config.gradle' diff --git a/platform/android/java/app/src/com/godot/game/GodotApp.java b/platform/android/java/app/src/com/godot/game/GodotApp.java index a43e289b6b..1d2cc05715 100644 --- a/platform/android/java/app/src/com/godot/game/GodotApp.java +++ b/platform/android/java/app/src/com/godot/game/GodotApp.java @@ -35,7 +35,7 @@ import org.godotengine.godot.FullScreenGodotApp; import android.os.Bundle; /** - * Template activity for Godot Android custom builds. + * Template activity for Godot Android builds. * Feel free to extend and modify this class for your custom logic. */ public class GodotApp extends FullScreenGodotApp { diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index 5a91e5ce32..cffe0a33d9 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -152,14 +152,14 @@ task copyReleaseAARToBin(type: Copy) { } /** - * Generate Godot custom build template by zipping the source files from the app directory, as well + * Generate Godot gradle build template by zipping the source files from the app directory, as well * as the AAR files generated by 'copyDebugAAR', 'copyDevAAR' and 'copyReleaseAAR'. - * The zip file also includes some gradle tools to allow building of the custom build. + * The zip file also includes some gradle tools to enable gradle builds from the Godot Editor. */ -task zipCustomBuild(type: Zip) { +task zipGradleBuild(type: Zip) { onlyIf { generateGodotTemplates.state.executed || generateDevTemplate.state.executed } doFirst { - logger.lifecycle("Generating Godot custom build template") + logger.lifecycle("Generating Godot gradle build template") } from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradlew', 'gradlew.bat', 'gradle/**'])) include '**/*' @@ -195,7 +195,7 @@ def templateBuildTasks() { && targetLibs.listFiles() != null && targetLibs.listFiles().length > 0) { String capitalizedTarget = target.capitalize() - // Copy the generated aar library files to the custom build directory. + // Copy the generated aar library files to the build directory. tasks += "copy" + capitalizedTarget + "AARToAppModule" // Copy the generated aar library files to the bin directory. tasks += "copy" + capitalizedTarget + "AARToBin" @@ -260,7 +260,7 @@ task generateGodotTemplates { gradle.startParameter.excludedTaskNames += templateExcludedBuildTask() dependsOn = templateBuildTasks() - finalizedBy 'zipCustomBuild' + finalizedBy 'zipGradleBuild' } /** @@ -273,7 +273,7 @@ task generateDevTemplate { gradle.startParameter.excludedTaskNames += templateExcludedBuildTask() dependsOn = templateBuildTasks() - finalizedBy 'zipCustomBuild' + finalizedBy 'zipGradleBuild' } task clean(type: Delete) { diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties index 5cd94e85d9..39a0dcda16 100644 --- a/platform/android/java/gradle.properties +++ b/platform/android/java/gradle.properties @@ -24,5 +24,5 @@ org.gradle.jvmargs=-Xmx4536m org.gradle.warning.mode=all # Disable resource optimizations for template release build. -# NOTE: This is turned on for custom build in order to improve the release build. +# NOTE: This is turned on for Godot Editor's gradle builds in order to improve the release build. android.enableResourceOptimizations=false diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 6296ee2c22..307fa7bae1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -275,16 +275,16 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC return false; } - final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method"); - if (renderer.equals("gl_compatibility")) { - mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl); - } else { + if (usesVulkan()) { if (!meetsVulkanRequirements(activity.getPackageManager())) { Log.e(TAG, "Missing requirements for vulkan support! Aborting..."); alert(R.string.error_missing_vulkan_requirements_message, R.string.text_error_title, this::forceQuit); return false; } mRenderView = new GodotVulkanRenderView(activity, this); + } else { + // Fallback to openGl + mRenderView = new GodotGLRenderView(activity, this, xrMode, use_debug_opengl); } View view = mRenderView.getView(); @@ -323,6 +323,15 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } /** + * Returns true if `Vulkan` is used for rendering. + */ + private boolean usesVulkan() { + final String renderer = GodotLib.getGlobal("rendering/renderer/rendering_method"); + final String renderingDevice = GodotLib.getGlobal("rendering/rendering_device/driver"); + return ("forward_plus".equals(renderer) || "mobile".equals(renderer)) && "vulkan".equals(renderingDevice); + } + + /** * Returns true if the device meets the base requirements for Vulkan support, false otherwise. */ private boolean meetsVulkanRequirements(@Nullable PackageManager packageManager) { diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index d28a6fcc04..0e9e02f247 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -61,7 +61,15 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &p_property) con } void AnimationNodeBlendSpace1D::_tree_changed() { - emit_signal(SNAME("tree_changed")); + AnimationRootNode::_tree_changed(); +} + +void AnimationNodeBlendSpace1D::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name); +} + +void AnimationNodeBlendSpace1D::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + AnimationRootNode::_animation_node_removed(p_oid, p_node); } void AnimationNodeBlendSpace1D::_bind_methods() { @@ -137,6 +145,8 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_ blend_points[p_at_index].position = p_position; blend_points[p_at_index].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace1D::_tree_changed), CONNECT_REFERENCE_COUNTED); + blend_points[p_at_index].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + blend_points[p_at_index].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_removed), CONNECT_REFERENCE_COUNTED); blend_points_used++; emit_signal(SNAME("tree_changed")); @@ -154,10 +164,14 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim if (blend_points[p_point].node.is_valid()) { blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace1D::_tree_changed)); + blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_renamed)); + blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_removed)); } blend_points[p_point].node = p_node; blend_points[p_point].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace1D::_tree_changed), CONNECT_REFERENCE_COUNTED); + blend_points[p_point].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + blend_points[p_point].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_removed), CONNECT_REFERENCE_COUNTED); emit_signal(SNAME("tree_changed")); } @@ -177,12 +191,16 @@ void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) { ERR_FAIL_COND(blend_points[p_point].node.is_null()); blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace1D::_tree_changed)); + blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_renamed)); + blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_removed)); for (int i = p_point; i < blend_points_used - 1; i++) { blend_points[i] = blend_points[i + 1]; } blend_points_used--; + + emit_signal(SNAME("animation_node_removed"), get_instance_id(), itos(p_point)); emit_signal(SNAME("tree_changed")); } diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index a1e9a7a764..4007df0ded 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -66,20 +66,21 @@ protected: void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); - void _tree_changed(); - StringName blend_position = "blend_position"; StringName closest = "closest"; StringName length_internal = "length_internal"; BlendMode blend_mode = BLEND_MODE_INTERPOLATED; -protected: bool sync = false; void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); + virtual void _tree_changed() override; + virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override; + virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override; + public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index c37d54961e..ae5b0d5779 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -81,6 +81,8 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_ blend_points[p_at_index].position = p_position; blend_points[p_at_index].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed), CONNECT_REFERENCE_COUNTED); + blend_points[p_at_index].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + blend_points[p_at_index].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed), CONNECT_REFERENCE_COUNTED); blend_points_used++; _queue_auto_triangles(); @@ -100,9 +102,13 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim if (blend_points[p_point].node.is_valid()) { blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed)); + blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed)); + blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed)); } blend_points[p_point].node = p_node; blend_points[p_point].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed), CONNECT_REFERENCE_COUNTED); + blend_points[p_point].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + blend_points[p_point].node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed), CONNECT_REFERENCE_COUNTED); emit_signal(SNAME("tree_changed")); } @@ -122,6 +128,8 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { ERR_FAIL_COND(blend_points[p_point].node.is_null()); blend_points[p_point].node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed)); + blend_points[p_point].node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed)); + blend_points[p_point].node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_removed)); for (int i = 0; i < triangles.size(); i++) { bool erase = false; @@ -144,6 +152,8 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { blend_points[i] = blend_points[i + 1]; } blend_points_used--; + + emit_signal(SNAME("animation_node_removed"), get_instance_id(), itos(p_point)); emit_signal(SNAME("tree_changed")); } @@ -598,10 +608,6 @@ Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName return get_blend_point_node(p_name.operator String().to_int()); } -void AnimationNodeBlendSpace2D::_tree_changed() { - emit_signal(SNAME("tree_changed")); -} - void AnimationNodeBlendSpace2D::set_blend_mode(BlendMode p_blend_mode) { blend_mode = p_blend_mode; } @@ -618,6 +624,18 @@ bool AnimationNodeBlendSpace2D::is_using_sync() const { return sync; } +void AnimationNodeBlendSpace2D::_tree_changed() { + AnimationRootNode::_tree_changed(); +} + +void AnimationNodeBlendSpace2D::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name); +} + +void AnimationNodeBlendSpace2D::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + AnimationRootNode::_animation_node_removed(p_oid, p_node); +} + void AnimationNodeBlendSpace2D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position); diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 044c93d9f6..a770bf01ee 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -85,14 +85,15 @@ protected: void _update_triangles(); void _queue_auto_triangles(); - void _tree_changed(); - -protected: bool sync = false; void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); + virtual void _tree_changed() override; + virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override; + virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override; + public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 12a96c8679..3fe46b380f 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -721,12 +721,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const { if (p_parameter == time || p_parameter == prev_xfading) { return 0.0; - } else if (p_parameter == prev_index) { + } else if (p_parameter == prev_index || p_parameter == current_index) { return -1; - } else if (p_parameter == transition_request || p_parameter == current_state) { - return String(); } else { - return 0; + return String(); } } @@ -748,6 +746,10 @@ void AnimationNodeTransition::set_input_count(int p_inputs) { while (get_input_count() > p_inputs) { remove_input(get_input_count() - 1); } + + pending_update = true; + + emit_signal(SNAME("tree_changed")); // For updating connect activity map. notify_property_list_changed(); } @@ -764,6 +766,11 @@ void AnimationNodeTransition::remove_input(int p_index) { AnimationNode::remove_input(p_index); } +bool AnimationNodeTransition::set_input_name(int p_input, const String &p_name) { + pending_update = true; + return AnimationNode::set_input_name(p_input, p_name); +} + void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) { ERR_FAIL_INDEX(p_input, get_input_count()); input_data.write[p_input].auto_advance = p_enable; @@ -819,6 +826,22 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex bool switched = false; bool restart = false; + if (pending_update) { + if (cur_current_index < 0 || cur_current_index >= get_input_count()) { + set_parameter(prev_index, -1); + if (get_input_count() > 0) { + set_parameter(current_index, 0); + set_parameter(current_state, get_input_name(0)); + } else { + set_parameter(current_index, -1); + set_parameter(current_state, StringName()); + } + } else { + set_parameter(current_state, get_input_name(cur_current_index)); + } + pending_update = false; + } + if (!cur_transition_request.is_empty()) { int new_idx = find_input(cur_transition_request); if (new_idx >= 0) { @@ -985,6 +1008,8 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod emit_signal(SNAME("tree_changed")); p_node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed), CONNECT_REFERENCE_COUNTED); p_node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_name), CONNECT_REFERENCE_COUNTED); } @@ -1047,6 +1072,8 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { { Ref<AnimationNode> node = nodes[p_name].node; node->disconnect("tree_changed", callable_mp(this, &AnimationNodeBlendTree::_tree_changed)); + node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed)); + node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed)); node->disconnect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed)); } @@ -1061,6 +1088,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { } } + emit_signal(SNAME("animation_node_removed"), get_instance_id(), p_name); emit_changed(); emit_signal(SNAME("tree_changed")); } @@ -1087,6 +1115,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN // Connection must be done with new name. nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED); + emit_signal(SNAME("animation_node_renamed"), get_instance_id(), p_name, p_new_name); emit_signal(SNAME("tree_changed")); } @@ -1287,6 +1316,18 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); } +void AnimationNodeBlendTree::_tree_changed() { + AnimationRootNode::_tree_changed(); +} + +void AnimationNodeBlendTree::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name); +} + +void AnimationNodeBlendTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + AnimationRootNode::_animation_node_removed(p_oid, p_node); +} + void AnimationNodeBlendTree::reset_state() { graph_offset = Vector2(); nodes.clear(); @@ -1295,10 +1336,6 @@ void AnimationNodeBlendTree::reset_state() { emit_signal(SNAME("tree_changed")); } -void AnimationNodeBlendTree::_tree_changed() { - emit_signal(SNAME("tree_changed")); -} - void AnimationNodeBlendTree::_node_changed(const StringName &p_node) { ERR_FAIL_COND(!nodes.has(p_node)); nodes[p_node].connections.resize(nodes[p_node].node->get_input_count()); diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 1e90952564..d4827180bb 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -296,6 +296,8 @@ class AnimationNodeTransition : public AnimationNodeSync { Ref<Curve> xfade_curve; bool allow_transition_to_self = false; + bool pending_update = false; + protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); @@ -313,6 +315,7 @@ public: virtual bool add_input(const String &p_name) override; virtual void remove_input(int p_index) override; + virtual bool set_input_name(int p_input, const String &p_name) override; void set_input_as_auto_advance(int p_input, bool p_enable); bool is_input_set_as_auto_advance(int p_input) const; @@ -358,7 +361,6 @@ class AnimationNodeBlendTree : public AnimationRootNode { Vector2 graph_offset; - void _tree_changed(); void _node_changed(const StringName &p_node); void _initialize_node_tree(); @@ -369,6 +371,10 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void _tree_changed() override; + virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override; + virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override; + virtual void reset_state() override; public: diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index ec28a5cca1..d19d3cc7a3 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -791,6 +791,8 @@ void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<Animation emit_signal(SNAME("tree_changed")); p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed), CONNECT_REFERENCE_COUNTED); } void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<AnimationNode> p_node) { @@ -802,6 +804,8 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima Ref<AnimationNode> node = states[p_name].node; if (node.is_valid()) { node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed)); + node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed)); + node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed)); } } @@ -811,6 +815,8 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima emit_signal(SNAME("tree_changed")); p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed), CONNECT_REFERENCE_COUNTED); + p_node->connect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed), CONNECT_REFERENCE_COUNTED); } void AnimationNodeStateMachine::set_allow_transition_to_self(bool p_enable) { @@ -884,10 +890,13 @@ void AnimationNodeStateMachine::remove_node(const StringName &p_name) { Ref<AnimationNode> node = states[p_name].node; ERR_FAIL_COND(node.is_null()); node->disconnect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed)); + node->disconnect("animation_node_renamed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_renamed)); + node->disconnect("animation_node_removed", callable_mp(this, &AnimationNodeStateMachine::_animation_node_removed)); } states.erase(p_name); + emit_signal(SNAME("animation_node_removed"), get_instance_id(), p_name); emit_changed(); emit_signal(SNAME("tree_changed")); } @@ -907,6 +916,7 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri _rename_transitions(p_name, p_new_name); + emit_signal(SNAME("animation_node_renamed"), get_instance_id(), p_name, p_new_name); emit_changed(); emit_signal(SNAME("tree_changed")); } @@ -1365,7 +1375,15 @@ Vector2 AnimationNodeStateMachine::get_node_position(const StringName &p_name) c void AnimationNodeStateMachine::_tree_changed() { emit_changed(); - emit_signal(SNAME("tree_changed")); + AnimationRootNode::_tree_changed(); +} + +void AnimationNodeStateMachine::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + AnimationRootNode::_animation_node_renamed(p_oid, p_old_name, p_new_name); +} + +void AnimationNodeStateMachine::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + AnimationRootNode::_animation_node_removed(p_oid, p_node); } void AnimationNodeStateMachine::_bind_methods() { diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index 5c2a4d6264..5867b6c65a 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -207,7 +207,6 @@ private: Vector2 graph_offset; - void _tree_changed(); void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition); void _rename_transitions(const StringName &p_name, const StringName &p_new_name); bool _can_connect(const StringName &p_name, Vector<AnimationNodeStateMachine *> p_parents = Vector<AnimationNodeStateMachine *>()); @@ -221,6 +220,10 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; + virtual void _tree_changed() override; + virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override; + virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override; + virtual void reset_state() override; public: diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2e25d685d6..8087ac6250 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -857,7 +857,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double HashMap<int, TrackNodeCache::PlayingAudioStreamInfo> &map = aa->playing_streams; // Find stream. int idx = -1; - if (p_seeked) { + if (p_seeked || p_started) { idx = a->track_find_key(i, p_time); // Discard previous stream when seeking. if (map.has(idx)) { @@ -866,12 +866,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } } else { List<int> to_play; - if (p_started) { - int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT); - if (first_key >= 0) { - to_play.push_back(first_key); - } - } + a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag); if (to_play.size()) { idx = to_play.back()->get(); @@ -888,6 +883,10 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double double end_ofs = a->audio_track_get_key_end_offset(i, idx); double len = stream->get_length(); + if (p_seeked || p_started) { + start_ofs += p_time - a->track_get_key_time(i, idx); + } + if (aa->object->call(SNAME("get_stream")) != aa->audio_stream) { aa->object->call(SNAME("set_stream"), aa->audio_stream); aa->audio_stream_playback.unref(); @@ -1286,6 +1285,8 @@ void AnimationPlayer::_animation_process(double p_delta) { _animation_update_transforms(); if (end_reached) { + _clear_audio_streams(); + _stop_playing_caches(false); if (queued.size()) { String old = playback.assigned; play(queued.front()->get()); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index dd5bf31c66..7c2edef1de 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -453,6 +453,8 @@ void AnimationNode::_bind_methods() { GDVIRTUAL_BIND(_has_filter); ADD_SIGNAL(MethodInfo("tree_changed")); + ADD_SIGNAL(MethodInfo("animation_node_renamed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); + ADD_SIGNAL(MethodInfo("animation_node_removed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "name"))); BIND_ENUM_CONSTANT(FILTER_IGNORE); BIND_ENUM_CONSTANT(FILTER_PASS); @@ -465,15 +467,33 @@ AnimationNode::AnimationNode() { //////////////////// +void AnimationRootNode::_tree_changed() { + emit_signal(SNAME("tree_changed")); +} + +void AnimationRootNode::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + emit_signal(SNAME("animation_node_renamed"), p_oid, p_old_name, p_new_name); +} + +void AnimationRootNode::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + emit_signal(SNAME("animation_node_removed"), p_oid, p_node); +} + +//////////////////// + void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) { if (root.is_valid()) { root->disconnect("tree_changed", callable_mp(this, &AnimationTree::_tree_changed)); + root->disconnect("animation_node_renamed", callable_mp(this, &AnimationTree::_animation_node_renamed)); + root->disconnect("animation_node_removed", callable_mp(this, &AnimationTree::_animation_node_removed)); } root = p_root; if (root.is_valid()) { root->connect("tree_changed", callable_mp(this, &AnimationTree::_tree_changed)); + root->connect("animation_node_renamed", callable_mp(this, &AnimationTree::_animation_node_renamed)); + root->connect("animation_node_removed", callable_mp(this, &AnimationTree::_animation_node_removed)); } properties_dirty = true; @@ -1546,6 +1566,10 @@ void AnimationTree::_process_graph(double p_delta) { double end_ofs = a->audio_track_get_key_end_offset(i, idx); double len = stream->get_length(); + if (seeked) { + start_ofs += time - a->track_get_key_time(i, idx); + } + if (t->object->call(SNAME("get_stream")) != t->audio_stream) { t->object->call(SNAME("set_stream"), t->audio_stream); t->audio_stream_playback.unref(); @@ -1982,11 +2006,46 @@ void AnimationTree::_tree_changed() { properties_dirty = true; } +void AnimationTree::_animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) { + ERR_FAIL_COND(!property_reference_map.has(p_oid)); + String base_path = property_reference_map[p_oid]; + String old_base = base_path + p_old_name; + String new_base = base_path + p_new_name; + for (const PropertyInfo &E : properties) { + if (E.name.begins_with(old_base)) { + String new_name = E.name.replace_first(old_base, new_base); + property_map[new_name] = property_map[E.name]; + property_map.erase(E.name); + } + } + + //update tree second + properties_dirty = true; + _update_properties(); +} + +void AnimationTree::_animation_node_removed(const ObjectID &p_oid, const StringName &p_node) { + ERR_FAIL_COND(!property_reference_map.has(p_oid)); + String base_path = String(property_reference_map[p_oid]) + String(p_node); + for (const PropertyInfo &E : properties) { + if (E.name.begins_with(base_path)) { + property_map.erase(E.name); + } + } + + //update tree second + properties_dirty = true; + _update_properties(); +} + void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) { ERR_FAIL_COND(node.is_null()); if (!property_parent_map.has(p_base_path)) { property_parent_map[p_base_path] = HashMap<StringName, StringName>(); } + if (!property_reference_map.has(node->get_instance_id())) { + property_reference_map[node->get_instance_id()] = p_base_path; + } if (node->get_input_count() && !input_activity_map.has(p_base_path)) { Vector<Activity> activity; @@ -2032,6 +2091,7 @@ void AnimationTree::_update_properties() { } properties.clear(); + property_reference_map.clear(); property_parent_map.clear(); input_activity_map.clear(); input_activity_map_get.clear(); diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index c5c2790fae..0540add85b 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -167,6 +167,11 @@ VARIANT_ENUM_CAST(AnimationNode::FilterAction) class AnimationRootNode : public AnimationNode { GDCLASS(AnimationRootNode, AnimationNode); +protected: + virtual void _tree_changed(); + virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name); + virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node); + public: AnimationRootNode() {} }; @@ -326,9 +331,12 @@ private: friend class AnimationNode; bool properties_dirty = true; void _tree_changed(); + void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name); + void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node); void _update_properties(); List<PropertyInfo> properties; HashMap<StringName, HashMap<StringName, StringName>> property_parent_map; + HashMap<ObjectID, StringName> property_reference_map; HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag. struct Activity { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index a930b8d972..ec75fcb665 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -3392,7 +3392,7 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("minimum_size_changed")); ADD_SIGNAL(MethodInfo("theme_changed")); - GDVIRTUAL_BIND(_has_point, "position"); + GDVIRTUAL_BIND(_has_point, "point"); GDVIRTUAL_BIND(_structured_text_parser, "args", "text"); GDVIRTUAL_BIND(_get_minimum_size); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 027c97b383..dc1d6cc73e 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -491,9 +491,11 @@ void OptionButton::show_popup() { return; } - Size2 button_size = get_global_transform_with_canvas().get_scale() * get_size(); - popup->set_position(get_screen_position() + Size2(0, button_size.height)); - popup->set_size(Size2i(button_size.width, 0)); + Rect2 rect = get_screen_rect(); + rect.position.y += rect.size.height; + rect.size.height = 0; + popup->set_position(rect.position); + popup->set_size(rect.size); // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused. if (current != NONE_SELECTED && !popup->is_item_disabled(current)) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 7091dd0388..cbb34a480b 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -614,7 +614,7 @@ void Viewport::_process_picking() { physics_last_mouse_state.mouse_mask.clear_flag(mouse_button_to_mask(mb->get_button_index())); // If touch mouse raised, assume we don't know last mouse pos until new events come - if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { + if (mb->get_device() == InputEvent::DEVICE_ID_EMULATION) { physics_has_last_mousepos = false; } } @@ -1348,7 +1348,7 @@ bool Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu Ref<InputEvent> ev = p_input; // Returns true if an event should be impacted by a control's mouse filter. - bool is_mouse_event = Ref<InputEventMouse>(p_input).is_valid(); + bool is_pointer_event = Ref<InputEventMouse>(p_input).is_valid() || Ref<InputEventScreenDrag>(p_input).is_valid() || Ref<InputEventScreenTouch>(p_input).is_valid(); Ref<InputEventMouseButton> mb = p_input; bool is_scroll_event = mb.is_valid() && @@ -1372,8 +1372,8 @@ bool Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu stopped = true; break; } - if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP && is_mouse_event && !(is_scroll_event && control->data.force_pass_scroll_events)) { - // Mouse events are stopped by default with MOUSE_FILTER_STOP, unless we have a scroll event and force_pass_scroll_events set to true + if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP && is_pointer_event && !(is_scroll_event && control->data.force_pass_scroll_events)) { + // Mouse, ScreenDrag and ScreenTouch events are stopped by default with MOUSE_FILTER_STOP, unless we have a scroll event and force_pass_scroll_events set to true stopped = true; break; } @@ -2290,6 +2290,7 @@ void Viewport::_drop_mouse_focus() { mb->set_global_position(c->get_local_mouse_position()); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); + mb->set_device(InputEvent::DEVICE_ID_INTERNAL); c->_call_gui_input(mb); } } @@ -2401,6 +2402,7 @@ void Viewport::_post_gui_grab_click_focus() { mb->set_position(click); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); + mb->set_device(InputEvent::DEVICE_ID_INTERNAL); gui.mouse_focus->_call_gui_input(mb); } } @@ -2418,6 +2420,7 @@ void Viewport::_post_gui_grab_click_focus() { mb->set_position(click); mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(true); + mb->set_device(InputEvent::DEVICE_ID_INTERNAL); MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb); } } diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 33946246b0..9fcfb29ef7 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -647,6 +647,7 @@ void Window::update_mouse_cursor_shape() { mm.instantiate(); mm->set_position(pos); mm->set_global_position(xform.xform(pos)); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); push_input(mm); } diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index 9a3918fd86..b9e8bcc6f1 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -80,6 +80,7 @@ public: virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override { return RS::LIGHT_BAKE_DISABLED; } virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; } virtual uint64_t light_get_version(RID p_light) const override { return 0; } + virtual uint32_t light_get_cull_mask(RID p_light) const override { return 0; } /* LIGHT INSTANCE API */ diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 41251b348c..67661ce821 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -145,6 +145,7 @@ public: virtual void decal_set_normal_fade(RID p_decal, float p_fade) override {} virtual AABB decal_get_aabb(RID p_decal) const override { return AABB(); } + virtual uint32_t decal_get_cull_mask(RID p_decal) const override { return 0; } virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 968f804593..e65d842a67 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -389,6 +389,13 @@ uint64_t LightStorage::light_get_version(RID p_light) const { return light->version; } +uint32_t LightStorage::light_get_cull_mask(RID p_light) const { + const Light *light = light_owner.get_or_null(p_light); + ERR_FAIL_COND_V(!light, 0); + + return light->cull_mask; +} + AABB LightStorage::light_get_aabb(RID p_light) const { const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, AABB()); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index 68f439ddef..c36d1ef503 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -517,13 +517,6 @@ public: return light->color; } - _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) { - const Light *light = light_owner.get_or_null(p_light); - ERR_FAIL_COND_V(!light, 0); - - return light->cull_mask; - } - _FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) { const Light *light = light_owner.get_or_null(p_light); return light->distance_fade; @@ -575,6 +568,7 @@ public: virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override; virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override; virtual uint64_t light_get_version(RID p_light) const override; + virtual uint32_t light_get_cull_mask(RID p_light) const override; Dependency *light_get_dependency(RID p_light) const; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 5d845ce510..0ee9b28826 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1906,7 +1906,7 @@ void TextureStorage::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->cull_mask = p_layers; - decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); + decal->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_DECAL); } void TextureStorage::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { @@ -1952,6 +1952,13 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const { return AABB(-decal->size / 2, decal->size); } +uint32_t TextureStorage::decal_get_cull_mask(RID p_decal) const { + Decal *decal = decal_owner.get_or_null(p_decal); + ERR_FAIL_COND_V(!decal, 0); + + return decal->cull_mask; +} + Dependency *TextureStorage::decal_get_dependency(RID p_decal) { Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND_V(!decal, nullptr); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index aeab3bf3cb..c16f5274ad 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -638,6 +638,7 @@ public: } virtual AABB decal_get_aabb(RID p_decal) const override; + virtual uint32_t decal_get_cull_mask(RID p_decal) const override; Dependency *decal_get_dependency(RID p_decal); /* DECAL INSTANCE API */ diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index d696955800..7d2cd12959 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1787,6 +1787,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { pair.pair_allocator = &pair_allocator; pair.pair_pass = pair_pass; pair.pair_mask = 0; + pair.cull_mask = 0xFFFFFFFF; if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; @@ -1807,12 +1808,14 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI); pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } + pair.cull_mask = RSG::light_storage->light_get_cull_mask(p_instance->base); } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + pair.cull_mask = RSG::texture_storage->decal_get_cull_mask(p_instance->base); } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index c3eec83d44..b3874ee7ae 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -733,11 +733,12 @@ public: DynamicBVH *bvh2 = nullptr; //some may need to cull in two uint32_t pair_mask; uint64_t pair_pass; + uint32_t cull_mask = 0xFFFFFFFF; // Needed for decals and lights in the mobile and compatibility renderers. _FORCE_INLINE_ bool operator()(void *p_data) { Instance *p_instance = (Instance *)p_data; - if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { + if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type)) && (cull_mask & p_instance->layer_mask)) { //test is more coarse in indexer p_instance->pair_check = pair_pass; InstancePair *pair = pair_allocator->alloc(); diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 9f3f5dd8e4..5bd4297179 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -84,6 +84,7 @@ public: virtual RS::LightBakeMode light_get_bake_mode(RID p_light) = 0; virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0; virtual uint64_t light_get_version(RID p_light) const = 0; + virtual uint32_t light_get_cull_mask(RID p_light) const = 0; /* LIGHT INSTANCE API */ diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 3a9034ad0d..227d44aa27 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -118,6 +118,7 @@ public: virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; virtual AABB decal_get_aabb(RID p_decal) const = 0; + virtual uint32_t decal_get_cull_mask(RID p_decal) const = 0; virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0; |