diff options
24 files changed, 280 insertions, 20 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index d8951ddb78..6c9d8d30f2 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -19,14 +19,14 @@ jobs: sudo rm -f /etc/apt/sources.list.d/* sudo cp -f misc/ci/sources.list /etc/apt/sources.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main" + sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main" sudo apt-get update - name: Install dependencies run: | - sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils python3-pip moreutils + sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils sudo update-alternatives --remove-all clang-format || true - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100 sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971 - name: File formatting checks (file_format.sh) diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml index 87e2b8ea20..3816847804 100644 --- a/doc/classes/InputEventAction.xml +++ b/doc/classes/InputEventAction.xml @@ -5,6 +5,7 @@ </brief_description> <description> Contains a generic action which can be targeted from several types of inputs. Actions can be created from the [b]Input Map[/b] tab in the [b]Project > Project Settings[/b] menu. See [method Node._input]. + [b]Note:[/b] Unlike the other [InputEvent] subclasses which map to unique physical events, this virtual one is not emitted by the engine. This class is useful to emit actions manually with [method Input.parse_input_event], which are then received in [method Node._input]. To check if a physical event matches an action from the Input Map, use [method InputEvent.is_action] and [method InputEvent.is_action_pressed]. </description> <tutorials> <link title="InputEvent: Actions">$DOCS_URL/tutorials/inputs/inputevent.html#actions</link> diff --git a/doc/classes/PhysicsDirectSpaceState2DExtension.xml b/doc/classes/PhysicsDirectSpaceState2DExtension.xml index 3235793853..fbbb98a959 100644 --- a/doc/classes/PhysicsDirectSpaceState2DExtension.xml +++ b/doc/classes/PhysicsDirectSpaceState2DExtension.xml @@ -87,5 +87,11 @@ <description> </description> </method> + <method name="is_body_excluded_from_query" qualifiers="const"> + <return type="bool" /> + <param index="0" name="body" type="RID" /> + <description> + </description> + </method> </methods> </class> diff --git a/doc/classes/PhysicsDirectSpaceState3DExtension.xml b/doc/classes/PhysicsDirectSpaceState3DExtension.xml index 98593012db..4297846e53 100644 --- a/doc/classes/PhysicsDirectSpaceState3DExtension.xml +++ b/doc/classes/PhysicsDirectSpaceState3DExtension.xml @@ -95,5 +95,11 @@ <description> </description> </method> + <method name="is_body_excluded_from_query" qualifiers="const"> + <return type="bool" /> + <param index="0" name="body" type="RID" /> + <description> + </description> + </method> </methods> </class> diff --git a/doc/classes/PhysicsServer2DExtension.xml b/doc/classes/PhysicsServer2DExtension.xml index 9bb11e0d89..7ae27c3f32 100644 --- a/doc/classes/PhysicsServer2DExtension.xml +++ b/doc/classes/PhysicsServer2DExtension.xml @@ -933,5 +933,17 @@ <description> </description> </method> + <method name="body_test_motion_is_excluding_body" qualifiers="const"> + <return type="bool" /> + <param index="0" name="body" type="RID" /> + <description> + </description> + </method> + <method name="body_test_motion_is_excluding_object" qualifiers="const"> + <return type="bool" /> + <param index="0" name="object" type="int" /> + <description> + </description> + </method> </methods> </class> diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml index d45cb17510..5fe616b948 100644 --- a/doc/classes/PhysicsServer3DExtension.xml +++ b/doc/classes/PhysicsServer3DExtension.xml @@ -1284,5 +1284,17 @@ <description> </description> </method> + <method name="body_test_motion_is_excluding_body" qualifiers="const"> + <return type="bool" /> + <param index="0" name="body" type="RID" /> + <description> + </description> + </method> + <method name="body_test_motion_is_excluding_object" qualifiers="const"> + <return type="bool" /> + <param index="0" name="object" type="int" /> + <description> + </description> + </method> </methods> </class> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index bd5b656e1a..bf19ebc23a 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -42,15 +42,15 @@ <description> Changes the running scene to the one at the given [param path], after loading it into a [PackedScene] and creating a new instance. Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [param path] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if that scene cannot be instantiated. - [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. You won't be able to access it immediately after the [method change_scene_to_file] call. + [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. This ensures that both scenes are never loaded at the same time, which can exhaust system resources if the scenes are too large or if running in a memory constrained environment. As such, you won't be able to access the loaded scene immediately after the [method change_scene_to_file] call. </description> </method> <method name="change_scene_to_packed"> <return type="int" enum="Error" /> <param index="0" name="packed_scene" type="PackedScene" /> <description> - Changes the running scene to a new instance of the given [PackedScene]. - Returns [constant OK] on success or [constant ERR_CANT_CREATE] if the scene cannot be instantiated. + Changes the running scene to a new instance of the given [PackedScene] (which must be valid). + Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is invalid. [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. You won't be able to access it immediately after the [method change_scene_to_packed] call. </description> </method> @@ -209,6 +209,12 @@ Sets a custom [MultiplayerAPI] with the given [param root_path] (controlling also the relative subpaths), or override the default one if [param root_path] is empty. </description> </method> + <method name="unload_current_scene"> + <return type="void" /> + <description> + If a current scene is loaded, calling this method will unload it. + </description> + </method> </methods> <members> <member name="auto_accept_quit" type="bool" setter="set_auto_accept_quit" getter="is_auto_accept_quit" default="true"> diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp index 3a99c4e264..274fe34c52 100644 --- a/editor/event_listener_line_edit.cpp +++ b/editor/event_listener_line_edit.cpp @@ -168,8 +168,8 @@ void EventListenerLineEdit::clear_event() { } } -void EventListenerLineEdit::set_allowed_input_types(int input_types) { - allowed_input_types = input_types; +void EventListenerLineEdit::set_allowed_input_types(int p_type_masks) { + allowed_input_types = p_type_masks; } int EventListenerLineEdit::get_allowed_input_types() const { diff --git a/editor/event_listener_line_edit.h b/editor/event_listener_line_edit.h index 0679733b6a..aa0cc91d47 100644 --- a/editor/event_listener_line_edit.h +++ b/editor/event_listener_line_edit.h @@ -67,7 +67,7 @@ public: Ref<InputEvent> get_event() const; void clear_event(); - void set_allowed_input_types(int input_types); + void set_allowed_input_types(int p_type_masks); int get_allowed_input_types() const; void grab_focus(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 8306723f5c..6eed3e3e61 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2599,7 +2599,8 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str String fpath = p_paths[0]; String item_text = fpath.ends_with("/") ? TTR("Open in File Manager") : TTR("Show in File Manager"); - p_popup->add_icon_item(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), item_text, FILE_SHOW_IN_EXPLORER); + p_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); + p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), item_text); path = fpath; } } @@ -2644,7 +2645,7 @@ void FileSystemDock::_tree_empty_click(const Vector2 &p_pos, MouseButton p_butto tree_popup->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("New Resource..."), FILE_NEW_RESOURCE); tree_popup->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); tree_popup->add_separator(); - tree_popup->add_icon_item(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), TTR("Open in File Manager"), FILE_SHOW_IN_EXPLORER); + tree_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); tree_popup->set_position(tree->get_screen_position() + p_pos); tree_popup->reset_size(); @@ -2704,7 +2705,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton file_list_popup->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("New Resource..."), FILE_NEW_RESOURCE); file_list_popup->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); file_list_popup->add_separator(); - file_list_popup->add_icon_item(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), TTR("Open in File Manager"), FILE_SHOW_IN_EXPLORER); + file_list_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); file_list_popup->set_position(files->get_screen_position() + p_pos); file_list_popup->reset_size(); file_list_popup->popup(); @@ -2816,6 +2817,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { _tree_rmb_option(FILE_REMOVE); } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) { _tree_rmb_option(FILE_RENAME); + } else if (ED_IS_SHORTCUT("filesystem_dock/show_in_explorer", p_event)) { + _tree_rmb_option(FILE_SHOW_IN_EXPLORER); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { focus_on_filter(); } else { @@ -2874,6 +2877,8 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) { _file_list_rmb_option(FILE_REMOVE); } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) { _file_list_rmb_option(FILE_RENAME); + } else if (ED_IS_SHORTCUT("filesystem_dock/show_in_explorer", p_event)) { + _file_list_rmb_option(FILE_SHOW_IN_EXPLORER); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { focus_on_filter(); } else { @@ -3045,6 +3050,7 @@ FileSystemDock::FileSystemDock() { ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), Key::KEY_DELETE); ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), Key::F2); ED_SHORTCUT_OVERRIDE("filesystem_dock/rename", "macos", Key::ENTER); + ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager")); VBoxContainer *top_vbc = memnew(VBoxContainer); add_child(top_vbc); diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index b137f6f668..08d4bfff4a 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -515,6 +515,7 @@ Ref<InputEvent> InputEventConfigurationDialog::get_event() const { void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) { allowed_input_types = p_type_masks; + event_listener->set_allowed_input_types(p_type_masks); } InputEventConfigurationDialog::InputEventConfigurationDialog() { diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 1d08c1fe5f..8396d50a0e 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -236,6 +236,7 @@ static const char *gdscript_function_renames[][2] = { { "body_add_torque", "body_apply_torque" }, // PhysicsServer2D { "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image { "can_be_hidden", "_can_be_hidden" }, // EditorNode3DGizmoPlugin + { "can_drop_data", "_can_drop_data" }, // Control { "can_drop_data_fw", "_can_drop_data_fw" }, // ScriptEditor { "can_generate_small_preview", "_can_generate_small_preview" }, // EditorResourcePreviewGenerator { "can_instance", "can_instantiate" }, // PackedScene, Script @@ -262,6 +263,7 @@ static const char *gdscript_function_renames[][2] = { { "delete_char_at_cursor", "delete_char_at_caret" }, // LineEdit { "deselect_items", "deselect_all" }, // FileDialog { "disable_plugin", "_disable_plugin" }, // EditorPlugin + { "drop_data", "_drop_data" }, // Control { "drop_data_fw", "_drop_data_fw" }, // ScriptEditor { "exclude_polygons_2d", "exclude_polygons" }, // Geometry2D { "find_node", "find_child" }, // Node @@ -691,6 +693,7 @@ static const char *csharp_function_renames[][2] = { { "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D { "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image { "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin + { "CanDropData", "_CanDropData" }, // Control { "CanDropDataFw", "_CanDropDataFw" }, // ScriptEditor { "CanGenerateSmallPreview", "_CanGenerateSmallPreview" }, // EditorResourcePreviewGenerator { "CanInstance", "CanInstantiate" }, // PackedScene, Script @@ -714,6 +717,7 @@ static const char *csharp_function_renames[][2] = { { "DampedStringJointSetParam", "DampedSpringJointSetParam" }, // PhysicsServer2D { "DeleteCharAtCursor", "DeleteCharAtCaret" }, // LineEdit { "DeselectItems", "DeselectAll" }, // FileDialog + { "DropData", "_DropData" }, // Control { "DropDataFw", "_DropDataFw" }, // ScriptEditor { "ExcludePolygons2d", "ExcludePolygons" }, // Geometry2D { "FindScancodeFromString", "FindKeycodeFromString" }, // OS diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index fefee9bb24..3b39967ba4 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -101,6 +101,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_huawei_controller_ext env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp") +env_openxr.add_source_files(module_obj, "extensions/openxr_pico_controller_extension.cpp") env_openxr.add_source_files(module_obj, "extensions/openxr_wmr_controller_extension.cpp") env.modules_sources += module_obj diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index e3ff1b4382..669c395b3e 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -307,6 +307,31 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); + // Create our Pico 4 / Neo 3 controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/pico/neo3_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // system click may not be available + profile->add_new_binding(menu_button, "/user/hand/left/input/back/click,/user/hand/right/input/back/click"); // right hand back click may not be available + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch"); + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our pico controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // pico controller has no secondary input + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + // Create our Valve index controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.cpp b/modules/openxr/extensions/openxr_pico_controller_extension.cpp new file mode 100644 index 0000000000..f2fcf22ce2 --- /dev/null +++ b/modules/openxr/extensions/openxr_pico_controller_extension.cpp @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* openxr_pico_controller_extension.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "openxr_pico_controller_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" + +// Pico controllers are not part of the OpenXR spec at the time of writing this +// code. We'll hardcode the extension name that is used internally, verified by +// tests on the Pico 4. Note that later versions of the Pico 4 and OpenXR +// runtime on Pico might use a different, standardized extension name. +#ifndef XR_PICO_CONTROLLER_INTERACTION_EXTENSION_NAME +#define XR_PICO_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_PICO_controller_interaction" +#endif + +HashMap<String, bool *> OpenXRPicoControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_PICO_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available; + + return request_extensions; +} + +bool OpenXRPicoControllerExtension::is_available() { + return available; +} + +void OpenXRPicoControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // Pico controller (Pico 4 and Pico Neo 3 controllers) + metadata->register_interaction_profile("Pico controller", "/interaction_profiles/pico/neo3_controller", XR_PICO_CONTROLLER_INTERACTION_EXTENSION_NAME); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Screenshot click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + metadata->register_io_path("/interaction_profiles/pico/neo3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); +} diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.h b/modules/openxr/extensions/openxr_pico_controller_extension.h new file mode 100644 index 0000000000..a2a1e2f3d3 --- /dev/null +++ b/modules/openxr/extensions/openxr_pico_controller_extension.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* openxr_pico_controller_extension.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef OPENXR_PICO_CONTROLLER_EXTENSION_H +#define OPENXR_PICO_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRPicoControllerExtension : public OpenXRExtensionWrapper { +public: + virtual HashMap<String, bool *> get_requested_extensions() override; + + bool is_available(); + + virtual void on_register_metadata() override; + +private: + bool available = false; +}; + +#endif // OPENXR_PICO_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 550ed8052e..33b3c2967f 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -217,7 +217,7 @@ bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) { String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_extension(p_toplevel_path); // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error. - ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_toplevel_path); + ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported toplevel path " + p_toplevel_path); if (required_extension == "") { // no extension needed, core top level are always "supported", they just won't be used if not really supported diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 56c31883e6..4e2fe3dab5 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -53,6 +53,7 @@ #include "extensions/openxr_htc_vive_tracker_extension.h" #include "extensions/openxr_huawei_controller_extension.h" #include "extensions/openxr_palm_pose_extension.h" +#include "extensions/openxr_pico_controller_extension.h" #include "extensions/openxr_wmr_controller_extension.h" static OpenXRAPI *openxr_api = nullptr; @@ -92,6 +93,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { // register our other extensions OpenXRAPI::register_extension_wrapper(memnew(OpenXRPalmPoseExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRPicoControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension)); diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 49b4852cbf..43eb0f4b1f 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -1799,7 +1799,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p ERR_FAIL_COND_V(dylibs_dir.is_null(), ERR_CANT_OPEN); CodesignData codesign_data(p_preset, p_debug); err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); - ERR_FAIL_COND_V(err, err); + if (err != OK) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Code signing failed, see editor log for details.")); + return err; + } } if (ep.step("Making .xcarchive", 3)) { @@ -1825,6 +1828,10 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p err = OS::get_singleton()->execute("xcodebuild", archive_args, &archive_str, nullptr, true); ERR_FAIL_COND_V(err, err); print_line("xcodebuild (.xcarchive):\n" + archive_str); + if (!archive_str.contains("** ARCHIVE SUCCEEDED **")) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR("Xcode project build failed, see editor log for details.")); + return FAILED; + } if (ep.step("Making .ipa", 4)) { return ERR_SKIP; @@ -1841,9 +1848,14 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p String export_str; err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true); ERR_FAIL_COND_V(err, err); + print_line("xcodebuild (.ipa):\n" + export_str); + if (!export_str.contains("** EXPORT SUCCEEDED **")) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR(".ipa export failed, see editor log for details.")); + return FAILED; + } #else - print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package."); + add_message(EXPORT_MESSAGE_WARNING, TTR("Xcode Build"), TTR(".ipa can only be built on macOS. Leaving Xcode project without building the package.")); #endif return OK; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 680e4260e7..7539810feb 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -2899,6 +2899,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { const int caret_line = get_caret_line(); const int caret_column = get_caret_column(); const String line = get_line(caret_line); + ERR_FAIL_INDEX_MSG(caret_column - 1, line.length(), "Caret column exceeds line length."); if (caret_column > 0 && line[caret_column - 1] == '(' && !code_completion_forced) { cancel_code_completion(); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index c6bfe5742f..b5c587c0aa 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1131,11 +1131,11 @@ Error SceneTree::change_scene_to_file(const String &p_path) { } Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) { - Node *new_scene = nullptr; - if (p_scene.is_valid()) { - new_scene = p_scene->instantiate(); - ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); - } + ERR_FAIL_COND_V_MSG(p_scene.is_null(), ERR_INVALID_PARAMETER, "Can't change to a null scene. Use unload_current_scene() if you wish to unload it."); + + Node *new_scene = p_scene->instantiate(); + new_scene = p_scene->instantiate(); + ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); call_deferred(SNAME("_change_scene"), new_scene); return OK; @@ -1147,6 +1147,13 @@ Error SceneTree::reload_current_scene() { return change_scene_to_file(fname); } +void SceneTree::unload_current_scene() { + if (current_scene) { + memdelete(current_scene); + current_scene = nullptr; + } +} + void SceneTree::add_current_scene(Node *p_current) { current_scene = p_current; root->add_child(p_current); @@ -1297,6 +1304,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed); ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene); + ClassDB::bind_method(D_METHOD("unload_current_scene"), &SceneTree::unload_current_scene); ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 77cfe0a04a..fc185b4f37 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -361,6 +361,7 @@ public: Error change_scene_to_file(const String &p_path); Error change_scene_to_packed(const Ref<PackedScene> &p_scene); Error reload_current_scene(); + void unload_current_scene(); Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false); Ref<Tween> create_tween(); diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp index a174ceadac..2dbb59a323 100644 --- a/servers/extensions/physics_server_2d_extension.cpp +++ b/servers/extensions/physics_server_2d_extension.cpp @@ -37,6 +37,8 @@ bool PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query(const RID & thread_local const HashSet<RID> *PhysicsDirectSpaceState2DExtension::exclude = nullptr; void PhysicsDirectSpaceState2DExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_body_excluded_from_query", "body"), &PhysicsDirectSpaceState2DExtension::is_body_excluded_from_query); + GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "result"); GDVIRTUAL_BIND(_intersect_point, "position", "canvas_instance_id", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results"); GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result", "max_results"); @@ -203,6 +205,9 @@ void PhysicsServer2DExtension::_bind_methods() { /* BODY API */ + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_body", "body"), &PhysicsServer2DExtension::body_test_motion_is_excluding_body); + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_object", "object"), &PhysicsServer2DExtension::body_test_motion_is_excluding_object); + GDVIRTUAL_BIND(_body_create); GDVIRTUAL_BIND(_body_set_space, "body", "space"); diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 788ece721b..0d8476fd68 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -37,6 +37,8 @@ bool PhysicsDirectSpaceState3DExtension::is_body_excluded_from_query(const RID & thread_local const HashSet<RID> *PhysicsDirectSpaceState3DExtension::exclude = nullptr; void PhysicsDirectSpaceState3DExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_body_excluded_from_query", "body"), &PhysicsDirectSpaceState3DExtension::is_body_excluded_from_query); + GDVIRTUAL_BIND(_intersect_ray, "from", "to", "collision_mask", "collide_with_bodies", "collide_with_areas", "hit_from_inside", "hit_back_faces", "result"); GDVIRTUAL_BIND(_intersect_point, "position", "collision_mask", "collide_with_bodies", "collide_with_areas", "results", "max_results"); GDVIRTUAL_BIND(_intersect_shape, "shape_rid", "transform", "motion", "margin", "collision_mask", "collide_with_bodies", "collide_with_areas", "result_count", "max_results"); @@ -206,6 +208,9 @@ void PhysicsServer3DExtension::_bind_methods() { /* BODY API */ + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_body", "body"), &PhysicsServer3DExtension::body_test_motion_is_excluding_body); + ClassDB::bind_method(D_METHOD("body_test_motion_is_excluding_object", "object"), &PhysicsServer3DExtension::body_test_motion_is_excluding_object); + GDVIRTUAL_BIND(_body_create); GDVIRTUAL_BIND(_body_set_space, "body", "space"); |