diff options
20 files changed, 92 insertions, 60 deletions
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml index 0c85e8e670..70c3e5a26e 100644 --- a/doc/classes/AnimationNodeAnimation.xml +++ b/doc/classes/AnimationNodeAnimation.xml @@ -17,6 +17,7 @@ </member> <member name="loop_mode" type="int" setter="set_loop_mode" getter="get_loop_mode" enum="Animation.LoopMode"> If [member use_custom_timeline] is [code]true[/code], override the loop settings of the original [Animation] resource with the value. + [b]Note:[/b] If the [member Animation.loop_mode] isn't set to looping, the [method Animation.track_set_interpolation_loop_wrap] option will not be respected. If you cannot get the expected behavior, consider duplicating the [Animation] resource and changing the loop settings. </member> <member name="play_mode" type="int" setter="set_play_mode" getter="get_play_mode" enum="AnimationNodeAnimation.PlayMode" default="0"> Determines the playback direction of the animation. diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 7b4b7c289b..eecbb05540 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -5,7 +5,7 @@ </brief_description> <description> The [AudioStreamPlayer] node plays an audio stream non-positionally. It is ideal for user interfaces, menus, or background music. - To use this node, [member stream] needs to be set to a valid [AudioStream] resource. Playing more than one sound at the time is also supported, see [member max_polyphony]. + To use this node, [member stream] needs to be set to a valid [AudioStream] resource. Playing more than one sound at the same time is also supported, see [member max_polyphony]. If you need to play audio at a specific position, use [AudioStreamPlayer2D] or [AudioStreamPlayer3D] instead. </description> <tutorials> diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml index cb59afd880..b8b4fc7b08 100644 --- a/doc/classes/Dictionary.xml +++ b/doc/classes/Dictionary.xml @@ -355,7 +355,6 @@ # Prints { "fruit": "apple", "vegetable": "potato", "dressing": "vinegar" } print(extra.merged(base, true)) [/codeblock] - See also [method merge]. </description> </method> <method name="recursive_equal" qualifiers="const"> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index c3ea440aea..9c1a6f6af6 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -60,7 +60,7 @@ [gdscript] func _forward_3d_draw_over_viewport(overlay): # Draw a circle at cursor position. - overlay.draw_circle(overlay.get_local_mouse_position(), 64) + overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE) func _forward_3d_gui_input(camera, event): if event is InputEventMouseMotion: diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index b73ca4a1a6..d97a68cf2e 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -4,7 +4,7 @@ Helper class for creating and parsing JSON data. </brief_description> <description> - The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network. + The [JSON] class enables all data types to be converted to and from a JSON string. This is useful for serializing data, e.g. to save to a file or send over the network. [method stringify] is used to convert any data type into a JSON string. [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [member data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. [b]Example[/b] @@ -25,7 +25,7 @@ else: print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) [/codeblock] - Alternatively, you can parse string using the static [method parse_string] method, but it doesn't allow to handle errors. + Alternatively, you can parse strings using the static [method parse_string] method, but it doesn't handle errors. [codeblock] var data = JSON.parse_string(json_string) # Returns null if parsing failed. [/codeblock] @@ -53,7 +53,7 @@ <method name="get_parsed_text" qualifiers="const"> <return type="String" /> <description> - Return the text parsed by [method parse] as long as the function is instructed to keep it. + Return the text parsed by [method parse] (requires passing [code]keep_text[/code] to [method parse]). </description> </method> <method name="parse"> @@ -62,7 +62,7 @@ <param index="1" name="keep_text" type="bool" default="false" /> <description> Attempts to parse the [param json_text] provided. - Returns an [enum Error]. If the parse was successful, it returns [constant OK] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. + Returns an [enum Error]. If the parse was successful, it returns [constant OK] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] to identify the source of the failure. Non-static variant of [method parse_string], if you want custom error handling. The optional [param keep_text] argument instructs the parser to keep a copy of the original text. This text can be obtained later by using the [method get_parsed_text] function and is used when saving the resource (instead of generating new text from [member data]). </description> @@ -84,7 +84,7 @@ Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network. [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types. [b]Note:[/b] If [param full_precision] is [code]true[/code], when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding. - The [param indent] parameter controls if and how something is indented, the string used for this parameter will be used where there should be an indent in the output, even spaces like [code]" "[/code] will work. [code]\t[/code] and [code]\n[/code] can also be used for a tab indent, or to make a newline for each indent respectively. + The [param indent] parameter controls if and how something is indented; its contents will be used where there should be an indent in the output. Even spaces like [code]" "[/code] will work. [code]\t[/code] and [code]\n[/code] can also be used for a tab indent, or to make a newline for each indent respectively. [b]Example output:[/b] [codeblock] ## JSON.stringify(my_dictionary) diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 406aacc75c..529912171c 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -57,6 +57,7 @@ <param index="1" name="color" type="Color" /> <description> Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors. This allows for different color tinting per instance. + [b]Note:[/b] Each component is stored in 32 bits in the Forward+ and Mobile rendering methods, but is packed into 16 bits in the Compatibility rendering method. For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If you intend to set an absolute color instead of tinting, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]). </description> </method> @@ -66,6 +67,7 @@ <param index="1" name="custom_data" type="Color" /> <description> Sets custom data for a specific instance. [param custom_data] is a [Color] type only to contain 4 floating-point numbers. + [b]Note:[/b] Each number is stored in 32 bits in the Forward+ and Mobile rendering methods, but is packed into 16 bits in the Compatibility rendering method. For the custom data to be used, ensure that [member use_custom_data] is [code]true[/code]. This custom instance data has to be manually accessed in your custom shader using [code]INSTANCE_CUSTOM[/code]. </description> diff --git a/doc/classes/ResourceImporterTexture.xml b/doc/classes/ResourceImporterTexture.xml index 678aa2101c..0761702aa1 100644 --- a/doc/classes/ResourceImporterTexture.xml +++ b/doc/classes/ResourceImporterTexture.xml @@ -84,8 +84,8 @@ </member> <member name="process/premult_alpha" type="bool" setter="" getter="" default="false"> An alternative to fixing darkened borders with [member process/fix_alpha_border] is to use premultiplied alpha. By enabling this option, the texture will be converted to this format. A premultiplied alpha texture requires specific materials to be displayed correctly: - - In 2D, a [CanvasItemMaterial] will need to be created and configured to use the [constant CanvasItemMaterial.BLEND_MODE_PREMULT_ALPHA] blend mode on [CanvasItem]s that use this texture. - - In 3D, there is no support for premultiplied alpha blend mode yet, so this option is only suited for 2D. + - In 2D, a [CanvasItemMaterial] will need to be created and configured to use the [constant CanvasItemMaterial.BLEND_MODE_PREMULT_ALPHA] blend mode on [CanvasItem]s that use this texture. In custom [code]@canvas_item[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used. + - In 3D, a [BaseMaterial3D] will need to be created and configured to use the [constant BaseMaterial3D.BLEND_MODE_PREMULT_ALPHA] blend mode on materials that use this texture. In custom [code]spatial[/code] shaders, [code]render_mode blend_premul_alpha;[/code] should be used. </member> <member name="process/size_limit" type="int" setter="" getter="" default="0"> If set to a value greater than [code]0[/code], the size of the texture is limited on import to a value smaller than or equal to the value specified here. For non-square textures, the size limit affects the longer dimension, with the shorter dimension scaled to preserve aspect ratio. Resizing is performed using cubic interpolation. diff --git a/doc/classes/SkeletonModifier3D.xml b/doc/classes/SkeletonModifier3D.xml index 620eed9b70..cb51ab6f89 100644 --- a/doc/classes/SkeletonModifier3D.xml +++ b/doc/classes/SkeletonModifier3D.xml @@ -6,7 +6,7 @@ <description> [SkeletonModifier3D] retrieves a target [Skeleton3D] by having a [Skeleton3D] parent. If there is [AnimationMixer], modification always performs after playback process of the [AnimationMixer]. - This node should be used to implement custom IK solvers, constraints, or skeleton physics + This node should be used to implement custom IK solvers, constraints, or skeleton physics. </description> <tutorials> </tutorials> diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 122585e595..a33fc977c6 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -5057,6 +5057,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) { clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT); clear.color_attachment = i; + tex_info->pending_clear.remove_from_list(); } } else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { if (pass_info->attachments[i].stencil_load_op == ATTACHMENT_LOAD_OP_CLEAR) { diff --git a/editor/project_manager/project_dialog.cpp b/editor/project_manager/project_dialog.cpp index 52d86a1a95..ee2253b294 100644 --- a/editor/project_manager/project_dialog.cpp +++ b/editor/project_manager/project_dialog.cpp @@ -370,6 +370,8 @@ void ProjectDialog::_browse_project_path() { } else { fdialog_project->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); } + + hide(); fdialog_project->popup_file_dialog(); } @@ -389,7 +391,7 @@ void ProjectDialog::_browse_install_path() { } void ProjectDialog::_project_path_selected(const String &p_path) { - show_dialog(); + show_dialog(false); if (create_dir->is_pressed() && (mode == MODE_NEW || mode == MODE_INSTALL)) { // Replace parent directory, but keep target dir name. @@ -691,7 +693,7 @@ void ProjectDialog::ask_for_path_and_show() { _browse_project_path(); } -void ProjectDialog::show_dialog() { +void ProjectDialog::show_dialog(bool p_reset_name) { if (mode == MODE_RENAME) { // Name and path are set in `ProjectManager::_rename_project`. project_path->set_editable(false); @@ -711,8 +713,10 @@ void ProjectDialog::show_dialog() { callable_mp((Control *)project_name, &Control::grab_focus).call_deferred(); callable_mp(project_name, &LineEdit::select_all).call_deferred(); } else { - String proj = TTR("New Game Project"); - project_name->set_text(proj); + if (p_reset_name) { + String proj = TTR("New Game Project"); + project_name->set_text(proj); + } project_path->set_editable(true); String fav_dir = EDITOR_GET("filesystem/directories/default_project_path"); @@ -793,6 +797,7 @@ void ProjectDialog::_notification(int p_what) { fdialog_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM); fdialog_project->connect("dir_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); fdialog_project->connect("file_selected", callable_mp(this, &ProjectDialog::_project_path_selected)); + fdialog_project->connect("canceled", callable_mp(this, &ProjectDialog::show_dialog).bind(false), CONNECT_DEFERRED); callable_mp((Node *)this, &Node::add_sibling).call_deferred(fdialog_project, false); } break; } diff --git a/editor/project_manager/project_dialog.h b/editor/project_manager/project_dialog.h index 8517189e5a..0efe1991ab 100644 --- a/editor/project_manager/project_dialog.h +++ b/editor/project_manager/project_dialog.h @@ -139,7 +139,7 @@ public: void set_zip_title(const String &p_title); void ask_for_path_and_show(); - void show_dialog(); + void show_dialog(bool p_reset_name = true); ProjectDialog(); }; diff --git a/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml b/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml index ea914715a3..5353dc7376 100644 --- a/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml +++ b/modules/interactive_music/doc_classes/AudioStreamSynchronized.xml @@ -47,7 +47,7 @@ </members> <constants> <constant name="MAX_STREAMS" value="32"> - Maximum amount of streams that can be synchrohized. + Maximum amount of streams that can be synchronized. </constant> </constants> </class> diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 309cbe0d72..ed5810da3c 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -176,7 +176,7 @@ <param index="0" name="refresh_rate" type="float" /> <description> Informs the user the HMD refresh rate has changed. - [b]Node:[/b] Only emitted if XR runtime supports the refresh rate extension. + [b]Note:[/b] Only emitted if XR runtime supports the refresh rate extension. </description> </signal> <signal name="session_begun"> diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml index 87994ef22b..1d4a944dc4 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -151,16 +151,16 @@ Indicates whether your app uses advertising data for tracking. </member> <member name="privacy/collected_data/audio_data/collected" type="bool" setter="" getter=""> - Indicates whether your app collects audio data data. + Indicates whether your app collects audio data. </member> <member name="privacy/collected_data/audio_data/collection_purposes" type="int" setter="" getter=""> The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. </member> <member name="privacy/collected_data/audio_data/linked_to_user" type="bool" setter="" getter=""> - Indicates whether your app links audio data data to the user's identity. + Indicates whether your app links audio data to the user's identity. </member> <member name="privacy/collected_data/audio_data/used_for_tracking" type="bool" setter="" getter=""> - Indicates whether your app uses audio data data for tracking. + Indicates whether your app uses audio data for tracking. </member> <member name="privacy/collected_data/browsing_history/collected" type="bool" setter="" getter=""> Indicates whether your app collects browsing history. diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 4a52e26373..8a2f83be2d 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -4970,6 +4970,23 @@ void DisplayServerX11::process_events() { pos = Point2i(windows[focused_window_id].size.width / 2, windows[focused_window_id].size.height / 2); } + BitField<MouseButtonMask> last_button_state = 0; + if (event.xmotion.state & Button1Mask) { + last_button_state.set_flag(MouseButtonMask::LEFT); + } + if (event.xmotion.state & Button2Mask) { + last_button_state.set_flag(MouseButtonMask::MIDDLE); + } + if (event.xmotion.state & Button3Mask) { + last_button_state.set_flag(MouseButtonMask::RIGHT); + } + if (event.xmotion.state & Button4Mask) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1); + } + if (event.xmotion.state & Button5Mask) { + last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2); + } + Ref<InputEventMouseMotion> mm; mm.instantiate(); @@ -4977,13 +4994,13 @@ void DisplayServerX11::process_events() { if (xi.pressure_supported) { mm->set_pressure(xi.pressure); } else { - mm->set_pressure(bool(mouse_get_button_state().has_flag(MouseButtonMask::LEFT)) ? 1.0f : 0.0f); + mm->set_pressure(bool(last_button_state.has_flag(MouseButtonMask::LEFT)) ? 1.0f : 0.0f); } mm->set_tilt(xi.tilt); mm->set_pen_inverted(xi.pen_inverted); _get_key_modifier_state(event.xmotion.state, mm); - mm->set_button_mask(mouse_get_button_state()); + mm->set_button_mask(last_button_state); mm->set_position(pos); mm->set_global_position(pos); mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity()); diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index 92ade4b77a..34ad52bbf6 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -224,16 +224,16 @@ Indicates whether your app uses advertising data for tracking. </member> <member name="privacy/collected_data/audio_data/collected" type="bool" setter="" getter=""> - Indicates whether your app collects audio data data. + Indicates whether your app collects audio data. </member> <member name="privacy/collected_data/audio_data/collection_purposes" type="int" setter="" getter=""> The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. </member> <member name="privacy/collected_data/audio_data/linked_to_user" type="bool" setter="" getter=""> - Indicates whether your app links audio data data to the user's identity. + Indicates whether your app links audio data to the user's identity. </member> <member name="privacy/collected_data/audio_data/used_for_tracking" type="bool" setter="" getter=""> - Indicates whether your app uses audio data data for tracking. + Indicates whether your app uses audio data for tracking. </member> <member name="privacy/collected_data/browsing_history/collected" type="bool" setter="" getter=""> Indicates whether your app collects browsing history. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 36f3f632d5..0a7f3157f3 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1333,13 +1333,15 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod wd.is_popup = true; } if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) { - DWM_BLURBEHIND bb; - ZeroMemory(&bb, sizeof(bb)); - HRGN hRgn = CreateRectRgn(0, 0, -1, -1); - bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; - bb.hRgnBlur = hRgn; - bb.fEnable = TRUE; - DwmEnableBlurBehindWindow(wd.hWnd, &bb); + if (OS::get_singleton()->is_layered_allowed()) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + } wd.layered_window = true; } @@ -2119,28 +2121,29 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W } break; case WINDOW_FLAG_TRANSPARENT: { if (p_enabled) { - //enable per-pixel alpha - - DWM_BLURBEHIND bb; - ZeroMemory(&bb, sizeof(bb)); - HRGN hRgn = CreateRectRgn(0, 0, -1, -1); - bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; - bb.hRgnBlur = hRgn; - bb.fEnable = TRUE; - DwmEnableBlurBehindWindow(wd.hWnd, &bb); - + // Enable per-pixel alpha. + if (OS::get_singleton()->is_layered_allowed()) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + } wd.layered_window = true; } else { - //disable per-pixel alpha + // Disable per-pixel alpha. wd.layered_window = false; - - DWM_BLURBEHIND bb; - ZeroMemory(&bb, sizeof(bb)); - HRGN hRgn = CreateRectRgn(0, 0, -1, -1); - bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; - bb.hRgnBlur = hRgn; - bb.fEnable = FALSE; - DwmEnableBlurBehindWindow(wd.hWnd, &bb); + if (OS::get_singleton()->is_layered_allowed()) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = FALSE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + } } } break; case WINDOW_FLAG_NO_FOCUS: { diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index a27da73b89..e4baae1afb 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -237,6 +237,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe } // Finished. if (Animation::is_less_approx(prev_playback_time, anim_size) && Animation::is_greater_or_equal_approx(cur_playback_time, anim_size)) { + cur_playback_time = anim_size; process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation); } } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 19229f405a..24b777e2eb 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -204,19 +204,20 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f } double prev_pos = cd.pos; // The animation may be changed during process, so it is safer that the state is changed before process. - cd.pos = next_pos; // End detection. if (p_is_current) { if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) { if (!backwards && Animation::is_less_or_equal_approx(prev_pos, len) && Math::is_equal_approx(next_pos, len)) { // Playback finished. + next_pos = len; // Snap to the edge. end_reached = true; end_notify = Animation::is_less_approx(prev_pos, len); // Notify only if not already at the end. p_blend = 1.0; } if (backwards && Animation::is_greater_or_equal_approx(prev_pos, 0) && Math::is_equal_approx(next_pos, 0)) { // Playback finished. + next_pos = 0; // Snap to the edge. end_reached = true; end_notify = Animation::is_greater_approx(prev_pos, 0); // Notify only if not already at the beginning. p_blend = 1.0; @@ -224,6 +225,8 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f } } + cd.pos = next_pos; + PlaybackInfo pi; if (p_started) { pi.time = prev_pos; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 9b762f7b3c..60b3e371a0 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -912,7 +912,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { // This prevents interactions with a port hotzone that is behind another node. Rect2 graph_node_rect = Rect2(graph_node->get_position(), graph_node->get_size() * zoom); - if (graph_node_rect.has_point(click_pos * zoom)) { + if (graph_node_rect.has_point(p_point)) { break; } } @@ -1044,12 +1044,6 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { return; } } - - // This prevents interactions with a port hotzone that is behind another node. - Rect2 graph_node_rect = Rect2(graph_node->get_position(), graph_node->get_size() * zoom); - if (graph_node_rect.has_point(click_pos * zoom)) { - break; - } } } @@ -1121,6 +1115,12 @@ void GraphEdit::_top_connection_layer_input(const Ref<InputEvent> &p_ev) { } connecting_target_valid = false; } + + // This prevents interactions with a port hotzone that is behind another node. + Rect2 graph_node_rect = Rect2(graph_node->get_position(), graph_node->get_size() * zoom); + if (graph_node_rect.has_point(mm->get_position())) { + break; + } } } } |