diff options
89 files changed, 577 insertions, 160 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 0eacffeb88..4586dc6d14 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1393,7 +1393,7 @@ void _OS::_bind_methods() { ADD_PROPERTY_DEFAULT("current_screen", 0); ADD_PROPERTY_DEFAULT("exit_code", 0); ADD_PROPERTY_DEFAULT("vsync_enabled", true); - ADD_PROPERTY_DEFAULT("vsync_via_compositor", false); + ADD_PROPERTY_DEFAULT("vsync_via_compositor", true); ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false); ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); ADD_PROPERTY_DEFAULT("keep_screen_on", true); diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 8c8f65c3a0..e847a9cf0c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -803,6 +803,18 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::OBJECT: { +#ifdef DEBUG_ENABLED + // Test for potential wrong values sent by the debugger when it breaks. + Object *obj = p_variant; + if (!obj || !ObjectDB::instance_validate(obj)) { + // Object is invalid, send a NULL instead. + if (buf) { + encode_uint32(Variant::NIL, buf); + } + r_len += 4; + return OK; + } +#endif // DEBUG_ENABLED if (!p_full_objects) { flags |= ENCODE_FLAG_OBJECT_AS_ID; } diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 89fc18476b..0eadf27c4d 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -21,6 +21,7 @@ <return type="AudioStreamPlayback"> </return> <description> + Returns the [AudioStreamPlayback] object associated with this [AudioStreamPlayer]. </description> </method> <method name="play"> @@ -69,6 +70,7 @@ The [AudioStream] object to be played. </member> <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false"> + If [code]true[/code], the playback is paused. You can resume it by setting [code]stream_paused[/code] to [code]false[/code]. </member> <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db" default="0.0"> Volume of sound, in dB. diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index 4734aff770..ec3b7872b7 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -21,6 +21,7 @@ <return type="AudioStreamPlayback"> </return> <description> + Returns the [AudioStreamPlayback] object associated with this [AudioStreamPlayer2D]. </description> </method> <method name="play"> @@ -75,6 +76,7 @@ The [AudioStream] object to be played. </member> <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false"> + If [code]true[/code], the playback is paused. You can resume it by setting [code]stream_paused[/code] to [code]false[/code]. </member> <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db" default="0.0"> Base volume without dampening. diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index a73f96d082..5e12e06650 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -21,6 +21,7 @@ <return type="AudioStreamPlayback"> </return> <description> + Returns the [AudioStreamPlayback] object associated with this [AudioStreamPlayer3D]. </description> </method> <method name="play"> @@ -99,6 +100,7 @@ The [AudioStream] object to be played. </member> <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false"> + If [code]true[/code], the playback is paused. You can resume it by setting [code]stream_paused[/code] to [code]false[/code]. </member> <member name="unit_db" type="float" setter="set_unit_db" getter="get_unit_db" default="0.0"> Base sound level unaffected by dampening, in dB. diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 187e13d7bd..04e203793b 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -85,6 +85,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns a global singleton with given [code]name[/code]. Often used for plugins, e.g. GodotPayments. </description> </method> <method name="get_version_info" qualifiers="const"> @@ -116,6 +117,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if a singleton with given [code]name[/code] exists in global scope. </description> </method> <method name="is_in_physics_frame" qualifiers="const"> @@ -134,6 +136,7 @@ The number of fixed iterations per second (for fixed process and physics). </member> <member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5"> + Controls how much physic ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows to smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. </member> <member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0"> The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit. diff --git a/doc/classes/HScrollBar.xml b/doc/classes/HScrollBar.xml index 14ace8bc76..90f14dd344 100644 --- a/doc/classes/HScrollBar.xml +++ b/doc/classes/HScrollBar.xml @@ -4,7 +4,7 @@ Horizontal scroll bar. </brief_description> <description> - Horizontal scroll bar. See [ScrollBar]. This one goes from left (min) to right (max). + Horizontal version of [ScrollBar], which goes from left (min) to right (max). </description> <tutorials> </tutorials> @@ -14,22 +14,31 @@ </constants> <theme_items> <theme_item name="decrement" type="Texture"> + Icon used as a button to scroll the [ScrollBar] left. Supports custom step using the [member ScrollBar.custom_step] property. </theme_item> <theme_item name="decrement_highlight" type="Texture"> + Displayed when the mouse cursor hovers over the decrement button. </theme_item> <theme_item name="grabber" type="StyleBox"> + Used as texture for the grabber, the draggable element representing current scroll. </theme_item> <theme_item name="grabber_highlight" type="StyleBox"> + Used when the mouse hovers over the grabber. </theme_item> <theme_item name="grabber_pressed" type="StyleBox"> + Used when the grabber is being dragged. </theme_item> <theme_item name="increment" type="Texture"> + Icon used as a button to scroll the [ScrollBar] right. Supports custom step using the [member ScrollBar.custom_step] property. </theme_item> <theme_item name="increment_highlight" type="Texture"> + Displayed when the mouse cursor hovers over the increment button. </theme_item> <theme_item name="scroll" type="StyleBox"> + Used as background of this [ScrollBar]. </theme_item> <theme_item name="scroll_focus" type="StyleBox"> + Used as background when the [ScrollBar] has the GUI focus. </theme_item> </theme_items> </class> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 78459d2839..a360010b7e 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -96,7 +96,7 @@ The cursor's position inside the [LineEdit]. When set, the text may scroll to accommodate it. </member> <member name="clear_button_enabled" type="bool" setter="set_clear_button_enabled" getter="is_clear_button_enabled" default="false"> - If [code]true[/code], the [LineEdit] will show a clear button if [code]text[/code] is not empty. + If [code]true[/code], the [LineEdit] will show a clear button if [code]text[/code] is not empty, which can be used to clear the text quickly. </member> <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled" default="true"> If [code]true[/code], the context menu will appear when right-clicked. @@ -128,8 +128,10 @@ The character to use to mask secret input (defaults to "*"). Only a single character can be used as the secret character. </member> <member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true"> + If [code]false[/code], it's impossible to select the text using mouse nor keyboard. </member> <member name="shortcut_keys_enabled" type="bool" setter="set_shortcut_keys_enabled" getter="is_shortcut_keys_enabled" default="true"> + If [code]false[/code], using shortcuts will be disabled. </member> <member name="text" type="String" setter="set_text" getter="get_text" default=""""> String value of the [LineEdit]. @@ -192,30 +194,43 @@ </constants> <theme_items> <theme_item name="clear" type="Texture"> + Texture for the clear button. See [member clear_button_enabled]. </theme_item> <theme_item name="clear_button_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + Color used as default tint for the clear button. </theme_item> <theme_item name="clear_button_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + Color used for the clear button when it's pressed. </theme_item> <theme_item name="cursor_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + Color of the [LineEdit]'s visual cursor (caret). </theme_item> <theme_item name="focus" type="StyleBox"> + Background used when [LineEdit] has GUI focus. </theme_item> <theme_item name="font" type="Font"> + Font used for the text. </theme_item> <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + Default font color. </theme_item> <theme_item name="font_color_selected" type="Color" default="Color( 0, 0, 0, 1 )"> + Font color for selected text (inside the selection rectangle). </theme_item> <theme_item name="font_color_uneditable" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )"> + Font color when editing is disabled. </theme_item> <theme_item name="minimum_spaces" type="int" default="12"> + Minimum horizontal space for the text (not counting the clear button and content margins). </theme_item> <theme_item name="normal" type="StyleBox"> + Default background for the [LineEdit]. </theme_item> <theme_item name="read_only" type="StyleBox"> + Background used when [LineEdit] is in read-only mode ([member editable] is set to [code]false[/code]). </theme_item> <theme_item name="selection_color" type="Color" default="Color( 0.49, 0.49, 0.49, 1 )"> + Color of the selection rectangle. </theme_item> </theme_items> </class> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 71d0c1a6fe..2236c42094 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -613,9 +613,9 @@ <return type="bool"> </return> <description> - Returns [code]true[/code] if the build is a debug build. - Returns [code]true[/code] when running in the editor. - Returns [code]false[/code] if the build is a release build. + Returns [code]true[/code] if the Godot binary used to run the project is a [i]debug[/i] export template, or when running in the editor. + Returns [code]false[/code] if the Godot binary used to run the project is a [i]release[/i] export template. + To check whether the Godot binary used to run the project is an export template (debug or release), use [code]OS.has_feature("standalone")[/code] instead. </description> </method> <method name="is_ok_left_and_cancel_right" qualifiers="const"> @@ -937,8 +937,9 @@ <member name="vsync_enabled" type="bool" setter="set_use_vsync" getter="is_vsync_enabled" default="true"> If [code]true[/code], vertical synchronization (Vsync) is enabled. </member> - <member name="vsync_via_compositor" type="bool" setter="set_vsync_via_compositor" getter="is_vsync_via_compositor_enabled" default="false"> + <member name="vsync_via_compositor" type="bool" setter="set_vsync_via_compositor" getter="is_vsync_via_compositor_enabled" default="true"> If [code]true[/code] and [code]vsync_enabled[/code] is true, the operating system's window compositor will be used for vsync when the compositor is enabled and the game is in windowed mode. + [b]Note:[/b] This property is only implemented on Windows. </member> <member name="window_borderless" type="bool" setter="set_borderless_window" getter="get_borderless_window" default="false"> If [code]true[/code], removes the window frame. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 126f11a4ed..1bc43dc964 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -437,7 +437,7 @@ <member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables vertical synchronization. This eliminates tearing that may appear in moving scenes, at the cost of higher input latency and stuttering at lower framerates. If [code]false[/code], vertical synchronization will be disabled, however, many platforms will enforce it regardless (such as mobile platforms and HTML5). </member> - <member name="display/window/vsync/vsync_via_compositor" type="bool" setter="" getter="" default="false"> + <member name="display/window/vsync/vsync_via_compositor" type="bool" setter="" getter="" default="true"> If [code]Use Vsync[/code] is enabled and this setting is [code]true[/code], enables vertical synchronization via the operating system's window compositor when in windowed mode and the compositor is enabled. This will prevent stutter in certain situations. (Windows only.) </member> <member name="editor/script_templates_search_path" type="String" setter="" getter="" default=""res://script_templates""> diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml index 3d0fa9a0d5..2991d76bec 100644 --- a/doc/classes/ScriptCreateDialog.xml +++ b/doc/classes/ScriptCreateDialog.xml @@ -24,6 +24,8 @@ </argument> <argument index="2" name="built_in_enabled" type="bool" default="true"> </argument> + <argument index="3" name="load_enabled" type="bool" default="true"> + </argument> <description> Prefills required fields to configure the ScriptCreateDialog for use. </description> diff --git a/doc/classes/ScrollBar.xml b/doc/classes/ScrollBar.xml index ea30b9d48c..e4ace8e8ae 100644 --- a/doc/classes/ScrollBar.xml +++ b/doc/classes/ScrollBar.xml @@ -12,6 +12,7 @@ </methods> <members> <member name="custom_step" type="float" setter="set_custom_step" getter="get_custom_step" default="-1.0"> + Overrides the step used when clicking increment and decrement buttons or when using arrow keys when the [ScrollBar] is focused. </member> <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" override="true" default="0" /> <member name="step" type="float" setter="set_step" getter="get_step" override="true" default="0.0" /> diff --git a/doc/classes/VScrollBar.xml b/doc/classes/VScrollBar.xml index 6240178b82..add695ef2c 100644 --- a/doc/classes/VScrollBar.xml +++ b/doc/classes/VScrollBar.xml @@ -1,9 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VScrollBar" inherits="ScrollBar" category="Core" version="3.2"> <brief_description> - Vertical version of [ScrollBar], which goes from top (min) to bottom (max). + Vertical scroll bar. </brief_description> <description> + Vertical version of [ScrollBar], which goes from top (min) to bottom (max). </description> <tutorials> </tutorials> @@ -17,22 +18,31 @@ </constants> <theme_items> <theme_item name="decrement" type="Texture"> + Icon used as a button to scroll the [ScrollBar] up. Supports custom step using the [member ScrollBar.custom_step] property. </theme_item> <theme_item name="decrement_highlight" type="Texture"> + Displayed when the mouse cursor hovers over the decrement button. </theme_item> <theme_item name="grabber" type="StyleBox"> + Used as texture for the grabber, the draggable element representing current scroll. </theme_item> <theme_item name="grabber_highlight" type="StyleBox"> + Used when the mouse hovers over the grabber. </theme_item> <theme_item name="grabber_pressed" type="StyleBox"> + Used when the grabber is being dragged. </theme_item> <theme_item name="increment" type="Texture"> + Icon used as a button to scroll the [ScrollBar] down. Supports custom step using the [member ScrollBar.custom_step] property. </theme_item> <theme_item name="increment_highlight" type="Texture"> + Displayed when the mouse cursor hovers over the increment button. </theme_item> <theme_item name="scroll" type="StyleBox"> + Used as background of this [ScrollBar]. </theme_item> <theme_item name="scroll_focus" type="StyleBox"> + Used as background when the [ScrollBar] has the GUI focus. </theme_item> </theme_items> </class> diff --git a/doc/classes/VisibilityEnabler.xml b/doc/classes/VisibilityEnabler.xml index e3c7d05fce..56fa7b77a9 100644 --- a/doc/classes/VisibilityEnabler.xml +++ b/doc/classes/VisibilityEnabler.xml @@ -15,6 +15,7 @@ <argument index="0" name="enabler" type="int" enum="VisibilityEnabler.Enabler"> </argument> <description> + Returns whether the enabler identified by given [enum Enabler] constant is active. </description> </method> <method name="set_enabler"> @@ -25,6 +26,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Sets active state of the enabler identified by given [enum Enabler] constant. </description> </method> </methods> diff --git a/doc/classes/VisibilityEnabler2D.xml b/doc/classes/VisibilityEnabler2D.xml index 96f6a42cdf..547793c385 100644 --- a/doc/classes/VisibilityEnabler2D.xml +++ b/doc/classes/VisibilityEnabler2D.xml @@ -15,6 +15,7 @@ <argument index="0" name="enabler" type="int" enum="VisibilityEnabler2D.Enabler"> </argument> <description> + Returns whether the enabler identified by given [enum Enabler] constant is active. </description> </method> <method name="set_enabler"> @@ -25,6 +26,7 @@ <argument index="1" name="enabled" type="bool"> </argument> <description> + Sets active state of the enabler identified by given [enum Enabler] constant. </description> </method> </methods> @@ -65,6 +67,7 @@ This enabler will stop the parent's _physics_process function. </constant> <constant name="ENABLER_PAUSE_ANIMATED_SPRITES" value="5" enum="Enabler"> + This enabler will stop [AnimatedSprite] nodes animations. </constant> <constant name="ENABLER_MAX" value="6" enum="Enabler"> Represents the size of the [enum Enabler] enum. diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index cd19ceb868..f6d5312fc7 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3790,8 +3790,9 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari value = p_value; //all good } else { String tpath = animation->track_get_path(i); - if (NodePath(tpath.get_basename()) == np) { - String subindex = tpath.get_extension(); + int index = tpath.find_last(":"); + if (NodePath(tpath.substr(0, index + 1)) == np) { + String subindex = tpath.substr(index + 1, tpath.length() - index); value = p_value.get(subindex); } else { continue; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index f74cadf67e..93e9cc58fb 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1761,7 +1761,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false); + make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false, false); make_script_dialog->popup_centered(); } break; diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index c19bee321a..83259afb35 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -215,7 +215,7 @@ void GroupDialog::_group_renamed() { return; } - String name = renamed_group->get_text(0).strip_edges(); + const String name = renamed_group->get_text(0).strip_edges(); for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) { if (E != renamed_group && E->get_text(0) == name) { renamed_group->set_text(0, selected_group); @@ -232,6 +232,8 @@ void GroupDialog::_group_renamed() { return; } + renamed_group->set_text(0, name); // Spaces trimmed. + undo_redo->create_action(TTR("Rename Group")); List<Node *> nodes; @@ -254,8 +256,8 @@ void GroupDialog::_group_renamed() { undo_redo->add_undo_method(this, "_delete_group_item", selected_group); } - undo_redo->add_do_method(this, "_rename_group_item", selected_group, renamed_group->get_text(0)); - undo_redo->add_undo_method(this, "_rename_group_item", renamed_group->get_text(0), selected_group); + undo_redo->add_do_method(this, "_rename_group_item", selected_group, name); + undo_redo->add_undo_method(this, "_rename_group_item", name, selected_group); undo_redo->add_do_method(this, "_group_selected"); undo_redo->add_undo_method(this, "_group_selected"); undo_redo->add_do_method(this, "emit_signal", "group_edited"); @@ -550,8 +552,8 @@ void GroupsEditor::_add_group(const String &p_group) { if (!node) return; - String name = group_name->get_text(); - if (name.strip_edges() == "") + const String name = group_name->get_text().strip_edges(); + if (name.empty()) return; if (node->is_in_group(name)) diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d0bd57d658..f13abd47a9 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1004,7 +1004,7 @@ void ScriptEditor::_menu_option(int p_option) { ScriptEditorBase *current = _get_current_editor(); switch (p_option) { case FILE_NEW: { - script_create_dialog->config("Node", "new_script", false); + script_create_dialog->config("Node", "new_script", false, false); script_create_dialog->popup_centered(); } break; case FILE_NEW_TEXTFILE: { diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index b64ff6119c..b24d5add9f 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1303,12 +1303,14 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2; Size2 workspace_minsize = workspace->get_custom_minimum_size(); - if (tile_workspace_size.x > workspace_minsize.x && tile_workspace_size.y > workspace_minsize.y) { - undo_redo->add_do_method(workspace, "set_custom_minimum_size", tile_workspace_size); + // If the new region is bigger, just directly change the workspace size to avoid checking all other tiles. + if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) { + Size2 max_workspace_size = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y)); + undo_redo->add_do_method(workspace, "set_custom_minimum_size", max_workspace_size); undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", tile_workspace_size); + undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", max_workspace_size); undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize); - undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", tile_workspace_size); + undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", max_workspace_size); undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize); } else if (workspace_minsize.x > get_current_texture()->get_size().x + WORKSPACE_MARGIN.x * 2 || workspace_minsize.y > get_current_texture()->get_size().y + WORKSPACE_MARGIN.y * 2) { undo_redo->add_do_method(this, "update_workspace_minsize"); @@ -1803,8 +1805,6 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D); edited_collision_shape = _convex; _set_edited_shape_points(_get_collision_shape_points(concave)); - } else { - // Shouldn't happen } for (int i = 0; i < sd.size(); i++) { if (sd[i].get("shape") == previous_shape) { @@ -3267,12 +3267,16 @@ void TileSetEditor::update_workspace_minsize() { List<int> *tiles = new List<int>(); tileset->get_tile_list(tiles); for (List<int>::Element *E = tiles->front(); E; E = E->next()) { - if (tileset->tile_get_texture(E->get())->get_rid() == current_texture_rid) { - Rect2i region = tileset->tile_get_region(E->get()); - if (region.position.x + region.size.x > workspace_min_size.x) - workspace_min_size.x = region.position.x + region.size.x; - if (region.position.y + region.size.y > workspace_min_size.y) - workspace_min_size.y = region.position.y + region.size.y; + if (tileset->tile_get_texture(E->get())->get_rid() != current_texture_rid) { + continue; + } + + Rect2i region = tileset->tile_get_region(E->get()); + if (region.position.x + region.size.x > workspace_min_size.x) { + workspace_min_size.x = region.position.x + region.size.x; + } + if (region.position.y + region.size.y > workspace_min_size.y) { + workspace_min_size.y = region.position.y + region.size.y; } } delete tiles; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 25bc13033c..35d5fe5f70 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -99,7 +99,7 @@ bool ScriptCreateDialog::_can_be_built_in() { return (supports_built_in && built_in_enabled); } -void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled) { +void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled) { class_name->set_text(""); class_name->deselect(); @@ -117,6 +117,7 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_ file_path->deselect(); built_in_enabled = p_built_in_enabled; + load_enabled = p_load_enabled; _lang_changed(current_language); _class_name_changed(""); @@ -623,12 +624,12 @@ void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { void ScriptCreateDialog::_update_dialog() { + /* "Add Script Dialog" GUI logic and script checks. */ + bool script_ok = true; - /* "Add Script Dialog" gui logic and script checks */ + // Is script path/name valid (order from top to bottom)? - // Is Script Valid (order from top to bottom) - get_ok()->set_disabled(true); if (!is_built_in && !is_path_valid) { _msg_script_valid(false, TTR("Invalid path.")); script_ok = false; @@ -641,12 +642,12 @@ void ScriptCreateDialog::_update_dialog() { _msg_script_valid(false, TTR("Invalid inherited parent name or path.")); script_ok = false; } + if (script_ok) { _msg_script_valid(true, TTR("Script is valid.")); - get_ok()->set_disabled(false); } - /* Does script have named classes */ + // Does script have named classes? if (has_named_classes) { if (is_new_script_created) { @@ -663,7 +664,7 @@ void ScriptCreateDialog::_update_dialog() { class_name->set_text(""); } - /* Is script Built-in */ + // Is script Built-in? if (is_built_in) { file_path->set_editable(false); @@ -683,7 +684,7 @@ void ScriptCreateDialog::_update_dialog() { } internal->set_disabled(!_can_be_built_in()); - /* Is Script created or loaded from existing file */ + // Is Script created or loaded from existing file? if (is_built_in) { get_ok()->set_text(TTR("Create")); @@ -692,7 +693,8 @@ void ScriptCreateDialog::_update_dialog() { parent_browse_button->set_disabled(!can_inherit_from_file); _msg_path_valid(true, TTR("Built-in script (into scene file).")); } else if (is_new_script_created) { - // New Script Created + // New script created. + get_ok()->set_text(TTR("Create")); parent_name->set_editable(true); parent_search_button->set_disabled(false); @@ -700,8 +702,9 @@ void ScriptCreateDialog::_update_dialog() { if (is_path_valid) { _msg_path_valid(true, TTR("Will create a new script file.")); } - } else { - // Script Loaded + } else if (load_enabled) { + // Script loaded. + get_ok()->set_text(TTR("Load")); parent_name->set_editable(false); parent_search_button->set_disabled(true); @@ -709,7 +712,17 @@ void ScriptCreateDialog::_update_dialog() { if (is_path_valid) { _msg_path_valid(true, TTR("Will load an existing script file.")); } + } else { + get_ok()->set_text(TTR("Create")); + parent_name->set_editable(true); + parent_search_button->set_disabled(false); + parent_browse_button->set_disabled(!can_inherit_from_file); + _msg_path_valid(false, TTR("Script file already exists.")); + + script_ok = false; } + + get_ok()->set_disabled(!script_ok); } void ScriptCreateDialog::_bind_methods() { @@ -727,7 +740,7 @@ void ScriptCreateDialog::_bind_methods() { ClassDB::bind_method("_create", &ScriptCreateDialog::_create); ClassDB::bind_method("_browse_class_in_tree", &ScriptCreateDialog::_browse_class_in_tree); - ClassDB::bind_method(D_METHOD("config", "inherits", "path", "built_in_enabled"), &ScriptCreateDialog::config, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("config", "inherits", "path", "built_in_enabled", "load_enabled"), &ScriptCreateDialog::config, DEFVAL(true), DEFVAL(true)); ADD_SIGNAL(MethodInfo("script_created", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script"))); } @@ -884,8 +897,9 @@ ScriptCreateDialog::ScriptCreateDialog() { has_named_classes = false; supports_built_in = false; can_inherit_from_file = false; - built_in_enabled = true; is_built_in = false; + built_in_enabled = true; + load_enabled = true; is_new_script_created = true; } diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 91d6315a78..00f642fcf7 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -74,6 +74,7 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_class_name_valid; bool is_built_in; bool built_in_enabled; + bool load_enabled; int current_language; int default_language; bool re_check_path; @@ -126,7 +127,7 @@ protected: static void _bind_methods(); public: - void config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled = true); + void config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled = true, bool p_load_enabled = true); void set_inheritance_base_type(const String &p_base); ScriptCreateDialog(); }; diff --git a/main/main.cpp b/main/main.cpp index c29a5a0aa6..5cfab3dc4a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -815,6 +815,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph I = N; } +#ifdef TOOLS_ENABLED + if (editor && project_manager) { + OS::get_singleton()->print("Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting.\n"); + goto error; + } +#endif + // Network file system needs to be configured before globals, since globals are based on the // 'project.godot' file which will only be available through the network if this is enabled FileAccessNetwork::configure(); @@ -930,7 +937,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } - if (!project_manager) { + if (!project_manager && !editor) { // Determine if the project manager should be requested project_manager = main_args.size() == 0 && !found_project; } @@ -1028,7 +1035,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // window compositor ("--enable-vsync-via-compositor" or // "--disable-vsync-via-compositor") was present then it overrides the // project setting. - video_mode.vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", false); + video_mode.vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", true); } OS::get_singleton()->_vsync_via_compositor = video_mode.vsync_via_compositor; @@ -1395,6 +1402,7 @@ bool Main::start() { bool hasicon = false; String doc_tool; List<String> removal_docs; + String positional_arg; String game_path; String script; String test; @@ -1422,8 +1430,18 @@ bool Main::start() { } else if (args[i] == "-p" || args[i] == "--project-manager") { project_manager = true; #endif - } else if (args[i].length() && args[i][0] != '-' && game_path == "") { - game_path = args[i]; + } else if (args[i].length() && args[i][0] != '-' && positional_arg == "") { + positional_arg = args[i]; + + if (args[i].ends_with(".scn") || args[i].ends_with(".tscn") || args[i].ends_with(".escn")) { + // Only consider the positional argument to be a scene path if it ends with + // a file extension associated with Godot scenes. This makes it possible + // for projects to parse command-line arguments for custom CLI arguments + // or other file extensions without trouble. This can be used to implement + // "drag-and-drop onto executable" logic, which can prove helpful + // for non-game applications. + game_path = args[i]; + } } //parameters that have an argument to the right else if (i < (args.size() - 1)) { @@ -1518,7 +1536,7 @@ bool Main::start() { } if (_export_preset != "") { - if (game_path == "") { + if (positional_arg == "") { String err = "Command line includes export parameter option, but no destination path was given.\n"; err += "Please specify the binary's file path to export to. Aborting export."; ERR_PRINT(err); @@ -1709,7 +1727,7 @@ bool Main::start() { sml->get_root()->add_child(editor_node); if (_export_preset != "") { - editor_node->export_preset(_export_preset, game_path, export_debug, export_pack_only); + editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only); game_path = ""; // Do not load anything. } } diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp index 6ef1f2f4b9..06334556d9 100644 --- a/modules/gdnative/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative/gdnative.cpp @@ -170,6 +170,10 @@ bool GDAPI godot_is_instance_valid(const godot_object *p_object) { return ObjectDB::instance_validate((Object *)p_object); } +godot_object GDAPI *godot_instance_from_id(godot_int p_instance_id) { + return (godot_object *)ObjectDB::get_instance((ObjectID)p_instance_id); +} + void *godot_get_class_tag(const godot_string_name *p_class) { StringName class_name = *(StringName *)p_class; ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name); diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 7e2ca49f8d..8ccb8d2286 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -155,6 +155,13 @@ ["const godot_object *", "p_object"], ["void *", "p_class_tag"] ] + }, + { + "name": "godot_instance_from_id", + "return_type": "godot_object *", + "arguments": [ + ["godot_int", "p_instance_id"] + ] } ] }, diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 2fe59b8a73..e19a2ec149 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -290,6 +290,9 @@ bool GDAPI godot_is_instance_valid(const godot_object *p_object); void GDAPI *godot_get_class_tag(const godot_string_name *p_class); godot_object GDAPI *godot_object_cast_to(const godot_object *p_object, void *p_class_tag); +// equivalent of GDScript's instance_from_id +godot_object GDAPI *godot_instance_from_id(godot_int p_instance_id); + #ifdef __cplusplus } #endif diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 11e015b473..7b3175d9cd 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -90,11 +90,11 @@ bool GDScriptCompiler::_create_unary_operator(CodeGen &codegen, const GDScriptPa return true; } -bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer) { +bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer, int p_index_addr) { ERR_FAIL_COND_V(on->arguments.size() != 2, false); - int src_address_a = _parse_expression(codegen, on->arguments[0], p_stack_level, false, p_initializer); + int src_address_a = _parse_expression(codegen, on->arguments[0], p_stack_level, false, p_initializer, p_index_addr); if (src_address_a < 0) return false; if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) @@ -171,7 +171,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D return result; } -int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level) { +int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level, int p_index_addr) { Variant::Operator var_op = Variant::OP_MAX; @@ -205,7 +205,7 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS return _parse_expression(codegen, p_expression->arguments[1], p_stack_level, false, initializer); } - if (!_create_binary_operator(codegen, p_expression, var_op, p_stack_level, initializer)) + if (!_create_binary_operator(codegen, p_expression, var_op, p_stack_level, initializer, p_index_addr)) return -1; int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); @@ -214,7 +214,7 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS return dst_addr; } -int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root, bool p_initializer) { +int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root, bool p_initializer, int p_index_addr) { switch (p_expression->type) { //should parse variable declaration and adjust stack accordingly... @@ -704,7 +704,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return from; int index; - if (named) { + if (p_index_addr != 0) { + index = p_index_addr; + } else if (named) { if (on->arguments[0]->type == GDScriptParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(on->arguments[1]); @@ -1091,7 +1093,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.alloc_stack(slevel); } - int set_value = _parse_assign_right_expression(codegen, on, slevel + 1); + int set_value = _parse_assign_right_expression(codegen, on, slevel + 1, named ? 0 : set_index); if (set_value < 0) //error return set_value; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index bb3ee881f8..7d5234a023 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -140,12 +140,12 @@ class GDScriptCompiler { void _set_error(const String &p_error, const GDScriptParser::Node *p_node); bool _create_unary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level); - bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false); + bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false, int p_index_addr = 0); GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const; - int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level); - int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false); + int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level, int p_index_addr = 0); + int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false, int p_index_addr = 0); Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index a01a7397fe..eef39da8b5 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -500,6 +500,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Object *obj_A = *a; Object *obj_B = *b; +#ifdef DEBUG_ENABLED + if (!ObjectDB::instance_validate(obj_A)) { + err_text = "Left operand of 'is' was already freed."; + OPCODE_BREAK; + } +#endif // DEBUG_ENABLED + GDScript *scr_B = Object::cast_to<GDScript>(obj_B); if (scr_B) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a33d20e433..4350a8042a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -7867,12 +7867,12 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { def_type.is_constant = false; p_function->argument_types.write[i] = def_type; } else { - p_function->return_type = _resolve_type(p_function->return_type, p_function->line); + p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line); if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) { String arg_name = p_function->arguments[i]; _set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" + - arg_name + "' (" + p_function->arguments[i] + ").", + arg_name + "' (" + p_function->argument_types[i].to_string() + ").", p_function->line); } } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 33ca4a5d15..0572c5f746 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -269,7 +269,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { if ((item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function) && !item.label.ends_with("):")) { item.insertText = item.label + "("; - if (symbol && symbol->detail.find(",") == -1) { + if (symbol && symbol->children.empty()) { item.insertText += ")"; } } else if (item.kind == lsp::CompletionItemKind::Event) { diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml index 9403199398..102a9b4236 100644 --- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -15,8 +15,10 @@ Contains the audio data in bytes. </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> + If [code]true[/code], the stream will automatically loop when it reaches the end. </member> <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0"> + Time in seconds at which the stream starts after being looped. </member> </members> <constants> diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 69178317f7..f52b511522 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -110,7 +110,6 @@ String DirAccessJAndroid::get_drive(int p_drive) { Error DirAccessJAndroid::change_dir(String p_dir) { JNIEnv *env = ThreadAndroid::get_env(); - p_dir = p_dir.simplify_path(); if (p_dir == "" || p_dir == "." || (p_dir == ".." && current_dir == "")) return OK; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index d7a72779e6..b4b38ac450 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -883,10 +883,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { ns_android_string = string_table.size() - 1; } - int32_t attr_uses_permission_string = string_table.find("uses-feature"); - if (attr_uses_permission_string == -1) { + int32_t attr_uses_feature_string = string_table.find("uses-feature"); + if (attr_uses_feature_string == -1) { string_table.push_back("uses-feature"); - attr_uses_permission_string = string_table.size() - 1; + attr_uses_feature_string = string_table.size() - 1; } int32_t attr_required_string = string_table.find("required"); @@ -928,7 +928,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } { - manifest_cur_size += 96 + 20; // node and three attrs + end node + manifest_cur_size += 96 + 24; // node and three attrs + end node p_manifest.resize(manifest_cur_size); // start tag @@ -938,7 +938,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size encode_uint16(3, &p_manifest.write[ofs + 28]); // num_attrs @@ -982,7 +982,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name ofs += 24; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 8447af10e4..0ff37e3c37 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -100,6 +100,16 @@ public class GodotLib { public static native void hover(int type, int x, int y); /** + * Forward double_tap events from the main thread to the GL thread. + */ + public static native void double_tap(int x, int y); + + /** + * Forward scroll events from the main thread to the GL thread. + */ + public static native void scroll(int x, int y); + + /** * Forward accelerometer sensor events from the main thread to the GL thread. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotView.java index 78f3763d84..f938583082 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotView.java @@ -32,8 +32,10 @@ package org.godotengine.godot; import android.annotation.SuppressLint; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; +import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; +import org.godotengine.godot.input.GodotGestureHandler; import org.godotengine.godot.input.GodotInputHandler; import org.godotengine.godot.utils.GLUtils; import org.godotengine.godot.xr.XRMode; @@ -68,6 +70,7 @@ public class GodotView extends GLSurfaceView { private final Godot activity; private final GodotInputHandler inputHandler; + private final GestureDetector detector; private final GodotRenderer godotRenderer; public GodotView(Godot activity, XRMode xrMode, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl) { @@ -78,6 +81,7 @@ public class GodotView extends GLSurfaceView { this.activity = activity; this.inputHandler = new GodotInputHandler(this); + this.detector = new GestureDetector(activity, new GodotGestureHandler(this)); this.godotRenderer = new GodotRenderer(); init(xrMode, false, 16, 0); } @@ -90,6 +94,7 @@ public class GodotView extends GLSurfaceView { @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); + this.detector.onTouchEvent(event); return activity.gotTouchEvent(event); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java new file mode 100644 index 0000000000..b42b13894c --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -0,0 +1,106 @@ +/*************************************************************************/ +/* GodotGestureHandler.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.input; + +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.GodotView; + +/** + * Handles gesture input related events for the {@link GodotView} view. + * https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener + */ +public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener { + + private final GodotView godotView; + + public GodotGestureHandler(GodotView godotView) { + this.godotView = godotView; + } + + private void queueEvent(Runnable task) { + godotView.queueEvent(task); + } + + @Override + public boolean onDown(MotionEvent event) { + super.onDown(event); + //Log.i("GodotGesture", "onDown"); + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent event) { + super.onSingleTapConfirmed(event); + return true; + } + + @Override + public void onLongPress(MotionEvent event) { + //Log.i("GodotGesture", "onLongPress"); + } + + @Override + public boolean onDoubleTap(MotionEvent event) { + //Log.i("GodotGesture", "onDoubleTap"); + final int x = Math.round(event.getX()); + final int y = Math.round(event.getY()); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.double_tap(x, y); + } + }); + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + //Log.i("GodotGesture", "onScroll"); + final int x = Math.round(distanceX); + final int y = Math.round(distanceY); + queueEvent(new Runnable() { + @Override + public void run() { + GodotLib.scroll(x, y); + } + }); + return true; + } + + @Override + public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { + //Log.i("GodotGesture", "onFling"); + return true; + } +} diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 0a32f4423b..d3bc216608 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -835,6 +835,20 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jo os_android->process_hover(p_type, Point2(p_x, p_y)); } +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_double_tap(JNIEnv *env, jobject obj, jint p_x, jint p_y) { + if (step == 0) + return; + + os_android->process_double_tap(Point2(p_x, p_y)); +} + +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jobject obj, jint p_x, jint p_y) { + if (step == 0) + return; + + os_android->process_scroll(Point2(p_x, p_y)); +} + /* * Android Key codes. */ diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index 8c18c52d2b..08029c3c30 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -46,6 +46,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jobject obj, jint p_type, jint p_x, jint p_y); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_double_tap(JNIEnv *env, jobject obj, jint p_x, jint p_y); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jobject obj, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jobject obj, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 4c560273e8..bbea5e3699 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -502,6 +502,26 @@ void OS_Android::process_hover(int p_type, Point2 p_pos) { } } +void OS_Android::process_double_tap(Point2 p_pos) { + Ref<InputEventMouseButton> ev; + ev.instance(); + ev->set_position(p_pos); + ev->set_global_position(p_pos); + ev->set_pressed(true); + ev->set_doubleclick(true); + ev->set_button_index(1); + input->parse_input_event(ev); +} + +void OS_Android::process_scroll(Point2 p_pos) { + Ref<InputEventPanGesture> ev; + ev.instance(); + ev->set_position(p_pos); + ev->set_delta(p_pos - scroll_prev_pos); + input->parse_input_event(ev); + scroll_prev_pos = p_pos; +} + void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) { input->set_accelerometer(p_accelerometer); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 5ac50ddef2..1cf64a2e84 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -70,6 +70,7 @@ public: private: Vector<TouchPos> touch; Point2 hover_prev_pos; // needed to calculate the relative position on hover events + Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events bool use_gl2; bool use_apk_expansion; @@ -187,6 +188,8 @@ public: void process_gyroscope(const Vector3 &p_gyroscope); void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points); void process_hover(int p_type, Point2 p_pos); + void process_double_tap(Point2 p_pos); + void process_scroll(Point2 p_pos); void process_joy_event(JoypadEvent p_event); void process_event(Ref<InputEvent> p_event); void init_video_mode(int p_video_width, int p_video_height); diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index ce7b47c414..1cb72943fc 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -509,12 +509,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p io2.opaque = &dst_f; zipFile dst_pkg_zip = NULL; + DirAccess *tmp_app_path = NULL; String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip"; if (export_format == "dmg") { // We're on OSX so we can export to DMG, but first we create our application bundle tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app"); print_line("Exporting to " + tmp_app_path_name); - DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); + tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); if (!tmp_app_path) { err = ERR_CANT_CREATE; } @@ -617,19 +618,23 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (export_format == "dmg") { // write it into our application bundle file = tmp_app_path_name.plus_file(file); - - // write the file, need to add chmod - FileAccess *f = FileAccess::open(file, FileAccess::WRITE); - if (f) { - f->store_buffer(data.ptr(), data.size()); - f->close(); - if (is_execute) { - // Chmod with 0755 if the file is executable - FileAccess::set_unix_permissions(file, 0755); + if (err == OK) { + err = tmp_app_path->make_dir_recursive(file.get_base_dir()); + } + if (err == OK) { + // write the file, need to add chmod + FileAccess *f = FileAccess::open(file, FileAccess::WRITE); + if (f) { + f->store_buffer(data.ptr(), data.size()); + f->close(); + if (is_execute) { + // Chmod with 0755 if the file is executable + FileAccess::set_unix_permissions(file, 0755); + } + memdelete(f); + } else { + err = ERR_CANT_CREATE; } - memdelete(f); - } else { - err = ERR_CANT_CREATE; } } else { // add it to our zip file diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index 3a91c62546..19c8f71d0e 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -107,7 +107,7 @@ static void handle_crash(int sig) { output.erase(output.length() - 1, 1); } - fprintf(stderr, "[%ld] %s (%ls)\n", i, fname, output.c_str()); + fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str()); } free(strings); diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 28a8c4d658..917ced5feb 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -35,6 +35,7 @@ #define NORMAL_SUFFIX "_normal" +#ifdef TOOLS_ENABLED Dictionary AnimatedSprite::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -72,6 +73,7 @@ bool AnimatedSprite::_edit_use_rect() const { t = frames->get_frame(animation, frame); return t.is_valid(); } +#endif Rect2 AnimatedSprite::get_anchorable_rect() const { return _get_rect(); diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index 2017c62a48..cd00a4e181 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -156,6 +156,7 @@ protected: virtual void _validate_property(PropertyInfo &property) const; public: +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -164,6 +165,7 @@ public: virtual bool _edit_use_pivot() const; virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif virtual Rect2 get_anchorable_rect() const; diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index 1a6f30e0fd..faeb6b7169 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -50,6 +50,7 @@ void BackBufferCopy::_update_copy_mode() { } } +#ifdef TOOLS_ENABLED Rect2 BackBufferCopy::_edit_get_rect() const { return rect; @@ -58,6 +59,7 @@ Rect2 BackBufferCopy::_edit_get_rect() const { bool BackBufferCopy::_edit_use_rect() const { return true; } +#endif Rect2 BackBufferCopy::get_anchorable_rect() const { diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index 91acd81e00..4b26bf1bdc 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -53,8 +53,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif void set_rect(const Rect2 &p_rect); Rect2 get_rect() const; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 9895dba027..5631aa3355 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -351,7 +351,7 @@ CanvasItemMaterial::~CanvasItemMaterial() { } /////////////////////////////////////////////////////////////////// - +#ifdef TOOLS_ENABLED bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { if (_edit_use_rect()) { return _edit_get_rect().has_point(p_point); @@ -363,6 +363,7 @@ bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tole Transform2D CanvasItem::_edit_get_transform() const { return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot()); } +#endif bool CanvasItem::is_visible_in_tree() const { @@ -1121,9 +1122,10 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self); ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback); + +#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state); ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state); - ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position); ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position); ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale); @@ -1138,6 +1140,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot); ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot); ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform); +#endif ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 82645051e8..8814d99edd 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -249,7 +249,7 @@ public: }; /* EDITOR */ - +#ifdef TOOLS_ENABLED // Select the node virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; @@ -282,6 +282,7 @@ public: virtual Point2 _edit_get_pivot() const { return Point2(); }; virtual Transform2D _edit_get_transform() const; +#endif /* VISIBILITY */ diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 3090c9956e..d9cc94c6eb 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -227,6 +227,7 @@ CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { return build_mode; } +#ifdef TOOLS_ENABLED Rect2 CollisionPolygon2D::_edit_get_rect() const { return aabb; @@ -240,6 +241,7 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl return Geometry::is_point_in_polygon(p_point, Variant(polygon)); } +#endif String CollisionPolygon2D::get_configuration_warning() const { diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index e5e18b2674..d8dfec8fd2 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -67,16 +67,18 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_use_rect() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif + void set_build_mode(BuildMode p_mode); BuildMode get_build_mode() const; void set_polygon(const Vector<Point2> &p_polygon); Vector<Point2> get_polygon() const; - virtual Rect2 _edit_get_rect() const; - virtual bool _edit_use_rect() const; - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; - virtual String get_configuration_warning() const; void set_disabled(bool p_disabled); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 1843cbed67..eb66265010 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -33,6 +33,7 @@ #include "core/engine.h" #include "servers/visual_server.h" +#ifdef TOOLS_ENABLED Dictionary Light2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = get_texture_offset(); @@ -68,6 +69,7 @@ Rect2 Light2D::_edit_get_rect() const { bool Light2D::_edit_use_rect() const { return !texture.is_null(); } +#endif Rect2 Light2D::get_anchorable_rect() const { if (texture.is_null()) diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index f8476e8389..65db5c6ee6 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -85,6 +85,7 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -93,6 +94,7 @@ public: virtual bool _edit_use_pivot() const; virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif virtual Rect2 get_anchorable_rect() const; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 6a930683d1..0e8e8f6679 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -33,6 +33,8 @@ #include "core/engine.h" #define LINE_GRAB_WIDTH 8 + +#ifdef TOOLS_ENABLED Rect2 OccluderPolygon2D::_edit_get_rect() const { if (rect_cache_dirty) { @@ -80,6 +82,7 @@ bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double return false; } } +#endif void OccluderPolygon2D::set_polygon(const PoolVector<Vector2> &p_polygon) { @@ -215,6 +218,7 @@ void LightOccluder2D::_notification(int p_what) { } } +#ifdef TOOLS_ENABLED Rect2 LightOccluder2D::_edit_get_rect() const { return occluder_polygon.is_valid() ? occluder_polygon->_edit_get_rect() : Rect2(); @@ -224,6 +228,7 @@ bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p return occluder_polygon.is_valid() ? occluder_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false; } +#endif void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) { diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index 32d527093d..b20e347c35 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -57,8 +57,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_polygon(const PoolVector<Vector2> &p_polygon); PoolVector<Vector2> get_polygon() const; @@ -91,8 +93,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon); Ref<OccluderPolygon2D> get_occluder_polygon() const; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 4a022f0a9c..c31840c8e1 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -50,6 +50,7 @@ Line2D::Line2D() { _antialiased = false; } +#ifdef TOOLS_ENABLED Rect2 Line2D::_edit_get_rect() const { if (_points.size() == 0) @@ -79,6 +80,7 @@ bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc return false; } +#endif void Line2D::set_points(const PoolVector<Vector2> &p_points) { _points = p_points; diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index bc2deba8c6..3c7239f67c 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -56,11 +56,13 @@ public: LINE_TEXTURE_STRETCH }; - Line2D(); - +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif + + Line2D(); void set_points(const PoolVector<Vector2> &p_points); PoolVector<Vector2> get_points() const; diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 8f9c4e2a4d..93432ec40b 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -94,6 +94,7 @@ Ref<Texture> MeshInstance2D::get_texture() const { return texture; } +#ifdef TOOLS_ENABLED Rect2 MeshInstance2D::_edit_get_rect() const { if (mesh.is_valid()) { @@ -103,6 +104,7 @@ Rect2 MeshInstance2D::_edit_get_rect() const { return Node2D::_edit_get_rect(); } +#endif MeshInstance2D::MeshInstance2D() { } diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index e7f8b7c0c3..51f75a3ead 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -46,6 +46,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED + virtual Rect2 _edit_get_rect() const; +#endif + void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; @@ -55,8 +59,6 @@ public: void set_normal_map(const Ref<Texture> &p_texture); Ref<Texture> get_normal_map() const; - virtual Rect2 _edit_get_rect() const; - MeshInstance2D(); }; diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index 69d687229b..028459e778 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -94,6 +94,7 @@ Ref<Texture> MultiMeshInstance2D::get_normal_map() const { return normal_map; } +#ifdef TOOLS_ENABLED Rect2 MultiMeshInstance2D::_edit_get_rect() const { if (multimesh.is_valid()) { @@ -103,6 +104,7 @@ Rect2 MultiMeshInstance2D::_edit_get_rect() const { return Node2D::_edit_get_rect(); } +#endif MultiMeshInstance2D::MultiMeshInstance2D() { } diff --git a/scene/2d/multimesh_instance_2d.h b/scene/2d/multimesh_instance_2d.h index 253f4c77ca..c3f3e52920 100644 --- a/scene/2d/multimesh_instance_2d.h +++ b/scene/2d/multimesh_instance_2d.h @@ -47,6 +47,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED + virtual Rect2 _edit_get_rect() const; +#endif + void set_multimesh(const Ref<MultiMesh> &p_multimesh); Ref<MultiMesh> get_multimesh() const; @@ -56,8 +60,6 @@ public: void set_normal_map(const Ref<Texture> &p_texture); Ref<Texture> get_normal_map() const; - virtual Rect2 _edit_get_rect() const; - MultiMeshInstance2D(); ~MultiMeshInstance2D(); }; diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index bd930bdda5..ea79f89dd9 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -36,6 +36,7 @@ #include "thirdparty/misc/triangulator.h" +#ifdef TOOLS_ENABLED Rect2 NavigationPolygon::_edit_get_rect() const { if (rect_cache_dirty) { @@ -75,6 +76,7 @@ bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double } return false; } +#endif void NavigationPolygon::set_vertices(const PoolVector<Vector2> &p_vertices) { @@ -357,7 +359,7 @@ bool NavigationPolygonInstance::is_enabled() const { } ///////////////////////////// - +#ifdef TOOLS_ENABLED Rect2 NavigationPolygonInstance::_edit_get_rect() const { return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2(); @@ -367,6 +369,7 @@ bool NavigationPolygonInstance::_edit_is_selected_on_click(const Point2 &p_point return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false; } +#endif void NavigationPolygonInstance::_notification(int p_what) { diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h index 9bbaa864f4..cbc1711a32 100644 --- a/scene/2d/navigation_polygon.h +++ b/scene/2d/navigation_polygon.h @@ -57,8 +57,10 @@ protected: Array _get_outlines() const; public: +#ifdef TOOLS_ENABLED Rect2 _edit_get_rect() const; bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_vertices(const PoolVector<Vector2> &p_vertices); PoolVector<Vector2> get_vertices() const; @@ -100,8 +102,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_enabled(bool p_enabled); bool is_enabled() const; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index ad04dc8d9e..7bbc7577ed 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -35,6 +35,7 @@ #include "scene/main/viewport.h" #include "servers/visual_server.h" +#ifdef TOOLS_ENABLED Dictionary Node2D::_edit_get_state() const { Dictionary state; @@ -44,6 +45,7 @@ Dictionary Node2D::_edit_get_state() const { return state; } + void Node2D::_edit_set_state(const Dictionary &p_state) { pos = p_state["position"]; @@ -119,6 +121,7 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) { _change_notify("scale"); _change_notify("position"); } +#endif void Node2D::_update_xform_values() { diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index a03ccc5a80..00202481a6 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -55,6 +55,7 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -69,6 +70,7 @@ public: virtual bool _edit_use_rotation() const; virtual void _edit_set_rect(const Rect2 &p_edit_rect); +#endif void set_position(const Point2 &p_pos); void set_rotation(float p_radians); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index e6ae95af89..e9296b0fe7 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -37,6 +37,7 @@ #include "editor/editor_scale.h" #endif +#ifdef TOOLS_ENABLED Rect2 Path2D::_edit_get_rect() const { if (!curve.is_valid() || curve->get_point_count() == 0) @@ -85,6 +86,7 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc return false; } +#endif void Path2D::_notification(int p_what) { diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 21cb4374bd..35cf8211f4 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -47,9 +47,11 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_curve(const Ref<Curve2D> &p_curve); Ref<Curve2D> get_curve() const; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 3fd0bef7e9..90663bd675 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1212,7 +1212,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_ //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector2 body_velocity = p_linear_velocity; Vector2 body_velocity_normal = body_velocity.normalized(); @@ -1234,6 +1234,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const on_ceiling = false; on_wall = false; colliders.clear(); + floor_normal = p_up_direction; floor_velocity = Vector2(); while (p_max_slides) { @@ -1262,25 +1263,26 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const colliders.push_back(collision); motion = collision.remainder; - if (p_floor_direction == Vector2()) { + if (p_up_direction == Vector2()) { //all is a wall on_wall = true; } else { - if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + if (Math::acos(collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; + floor_normal = collision.normal; on_floor_body = collision.collider_rid; floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if ((body_velocity_normal + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { + if ((body_velocity_normal + p_up_direction).length() < 0.01 && collision.travel.length() < 1) { Transform2D gt = get_global_transform(); - gt.elements[2] -= collision.travel.slide(p_floor_direction); + gt.elements[2] -= collision.travel.slide(p_up_direction); set_global_transform(gt); return Vector2(); } } - } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + } else if (Math::acos(collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; @@ -1301,11 +1303,11 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const return body_velocity; } -Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { bool was_on_floor = on_floor; - Vector2 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); + Vector2 ret = move_and_slide(p_linear_velocity, p_up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); if (!was_on_floor || p_snap == Vector2()) { return ret; } @@ -1315,15 +1317,16 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { bool apply = true; - if (p_floor_direction != Vector2()) { - if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + if (p_up_direction != Vector2()) { + if (Math::acos(p_up_direction.normalized().dot(col.normal)) < p_floor_max_angle) { on_floor = true; + floor_normal = col.normal; on_floor_body = col.collider_rid; floor_velocity = col.collider_vel; if (p_stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, // so only ensure that motion happens on floor direction in this case. - col.travel = p_floor_direction * p_floor_direction.dot(col.travel); + col.travel = p_up_direction * p_up_direction.dot(col.travel); } } else { @@ -1353,6 +1356,11 @@ bool KinematicBody2D::is_on_ceiling() const { return on_ceiling; } +Vector2 KinematicBody2D::get_floor_normal() const { + + return floor_normal; +} + Vector2 KinematicBody2D::get_floor_velocity() const { return floor_velocity; @@ -1473,6 +1481,7 @@ void KinematicBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling); ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody2D::get_floor_normal); ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 7f2b42b554..6766bafde3 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -306,6 +306,7 @@ public: private: float margin; + Vector2 floor_normal; Vector2 floor_velocity; RID on_floor_body; bool on_floor; @@ -339,11 +340,12 @@ public: void set_safe_margin(float p_margin); float get_safe_margin() const; - Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); - Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; + Vector2 get_floor_normal() const; Vector2 get_floor_velocity() const; int get_slide_count() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 7b03193fe0..c480423eca 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -33,6 +33,7 @@ #include "core/math/geometry.h" #include "skeleton_2d.h" +#ifdef TOOLS_ENABLED Dictionary Polygon2D::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -87,6 +88,7 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler } return Geometry::is_point_in_polygon(p_point - get_offset(), polygon2d); } +#endif void Polygon2D::_skeleton_bone_setup_changed() { update(); diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index 84ad221760..07b8828532 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -77,6 +77,7 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -87,6 +88,7 @@ public: virtual bool _edit_use_rect() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif void set_polygon(const PoolVector<Vector2> &p_polygon); PoolVector<Vector2> get_polygon() const; diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 49ef92b861..cdeb905c0c 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -43,6 +43,7 @@ void Position2D::_draw_cross() { draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01)); } +#ifdef TOOLS_ENABLED Rect2 Position2D::_edit_get_rect() const { float extents = get_gizmo_extents(); @@ -52,6 +53,7 @@ Rect2 Position2D::_edit_get_rect() const { bool Position2D::_edit_use_rect() const { return false; } +#endif void Position2D::_notification(int p_what) { diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index 711c4ec02f..3ea636171d 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -44,8 +44,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif void set_gizmo_extents(float p_extents); float get_gizmo_extents() const; diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 837444532c..55daed0585 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -34,6 +34,7 @@ #include "scene/main/viewport.h" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED Dictionary Sprite::_edit_get_state() const { Dictionary state = Node2D::_edit_get_state(); state["offset"] = offset; @@ -58,6 +59,11 @@ bool Sprite::_edit_use_pivot() const { return true; } +bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + return is_pixel_opaque(p_point); +} + Rect2 Sprite::_edit_get_rect() const { return get_rect(); } @@ -65,6 +71,7 @@ Rect2 Sprite::_edit_get_rect() const { bool Sprite::_edit_use_rect() const { return texture.is_valid(); } +#endif Rect2 Sprite::get_anchorable_rect() const { return get_rect(); @@ -305,11 +312,6 @@ int Sprite::get_hframes() const { return hframes; } -bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - - return is_pixel_opaque(p_point); -} - bool Sprite::is_pixel_opaque(const Point2 &p_point) const { if (texture.is_null()) diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h index 2fd97f6611..d72bf3168d 100644 --- a/scene/2d/sprite.h +++ b/scene/2d/sprite.h @@ -67,6 +67,7 @@ protected: virtual void _validate_property(PropertyInfo &property) const; public: +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -75,10 +76,11 @@ public: virtual bool _edit_use_pivot() const; virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; - bool is_pixel_opaque(const Point2 &p_point) const; - virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif + + bool is_pixel_opaque(const Point2 &p_point) const; void set_texture(const Ref<Texture> &p_texture); Ref<Texture> get_texture() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 04ec13e415..b6db025d44 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1282,6 +1282,7 @@ PoolVector<int> TileMap::_get_tile_data() const { return data; } +#ifdef TOOLS_ENABLED Rect2 TileMap::_edit_get_rect() const { if (pending_update) { const_cast<TileMap *>(this)->update_dirty_quadrants(); @@ -1290,6 +1291,7 @@ Rect2 TileMap::_edit_get_rect() const { } return rect_cache; } +#endif void TileMap::set_collision_layer(uint32_t p_layer) { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 53bb696ba2..0875d197eb 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -244,7 +244,9 @@ public: INVALID_CELL = -1 }; +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; +#endif void set_tileset(const Ref<TileSet> &p_tileset); Ref<TileSet> get_tileset() const; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index f6a888fa09..42d9f88a60 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -135,7 +135,9 @@ void TouchScreenButton::_notification(int p_what) { return; if (shape.is_valid()) { Color draw_col = get_tree()->get_debug_collisions_color(); - Vector2 pos = shape_centered ? _edit_get_rect().size * 0.5f : Vector2(); + + Vector2 size = texture.is_null() ? shape->get_rect().size : texture->get_size(); + Vector2 pos = shape_centered ? size * 0.5f : Vector2(); draw_set_transform_matrix(get_canvas_transform().translated(pos)); shape->draw(get_canvas_item(), draw_col); } @@ -251,9 +253,7 @@ void TouchScreenButton::_input(const Ref<InputEvent> &p_event) { } bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { - Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(p_point); - Rect2 item_rect = _edit_get_rect(); bool touched = false; bool check_rect = true; @@ -261,7 +261,7 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { if (shape.is_valid()) { check_rect = false; - Transform2D xform = shape_centered ? Transform2D().translated(item_rect.size * 0.5f) : Transform2D(); + Transform2D xform = shape_centered ? Transform2D().translated(shape->get_rect().size * 0.5f) : Transform2D(); touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); } @@ -277,7 +277,7 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { if (!touched && check_rect) { if (texture.is_valid()) - touched = item_rect.has_point(coord); + touched = Rect2(Size2(), texture->get_size()).has_point(coord); } return touched; @@ -324,6 +324,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) { } } +#ifdef TOOLS_ENABLED Rect2 TouchScreenButton::_edit_get_rect() const { if (texture.is_null()) return CanvasItem::_edit_get_rect(); @@ -334,6 +335,7 @@ Rect2 TouchScreenButton::_edit_get_rect() const { bool TouchScreenButton::_edit_use_rect() const { return !texture.is_null(); } +#endif Rect2 TouchScreenButton::get_anchorable_rect() const { if (texture.is_null()) diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h index 9c9fc6125a..28dba59402 100644 --- a/scene/2d/touch_screen_button.h +++ b/scene/2d/touch_screen_button.h @@ -74,6 +74,11 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_use_rect() const; +#endif + void set_texture(const Ref<Texture> &p_texture); Ref<Texture> get_texture() const; @@ -103,8 +108,6 @@ public: bool is_pressed() const; - virtual Rect2 _edit_get_rect() const; - virtual bool _edit_use_rect() const; virtual Rect2 get_anchorable_rect() const; TouchScreenButton(); diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 223e57f39f..0ac725b7dd 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -38,6 +38,16 @@ #include "scene/main/viewport.h" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +Rect2 VisibilityNotifier2D::_edit_get_rect() const { + return rect; +} + +bool VisibilityNotifier2D::_edit_use_rect() const { + return true; +} +#endif + void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) { ERR_FAIL_COND(viewports.has(p_viewport)); @@ -84,15 +94,6 @@ void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) { _change_notify("rect"); } -Rect2 VisibilityNotifier2D::_edit_get_rect() const { - - return rect; -} - -bool VisibilityNotifier2D::_edit_use_rect() const { - return true; -} - Rect2 VisibilityNotifier2D::get_rect() const { return rect; diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index f9d4c238eb..a3b79d29e9 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -55,8 +55,10 @@ protected: static void _bind_methods(); public: +#ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; +#endif void set_rect(const Rect2 &p_rect); Rect2 get_rect() const; diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 289dc0ba07..3a30755f7f 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -398,9 +398,9 @@ Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const { CameraMatrix cm; if (mode == PROJECTION_ORTHOGONAL) - cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); + cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH); else - cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); + cm.set_perspective(fov, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH); Size2 vp_size; cm.get_viewport_size(vp_size.x, vp_size.y); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index c2860c25d8..999f39c841 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1140,7 +1140,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector3 body_velocity = p_linear_velocity; Vector3 body_velocity_normal = body_velocity.normalized(); @@ -1159,6 +1159,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve on_ceiling = false; on_wall = false; colliders.clear(); + floor_normal = p_up_direction; floor_velocity = Vector3(); while (p_max_slides) { @@ -1187,25 +1188,26 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve colliders.push_back(collision); motion = collision.remainder; - if (p_floor_direction == Vector3()) { + if (p_up_direction == Vector3()) { //all is a wall on_wall = true; } else { - if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + if (Math::acos(collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; + floor_normal = collision.normal; on_floor_body = collision.collider_rid; floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if ((body_velocity_normal + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { + if ((body_velocity_normal + p_up_direction).length() < 0.01 && collision.travel.length() < 1) { Transform gt = get_global_transform(); - gt.origin -= collision.travel.slide(p_floor_direction); + gt.origin -= collision.travel.slide(p_up_direction); set_global_transform(gt); return Vector3(); } } - } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + } else if (Math::acos(collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; @@ -1232,11 +1234,11 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve return body_velocity; } -Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { bool was_on_floor = on_floor; - Vector3 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); + Vector3 ret = move_and_slide(p_linear_velocity, p_up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); if (!was_on_floor || p_snap == Vector3()) { return ret; } @@ -1247,15 +1249,16 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { bool apply = true; - if (p_floor_direction != Vector3()) { - if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + if (p_up_direction != Vector3()) { + if (Math::acos(p_up_direction.normalized().dot(col.normal)) < p_floor_max_angle) { on_floor = true; + floor_normal = col.normal; on_floor_body = col.collider_rid; floor_velocity = col.collider_vel; if (p_stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, // so only ensure that motion happens on floor direction in this case. - col.travel = col.travel.project(p_floor_direction); + col.travel = col.travel.project(p_up_direction); } } else { apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. @@ -1284,6 +1287,11 @@ bool KinematicBody::is_on_ceiling() const { return on_ceiling; } +Vector3 KinematicBody::get_floor_normal() const { + + return floor_normal; +} + Vector3 KinematicBody::get_floor_velocity() const { return floor_velocity; @@ -1392,7 +1400,7 @@ void KinematicBody::_notification(int p_what) { void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move, DEFVAL(true)); @@ -1400,6 +1408,7 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling); ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody::get_floor_normal); ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody::get_floor_velocity); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody::set_axis_lock); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 06b31804b2..05bcbe22f0 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -300,6 +300,7 @@ private: float margin; + Vector3 floor_normal; Vector3 floor_velocity; RID on_floor_body; bool on_floor; @@ -330,11 +331,12 @@ public: void set_safe_margin(float p_margin); float get_safe_margin() const; - Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); - Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; + Vector3 get_floor_normal() const; Vector3 get_floor_velocity() const; int get_slide_count() const; diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 65912c1c07..b2020d44e8 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -165,7 +165,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { _pressed(); } } else { - if (!p_event->is_pressed()) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { _pressed(); } } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 5e656eea70..9a67745e0d 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -47,6 +47,7 @@ #include "editor/plugins/canvas_item_editor_plugin.h" #endif +#ifdef TOOLS_ENABLED Dictionary Control::_edit_get_state() const { Dictionary s; @@ -155,6 +156,11 @@ bool Control::_edit_use_pivot() const { return true; } +Size2 Control::_edit_get_minimum_size() const { + return get_combined_minimum_size(); +} +#endif + void Control::set_custom_minimum_size(const Size2 &p_custom) { if (p_custom == data.custom_minimum_size) @@ -193,11 +199,6 @@ Size2 Control::get_combined_minimum_size() const { return data.minimum_size_cache; } -Size2 Control::_edit_get_minimum_size() const { - - return get_combined_minimum_size(); -} - Transform2D Control::_get_internal_transform() const { Transform2D rot_scale; diff --git a/scene/gui/control.h b/scene/gui/control.h index a9831b9793..357858beb6 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -279,6 +279,7 @@ public: }; /* EDITOR */ +#ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const; virtual void _edit_set_state(const Dictionary &p_state); @@ -301,6 +302,7 @@ public: virtual bool _edit_use_pivot() const; virtual Size2 _edit_get_minimum_size() const; +#endif void accept_event(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 6b12947651..77913efd1c 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -35,9 +35,17 @@ void Label::set_autowrap(bool p_autowrap) { + if (autowrap == p_autowrap) { + return; + } + autowrap = p_autowrap; word_cache_dirty = true; update(); + + if (clip) { + minimum_size_changed(); + } } bool Label::has_autowrap() const { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 9505c0af39..225b382524 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -4542,8 +4542,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } p_block->statements.push_back(flow); - if (p_block->block_type == BlockNode::BLOCK_TYPE_CASE || p_block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { - return OK; + + BlockNode *block = p_block; + while (block) { + if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { + return OK; + } + block = block->parent_block; } } else if (tk.type == TK_CF_DISCARD) { @@ -4591,8 +4596,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } p_block->statements.push_back(flow); - if (p_block->block_type == BlockNode::BLOCK_TYPE_CASE || p_block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { - return OK; + + BlockNode *block = p_block; + while (block) { + if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) { + return OK; + } + block = block->parent_block; } } else if (tk.type == TK_CF_CONTINUE) { |