diff options
33 files changed, 259 insertions, 280 deletions
diff --git a/SConstruct b/SConstruct index f6c3b33fc6..ff1eba681d 100644 --- a/SConstruct +++ b/SConstruct @@ -475,7 +475,7 @@ if methods.get_cmdline_bool("fast_unsafe", env_base.dev_build): if env_base["use_precise_math_checks"]: env_base.Append(CPPDEFINES=["PRECISE_MATH_CHECKS"]) -if env_base["engine_update_check"]: +if env_base.editor_build and env_base["engine_update_check"]: env_base.Append(CPPDEFINES=["ENGINE_UPDATE_CHECK_ENABLED"]) if not env_base.File("#main/splash_editor.png").exists(): diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index c9493be4ef..18dbac991c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -794,11 +794,11 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA); builtin_type = (Variant::Type)bt; - ERR_FAIL_COND_V(!p_allow_objects && builtin_type == Variant::OBJECT, ERR_UNAUTHORIZED); + if (!p_allow_objects && builtin_type == Variant::OBJECT) { + class_name = EncodedObjectAsID::get_class_static(); + } } break; case HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME: { - ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); - String str; Error err = _decode_string(buf, len, r_len, str); if (err) { @@ -806,22 +806,28 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } builtin_type = Variant::OBJECT; - class_name = str; + if (p_allow_objects) { + class_name = str; + } else { + class_name = EncodedObjectAsID::get_class_static(); + } } break; case HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT: { - ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); - String path; Error err = _decode_string(buf, len, r_len, path); if (err) { return err; } - ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); - script = ResourceLoader::load(path, "Script"); - ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); builtin_type = Variant::OBJECT; - class_name = script->get_instance_base_type(); + if (p_allow_objects) { + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + script = ResourceLoader::load(path, "Script"); + ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); + class_name = script->get_instance_base_type(); + } else { + class_name = EncodedObjectAsID::get_class_static(); + } } break; default: ERR_FAIL_V(ERR_INVALID_DATA); // Future proofing. @@ -1243,13 +1249,10 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo if (array.is_typed()) { Ref<Script> script = array.get_typed_script(); if (script.is_valid()) { - ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE); header |= HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT; } else if (array.get_typed_class_name() != StringName()) { - ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE); header |= HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME; } else { - ERR_FAIL_COND_V(!p_full_objects && array.get_typed_builtin() == Variant::OBJECT, ERR_UNAVAILABLE); header |= HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN; } } diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index 6b9c0bcc76..4052e48400 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -190,7 +190,7 @@ <method name="get_line" qualifiers="const"> <return type="String" /> <description> - Returns the next line of the file as a [String]. + Returns the next line of the file as a [String]. The returned string doesn't include newline ([code]\n[/code]) or carriage return ([code]\r[/code]) characters, but does include any other leading or trailing whitespace. Text is interpreted as being UTF-8 encoded. </description> </method> diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index c490620fc0..31ce1dba4a 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -23,13 +23,6 @@ Bakes the [NavigationPolygon]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread. </description> </method> - <method name="get_avoidance_layer_value" qualifiers="const"> - <return type="bool" /> - <param index="0" name="layer_number" type="int" /> - <description> - Returns whether or not the specified layer of the [member avoidance_layers] bitmask is enabled, given a [param layer_number] between 1 and 32. - </description> - </method> <method name="get_navigation_layer_value" qualifiers="const"> <return type="bool" /> <param index="0" name="layer_number" type="int" /> @@ -61,14 +54,6 @@ Returns [code]true[/code] when the [NavigationPolygon] is being baked on a background thread. </description> </method> - <method name="set_avoidance_layer_value"> - <return type="void" /> - <param index="0" name="layer_number" type="int" /> - <param index="1" name="value" type="bool" /> - <description> - Based on [param value], enables or disables the specified layer in the [member avoidance_layers] bitmask, given a [param layer_number] between 1 and 32. - </description> - </method> <method name="set_navigation_layer_value"> <return type="void" /> <param index="0" name="layer_number" type="int" /> @@ -86,12 +71,6 @@ </method> </methods> <members> - <member name="avoidance_layers" type="int" setter="set_avoidance_layers" getter="get_avoidance_layers" default="1"> - A bitfield determining all avoidance layers for the avoidance constrain. - </member> - <member name="constrain_avoidance" type="bool" setter="set_constrain_avoidance" getter="get_constrain_avoidance" default="false" experimental="When enabled, agents are known to get stuck on the navigation polygon corners and edges, especially at a high frame rate. Not recommended for use in production at this stage."> - If [code]true[/code] constraints avoidance agent's with an avoidance mask bit that matches with a bit of the [member avoidance_layers] to the navigation polygon. Due to each navigation polygon outline creating an obstacle and each polygon edge creating an avoidance line constrain keep the navigation polygon shape as simple as possible for performance. - </member> <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true"> Determines if the [NavigationRegion2D] is enabled or disabled. </member> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 015d16291b..1daa1b04e4 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -488,6 +488,9 @@ <member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true"> If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings. </member> + <member name="debug/gdscript/warnings/enum_variable_without_default" type="int" setter="" getter="" default="1"> + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a variable has an enum type but no explicit default value, but only if the enum does not contain [code]0[/code] as a valid value. + </member> <member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true"> If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings. </member> diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml index 2c88ecd675..43ee4dda60 100644 --- a/doc/classes/ScriptEditor.xml +++ b/doc/classes/ScriptEditor.xml @@ -34,6 +34,35 @@ Returns an array with all [Script] objects which are currently open in editor. </description> </method> + <method name="goto_help"> + <return type="void" /> + <param index="0" name="topic" type="String" /> + <description> + Opens help for the given topic. The [param topic] is an encoded string that controls which class, method, constant, signal, annotation, property, or theme item should be focused. + The supported [param topic] formats include [code]class_name:class[/code], [code]class_method:class:method[/code], [code]class_constant:class:constant[/code], [code]class_signal:class:signal[/code], [code]class_annotation:class:@annotation[/code], [code]class_property:class:property[/code], and [code]class_theme_item:class:item[/code], where [code]class[/code] is the class name, [code]method[/code] is the method name, [code]constant[/code] is the constant name, [code]signal[/code] is the signal name, [code]annotation[/code] is the annotation name, [code]property[/code] is the property name, and [code]item[/code] is the theme item. + [b]Examples:[/b] + [codeblock] + # Shows help for the Node class. + class_name:Node + # Shows help for the global min function. + # Global objects are accessible in the `@GlobalScope` namespace, shown here. + class_method:@GlobalScope:min + # Shows help for get_viewport in the Node class. + class_method:Node:get_viewport + # Shows help for the Input constant MOUSE_BUTTON_MIDDLE. + class_constant:Input:MOUSE_BUTTON_MIDDLE + # Shows help for the BaseButton signal pressed. + class_signal:BaseButton:pressed + # Shows help for the CanvasItem property visible. + class_property:CanvasItem:visible + # Shows help for the GDScript annotation export. + # Annotations should be prefixed with the `@` symbol in the descriptor, as shown here. + class_annotation:@GDScript:@export + # Shows help for the GraphNode theme item named panel_selected. + class_theme_item:GraphNode:panel_selected + [/codeblock] + </description> + </method> <method name="goto_line"> <return type="void" /> <param index="0" name="line_number" type="int" /> diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 7919d61f26..aed1462eb6 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3220,12 +3220,13 @@ void EditorInspector::update_tree() { } // Search for the doc path in the cache. - HashMap<StringName, HashMap<StringName, String>>::Iterator E = doc_path_cache.find(classname); + HashMap<StringName, HashMap<StringName, DocCacheInfo>>::Iterator E = doc_cache.find(classname); if (E) { - HashMap<StringName, String>::Iterator F = E->value.find(propname); + HashMap<StringName, DocCacheInfo>::Iterator F = E->value.find(propname); if (F) { found = true; - doc_path = F->value; + doc_path = F->value.doc_path; + theme_item_name = F->value.theme_item_name; } } @@ -3246,23 +3247,22 @@ void EditorInspector::update_tree() { theme_item_name = F->value.theme_properties[i].name; } } - - if (is_native_class) { - doc_path_cache[classname][propname] = doc_path; - } } else { for (int i = 0; i < F->value.properties.size(); i++) { String doc_path_current = "class_property:" + F->value.name + ":" + F->value.properties[i].name; if (F->value.properties[i].name == propname.operator String()) { doc_path = doc_path_current; } - - if (is_native_class) { - doc_path_cache[classname][propname] = doc_path; - } } } + if (is_native_class) { + DocCacheInfo cache_info; + cache_info.doc_path = doc_path; + cache_info.theme_item_name = theme_item_name; + doc_cache[classname][propname] = cache_info; + } + if (!doc_path.is_empty() || F->value.inherits.is_empty()) { break; } diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 8c55950a2b..eff4f9caa5 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -505,7 +505,12 @@ class EditorInspector : public ScrollContainer { int property_focusable; int update_scroll_request; - HashMap<StringName, HashMap<StringName, String>> doc_path_cache; + struct DocCacheInfo { + String doc_path; + String theme_item_name; + }; + + HashMap<StringName, HashMap<StringName, DocCacheInfo>> doc_cache; HashSet<StringName> restart_request_props; HashMap<String, String> custom_property_descriptions; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e5ef888370..20fa30ff34 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3841,6 +3841,8 @@ void EditorNode::_set_current_scene_nocheck(int p_idx) { if (tabs_to_close.is_empty()) { callable_mp(this, &EditorNode::_set_main_scene_state).call_deferred(state, get_edited_scene()); // Do after everything else is done setting up. } + + _update_undo_redo_allowed(); } void EditorNode::setup_color_picker(ColorPicker *p_picker) { @@ -3926,14 +3928,18 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b } int prev = editor_data.get_edited_scene(); - int idx = editor_data.add_edited_scene(-1); + int idx = prev; - if (!editor_data.get_edited_scene_root() && editor_data.get_edited_scene_count() == 2) { - _remove_edited_scene(); - } else if (p_silent_change_tab) { - _set_current_scene_nocheck(idx); + if (prev == -1 || editor_data.get_edited_scene_root() || !editor_data.get_scene_path(prev).is_empty()) { + idx = editor_data.add_edited_scene(-1); + + if (p_silent_change_tab) { + _set_current_scene_nocheck(idx); + } else { + _set_current_scene(idx); + } } else { - _set_current_scene(idx); + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id()); } dependency_errors.clear(); @@ -3950,7 +3956,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b dependency_error->show(DependencyErrorDialog::MODE_SCENE, lpath, errors); opening_prev = false; - if (prev != -1) { + if (prev != -1 && prev != idx) { _set_current_scene(prev); editor_data.remove_scene(idx); } @@ -3961,7 +3967,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b _dialog_display_load_error(lpath, err); opening_prev = false; - if (prev != -1) { + if (prev != -1 && prev != idx) { _set_current_scene(prev); editor_data.remove_scene(idx); } @@ -3997,7 +4003,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b sdata.unref(); _dialog_display_load_error(lpath, ERR_FILE_CORRUPT); opening_prev = false; - if (prev != -1) { + if (prev != -1 && prev != idx) { _set_current_scene(prev); editor_data.remove_scene(idx); } @@ -4023,10 +4029,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b _load_editor_plugin_states_from_config(editor_state_cf); } - _update_title(); - scene_tabs->update_scene_tabs(); - _add_to_recent_scenes(lpath); - if (editor_folding.has_folding_data(lpath)) { editor_folding.load_scene_folding(new_scene, lpath); } else if (EDITOR_GET("interface/inspector/auto_unfold_foreign_scenes")) { @@ -4066,6 +4068,14 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b save_editor_layout_delayed(); } + if (p_set_inherited) { + EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(editor_data.get_current_edited_scene_history_id()); + } + + _update_title(); + scene_tabs->update_scene_tabs(); + _add_to_recent_scenes(lpath); + return OK; } diff --git a/editor/gui/editor_scene_tabs.cpp b/editor/gui/editor_scene_tabs.cpp index b6cb3d7371..5d1e68f008 100644 --- a/editor/gui/editor_scene_tabs.cpp +++ b/editor/gui/editor_scene_tabs.cpp @@ -135,6 +135,17 @@ void EditorSceneTabs::_scene_tab_input(const Ref<InputEvent> &p_input) { } } +void EditorSceneTabs::unhandled_key_input(const Ref<InputEvent> &p_event) { + if (!tab_preview_panel->is_visible()) { + return; + } + + Ref<InputEventKey> k = p_event; + if (k.is_valid() && k->is_action_pressed(SNAME("ui_cancel"), false, true)) { + tab_preview_panel->hide(); + } +} + void EditorSceneTabs::_reposition_active_tab(int p_to_index) { EditorNode::get_editor_data().move_edited_scene_to_index(p_to_index); update_scene_tabs(); @@ -369,6 +380,7 @@ EditorSceneTabs::EditorSceneTabs() { singleton = this; set_process_shortcut_input(true); + set_process_unhandled_key_input(true); tabbar_panel = memnew(PanelContainer); add_child(tabbar_panel); diff --git a/editor/gui/editor_scene_tabs.h b/editor/gui/editor_scene_tabs.h index 770114835a..ac9e6b8c43 100644 --- a/editor/gui/editor_scene_tabs.h +++ b/editor/gui/editor_scene_tabs.h @@ -79,6 +79,7 @@ class EditorSceneTabs : public MarginContainer { protected: void _notification(int p_what); + virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; static void _bind_methods(); public: diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 8d24e90cce..8a9118a03e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5860,13 +5860,34 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons } void CanvasItemEditorViewport::_perform_drop_data() { + ERR_FAIL_COND(selected_files.size() <= 0); + _remove_preview(); - // Without root dropping multiple files is not allowed - if (!target_node && selected_files.size() > 1) { - accept->set_text(TTR("Cannot instantiate multiple nodes without root.")); - accept->popup_centered(); - return; + if (!target_node) { + // Without root dropping multiple files is not allowed + if (selected_files.size() > 1) { + accept->set_text(TTR("Cannot instantiate multiple nodes without root.")); + accept->popup_centered(); + return; + } + + const String &path = selected_files[0]; + Ref<Resource> res = ResourceLoader::load(path); + if (res.is_null()) { + return; + } + + Ref<PackedScene> scene = res; + if (scene.is_valid()) { + // Without root node act the same as "Load Inherited Scene". + Error err = EditorNode::get_singleton()->load_scene(path, false, true); + if (err != OK) { + accept->set_text(vformat(TTR("Error instantiating scene from %s."), path.get_file())); + accept->popup_centered(); + } + return; + } } PackedStringArray error_files; @@ -5882,27 +5903,21 @@ void CanvasItemEditorViewport::_perform_drop_data() { if (res.is_null()) { continue; } - Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - if (scene != nullptr && scene.is_valid()) { - if (!target_node) { - // Without root node act the same as "Load Inherited Scene" - Error err = EditorNode::get_singleton()->load_scene(path, false, true); - if (err != OK) { - error_files.push_back(path.get_file()); - } - } else { - bool success = _create_instance(target_node, path, drop_pos); - if (!success) { - error_files.push_back(path.get_file()); - } - } - } else { - Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); - if (texture != nullptr && texture.is_valid()) { - Node *child = Object::cast_to<Node>(ClassDB::instantiate(default_texture_node_type)); - _create_nodes(target_node, child, path, drop_pos); - undo_redo->add_do_method(editor_selection, "add_node", child); + + Ref<PackedScene> scene = res; + if (scene.is_valid()) { + bool success = _create_instance(target_node, path, drop_pos); + if (!success) { + error_files.push_back(path.get_file()); } + continue; + } + + Ref<Texture2D> texture = res; + if (texture.is_valid()) { + Node *child = Object::cast_to<Node>(ClassDB::instantiate(default_texture_node_type)); + _create_nodes(target_node, child, path, drop_pos); + undo_redo->add_do_method(editor_selection, "add_node", child); } } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 6c63d9ff0d..c832570fee 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3886,6 +3886,8 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); ClassDB::bind_method(D_METHOD("open_script_create_dialog", "base_name", "base_path"), &ScriptEditor::open_script_create_dialog); + ClassDB::bind_method(D_METHOD("goto_help", "topic"), &ScriptEditor::goto_help); + ADD_SIGNAL(MethodInfo("editor_script_changed", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script"))); ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script"))); } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index f9efc62f03..1da2f89c1c 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -1838,7 +1838,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i tile_size = tile_set_atlas_source->get_texture_region_size(); Vector2i origin = margins + (area.position * (tile_size + separation)); - TilesEditorUtils::draw_selection_rect(tile_atlas_control, Rect2i(origin, area.size * tile_size)); + Vector2i size = area.size * tile_size + (area.size - Vector2i(1, 1)).max(Vector2i(0, 0)) * separation; + TilesEditorUtils::draw_selection_rect(tile_atlas_control, Rect2i(origin, size)); } else { Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); if (hovered_base_tile_coords.x >= 0 && hovered_base_tile_coords.y >= 0 && hovered_base_tile_coords.x < grid_size.x && hovered_base_tile_coords.y < grid_size.y) { diff --git a/main/main.cpp b/main/main.cpp index a1031b5385..ed74094c9e 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -697,7 +697,9 @@ Error Main::test_setup() { /** INITIALIZE SERVERS **/ register_server_types(); +#ifndef _3D_DISABLED XRServer::set_xr_mode(XRServer::XRMODE_OFF); // Skip in tests. +#endif // _3D_DISABLED initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS); diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index e8195d0aa0..6471c5a142 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -263,9 +263,6 @@ Removed VisualShaderNodeComment, which is replaced by VisualShaderNodeFrame. GH-87888 -------- -Validate extension JSON: API was removed: classes/OpenXRHand/methods/get_hand_skeleton -Validate extension JSON: API was removed: classes/OpenXRHand/methods/set_hand_skeleton -Validate extension JSON: API was removed: classes/OpenXRHand/properties/hand_skeleton Validate extension JSON: API was removed: classes/Skeleton3D/properties/animate_physical_bones Validate extension JSON: API was removed: classes/SkeletonIK3D/methods/get_interpolation Validate extension JSON: API was removed: classes/SkeletonIK3D/methods/set_interpolation @@ -280,3 +277,16 @@ Validate extension JSON: API was removed: classes/BoneAttachment3D/methods/on_bo Validate extension JSON: API was removed: classes/Skeleton3D/signals/bone_pose_changed They have been replaced by a safer API due to performance concerns. Compatibility method registered. + +GH-90747 +-------- +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get_avoidance_layers +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/set_avoidance_layers +Validate extension JSON: API was removed: classes/NavigationRegion2D/properties/avoidance_layers +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get_avoidance_layer_value +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/set_avoidance_layer_value +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/set_constrain_avoidance +Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get_constrain_avoidance +Validate extension JSON: API was removed: classes/NavigationRegion2D/properties/constrain_avoidance + +Experimental NavigationRegion2D feature "constrain_avoidance" was discontinued with no replacement. diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index b198338ff0..cd19887d82 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1957,6 +1957,18 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi } else { parser->push_warning(p_assignable, GDScriptWarning::UNTYPED_DECLARATION, declaration_type, p_assignable->identifier->name); } + } else if (specified_type.kind == GDScriptParser::DataType::ENUM && p_assignable->initializer == nullptr) { + // Warn about enum variables without default value. Unless the enum defines the "0" value, then it's fine. + bool has_zero_value = false; + for (const KeyValue<StringName, int64_t> &kv : specified_type.enum_values) { + if (kv.value == 0) { + has_zero_value = true; + break; + } + } + if (!has_zero_value) { + parser->push_warning(p_assignable, GDScriptWarning::ENUM_VARIABLE_WITHOUT_DEFAULT, p_assignable->identifier->name); + } } #endif diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 708966a0a8..48a0abe617 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -126,6 +126,9 @@ String GDScriptWarning::get_message() const { case INT_AS_ENUM_WITHOUT_MATCH: CHECK_SYMBOLS(3); return vformat(R"(Cannot %s %s as Enum "%s": no enum member has matching value.)", symbols[0], symbols[1], symbols[2]); + case ENUM_VARIABLE_WITHOUT_DEFAULT: + CHECK_SYMBOLS(1); + return vformat(R"(The variable "%s" has an enum type and does not set an explicit default value. The default will be set to "0".)", symbols[0]); case EMPTY_FILE: return "Empty script file."; case DEPRECATED_KEYWORD: @@ -221,6 +224,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "NARROWING_CONVERSION", "INT_AS_ENUM_WITHOUT_CAST", "INT_AS_ENUM_WITHOUT_MATCH", + "ENUM_VARIABLE_WITHOUT_DEFAULT", "EMPTY_FILE", "DEPRECATED_KEYWORD", "RENAMED_IN_GODOT_4_HINT", diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 93c232a0f8..3ad9488138 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -78,6 +78,7 @@ public: NARROWING_CONVERSION, // Float value into an integer slot, precision is lost. INT_AS_ENUM_WITHOUT_CAST, // An integer value was used as an enum value without casting. INT_AS_ENUM_WITHOUT_MATCH, // An integer value was used as an enum value without matching enum member. + ENUM_VARIABLE_WITHOUT_DEFAULT, // A variable with an enum type does not have a default value. The default will be set to `0` instead of the first enum value. EMPTY_FILE, // A script file is empty. DEPRECATED_KEYWORD, // The keyword is deprecated and should be replaced. RENAMED_IN_GODOT_4_HINT, // A variable or function that could not be found has been renamed in Godot 4. @@ -129,6 +130,7 @@ public: WARN, // NARROWING_CONVERSION WARN, // INT_AS_ENUM_WITHOUT_CAST WARN, // INT_AS_ENUM_WITHOUT_MATCH + WARN, // ENUM_VARIABLE_WITHOUT_DEFAULT WARN, // EMPTY_FILE WARN, // DEPRECATED_KEYWORD WARN, // RENAMED_IN_GODOT_4_HINT diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.gd b/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.gd new file mode 100644 index 0000000000..13e3edf93f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.gd @@ -0,0 +1,9 @@ +enum HasZero { A = 0, B = 1 } +enum HasNoZero { A = 1, B = 2 } +var has_zero: HasZero # No warning, because the default `0` is valid. +var has_no_zero: HasNoZero # Warning, because there is no `0` in the enum. + + +func test(): + print(has_zero) + print(has_no_zero) diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.out b/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.out new file mode 100644 index 0000000000..ae40e0bc8c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/warnings/enum_without_default_value.out @@ -0,0 +1,7 @@ +GDTEST_OK +>> WARNING +>> Line: 4 +>> ENUM_VARIABLE_WITHOUT_DEFAULT +>> The variable "has_no_zero" has an enum type and does not set an explicit default value. The default will be set to "0". +0 +0 diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd index d7485f49e6..42b29eee43 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.gd +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd @@ -23,6 +23,7 @@ var test_var_hard_int: int var test_var_hard_variant_type: Variant.Type @export var test_var_hard_variant_type_exported: Variant.Type var test_var_hard_node_process_mode: Node.ProcessMode +@warning_ignore("enum_variable_without_default") var test_var_hard_my_enum: MyEnum var test_var_hard_array: Array var test_var_hard_array_int: Array[int] diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml index 9cc548dd6f..23d932ddd7 100644 --- a/modules/openxr/doc_classes/OpenXRHand.xml +++ b/modules/openxr/doc_classes/OpenXRHand.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="OpenXRHand" inherits="SkeletonModifier3D" deprecated="Use [XRHandModifier3D] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="OpenXRHand" inherits="Node3D" deprecated="Use [XRHandModifier3D] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> Node supporting hand and finger tracking in OpenXR. </brief_description> @@ -18,11 +18,14 @@ <member name="hand" type="int" setter="set_hand" getter="get_hand" enum="OpenXRHand.Hands" default="0"> Specifies whether this node tracks the left or right hand of the player. </member> + <member name="hand_skeleton" type="NodePath" setter="set_hand_skeleton" getter="get_hand_skeleton" default="NodePath("")"> + Set a [Skeleton3D] node for which the pose positions will be updated. + </member> <member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0"> Set the motion range (if supported) limiting the hand motion. </member> <member name="skeleton_rig" type="int" setter="set_skeleton_rig" getter="get_skeleton_rig" enum="OpenXRHand.SkeletonRig" default="0"> - Set the type of skeleton rig the parent [Skeleton3D] is compliant with. + Set the type of skeleton rig the [member hand_skeleton] is compliant with. </member> </members> <constants> diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp index f20d1f8e19..2a4104f6ee 100644 --- a/modules/openxr/scene/openxr_hand.cpp +++ b/modules/openxr/scene/openxr_hand.cpp @@ -40,6 +40,9 @@ void OpenXRHand::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand", "hand"), &OpenXRHand::set_hand); ClassDB::bind_method(D_METHOD("get_hand"), &OpenXRHand::get_hand); + ClassDB::bind_method(D_METHOD("set_hand_skeleton", "hand_skeleton"), &OpenXRHand::set_hand_skeleton); + ClassDB::bind_method(D_METHOD("get_hand_skeleton"), &OpenXRHand::get_hand_skeleton); + ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range); ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range); @@ -51,6 +54,7 @@ void OpenXRHand::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton"); ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton_rig", PROPERTY_HINT_ENUM, "OpenXR,Humanoid"), "set_skeleton_rig", "get_skeleton_rig"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); @@ -86,6 +90,12 @@ OpenXRHand::Hands OpenXRHand::get_hand() const { return hand; } +void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) { + hand_skeleton = p_hand_skeleton; + + // TODO if inside tree call _get_bones() +} + void OpenXRHand::set_motion_range(MotionRange p_motion_range) { ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX); motion_range = p_motion_range; @@ -97,6 +107,10 @@ OpenXRHand::MotionRange OpenXRHand::get_motion_range() const { return motion_range; } +NodePath OpenXRHand::get_hand_skeleton() const { + return hand_skeleton; +} + void OpenXRHand::_set_motion_range() { if (!hand_tracking_ext) { return; @@ -138,6 +152,20 @@ OpenXRHand::BoneUpdate OpenXRHand::get_bone_update() const { return bone_update; } +Skeleton3D *OpenXRHand::get_skeleton() { + if (!has_node(hand_skeleton)) { + return nullptr; + } + + Node *node = get_node(hand_skeleton); + if (!node) { + return nullptr; + } + + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + return skeleton; +} + void OpenXRHand::_get_joint_data() { // Table of bone names for different rig types. static const String bone_names[SKELETON_RIG_MAX][XR_HAND_JOINT_COUNT_EXT] = { @@ -262,7 +290,7 @@ void OpenXRHand::_get_joint_data() { } } -void OpenXRHand::_process_modification() { +void OpenXRHand::_update_skeleton() { if (openxr_api == nullptr || !openxr_api->is_initialized()) { return; } else if (hand_tracking_ext == nullptr || !hand_tracking_ext->get_active()) { @@ -367,14 +395,21 @@ void OpenXRHand::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _get_joint_data(); + + set_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { + set_process_internal(false); + // reset for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) { joints[i].bone = -1; joints[i].parent_joint = -1; } } break; + case NOTIFICATION_INTERNAL_PROCESS: { + _update_skeleton(); + } break; default: { } break; } diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h index fc0a994f48..4c77e7277c 100644 --- a/modules/openxr/scene/openxr_hand.h +++ b/modules/openxr/scene/openxr_hand.h @@ -31,15 +31,16 @@ #ifndef OPENXR_HAND_H #define OPENXR_HAND_H -#include "scene/3d/skeleton_modifier_3d.h" +#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_3d.h" #include <openxr/openxr.h> class OpenXRAPI; class OpenXRHandTrackingExtension; -class OpenXRHand : public SkeletonModifier3D { - GDCLASS(OpenXRHand, SkeletonModifier3D); +class OpenXRHand : public Node3D { + GDCLASS(OpenXRHand, Node3D); public: enum Hands { // Deprecated, need to change this to OpenXRInterface::Hands. @@ -85,13 +86,13 @@ private: void _set_motion_range(); + Skeleton3D *get_skeleton(); void _get_joint_data(); + void _update_skeleton(); protected: static void _bind_methods(); - virtual void _process_modification() override; - public: OpenXRHand(); @@ -101,6 +102,9 @@ public: void set_motion_range(MotionRange p_motion_range); MotionRange get_motion_range() const; + void set_hand_skeleton(const NodePath &p_hand_skeleton); + NodePath get_hand_skeleton() const; + void set_skeleton_rig(SkeletonRig p_skeleton_rig); SkeletonRig get_skeleton_rig() const; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 5510b59903..ab44e57d05 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -31,7 +31,6 @@ #include "navigation_region_2d.h" #include "core/math/geometry_2d.h" -#include "scene/2d/navigation_obstacle_2d.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" @@ -212,11 +211,6 @@ void NavigationRegion2D::set_navigation_map(RID p_navigation_map) { map_override = p_navigation_map; NavigationServer2D::get_singleton()->region_set_map(region, map_override); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override); - } - } } RID NavigationRegion2D::get_navigation_map() const { @@ -265,7 +259,6 @@ void NavigationRegion2D::_navigation_polygon_changed() { if (navigation_polygon.is_valid()) { NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon); } - _update_avoidance_constrain(); } #ifdef DEBUG_ENABLED @@ -317,13 +310,6 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationRegion2D::set_navigation_layer_value); ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationRegion2D::get_navigation_layer_value); - ClassDB::bind_method(D_METHOD("set_constrain_avoidance", "enabled"), &NavigationRegion2D::set_constrain_avoidance); - ClassDB::bind_method(D_METHOD("get_constrain_avoidance"), &NavigationRegion2D::get_constrain_avoidance); - ClassDB::bind_method(D_METHOD("set_avoidance_layers", "layers"), &NavigationRegion2D::set_avoidance_layers); - ClassDB::bind_method(D_METHOD("get_avoidance_layers"), &NavigationRegion2D::get_avoidance_layers); - ClassDB::bind_method(D_METHOD("set_avoidance_layer_value", "layer_number", "value"), &NavigationRegion2D::set_avoidance_layer_value); - ClassDB::bind_method(D_METHOD("get_avoidance_layer_value", "layer_number"), &NavigationRegion2D::get_avoidance_layer_value); - ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid); ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost); @@ -343,8 +329,6 @@ void NavigationRegion2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constrain_avoidance"), "set_constrain_avoidance", "get_constrain_avoidance"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "avoidance_layers", PROPERTY_HINT_LAYERS_AVOIDANCE), "set_avoidance_layers", "get_avoidance_layers"); ADD_SIGNAL(MethodInfo("navigation_polygon_changed")); ADD_SIGNAL(MethodInfo("bake_finished")); @@ -391,131 +375,12 @@ NavigationRegion2D::~NavigationRegion2D() { ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D::get_singleton()->free(region); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->free(constrain_avoidance_obstacles[i]); - } - } - constrain_avoidance_obstacles.clear(); - #ifdef DEBUG_ENABLED NavigationServer2D::get_singleton()->disconnect(SNAME("map_changed"), callable_mp(this, &NavigationRegion2D::_navigation_map_changed)); NavigationServer2D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationRegion2D::_navigation_debug_changed)); #endif // DEBUG_ENABLED } -void NavigationRegion2D::_update_avoidance_constrain() { - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->free(constrain_avoidance_obstacles[i]); - constrain_avoidance_obstacles[i] = RID(); - } - } - constrain_avoidance_obstacles.clear(); - - if (!constrain_avoidance) { - return; - } - - if (get_navigation_polygon() == nullptr) { - return; - } - - Ref<NavigationPolygon> _navpoly = get_navigation_polygon(); - int _outline_count = _navpoly->get_outline_count(); - if (_outline_count == 0) { - return; - } - - for (int outline_index(0); outline_index < _outline_count; outline_index++) { - const Vector<Vector2> &_outline = _navpoly->get_outline(outline_index); - - const int outline_size = _outline.size(); - if (outline_size < 3) { - ERR_FAIL_COND_MSG(_outline.size() < 3, "NavigationPolygon outline needs to have at least 3 vertex to create avoidance obstacles to constrain avoidance agent's"); - continue; - } - - RID obstacle_rid = NavigationServer2D::get_singleton()->obstacle_create(); - constrain_avoidance_obstacles.push_back(obstacle_rid); - - Vector<Vector2> new_obstacle_outline; - - if (outline_index == 0) { - for (int i(0); i < outline_size; i++) { - new_obstacle_outline.push_back(_outline[outline_size - i - 1]); - } - ERR_FAIL_COND_MSG(Geometry2D::is_polygon_clockwise(_outline), "Outer most outline needs to be clockwise to push avoidance agent inside"); - } else { - for (int i(0); i < outline_size; i++) { - new_obstacle_outline.push_back(_outline[i]); - } - } - new_obstacle_outline.resize(outline_size); - - NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle_rid, new_obstacle_outline); - NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle_rid, avoidance_layers); - if (is_inside_tree()) { - if (map_override.is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, map_override); - } else { - NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, get_world_2d()->get_navigation_map()); - } - NavigationServer2D::get_singleton()->obstacle_set_position(obstacle_rid, get_global_position()); - } - } - constrain_avoidance_obstacles.resize(_outline_count); -} - -void NavigationRegion2D::set_constrain_avoidance(bool p_enabled) { - constrain_avoidance = p_enabled; - _update_avoidance_constrain(); - notify_property_list_changed(); -} - -bool NavigationRegion2D::get_constrain_avoidance() const { - return constrain_avoidance; -} - -void NavigationRegion2D::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "avoidance_layers") { - if (!constrain_avoidance) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } -} - -void NavigationRegion2D::set_avoidance_layers(uint32_t p_layers) { - avoidance_layers = p_layers; - if (constrain_avoidance_obstacles.size() > 0) { - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(constrain_avoidance_obstacles[i], avoidance_layers); - } - } -} - -uint32_t NavigationRegion2D::get_avoidance_layers() const { - return avoidance_layers; -} - -void NavigationRegion2D::set_avoidance_layer_value(int p_layer_number, bool p_value) { - ERR_FAIL_COND_MSG(p_layer_number < 1, "Avoidance layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_MSG(p_layer_number > 32, "Avoidance layer number must be between 1 and 32 inclusive."); - uint32_t avoidance_layers_new = get_avoidance_layers(); - if (p_value) { - avoidance_layers_new |= 1 << (p_layer_number - 1); - } else { - avoidance_layers_new &= ~(1 << (p_layer_number - 1)); - } - set_avoidance_layers(avoidance_layers_new); -} - -bool NavigationRegion2D::get_avoidance_layer_value(int p_layer_number) const { - ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Avoidance layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Avoidance layer number must be between 1 and 32 inclusive."); - return get_avoidance_layers() & (1 << (p_layer_number - 1)); -} - void NavigationRegion2D::_region_enter_navigation_map() { if (!is_inside_tree()) { return; @@ -523,27 +388,12 @@ void NavigationRegion2D::_region_enter_navigation_map() { if (map_override.is_valid()) { NavigationServer2D::get_singleton()->region_set_map(region, map_override); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override); - } - } } else { NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map()); - } - } } current_global_transform = get_global_transform(); NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); - } - } NavigationServer2D::get_singleton()->region_set_enabled(region, enabled); @@ -552,11 +402,6 @@ void NavigationRegion2D::_region_enter_navigation_map() { void NavigationRegion2D::_region_exit_navigation_map() { NavigationServer2D::get_singleton()->region_set_map(region, RID()); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID()); - } - } } void NavigationRegion2D::_region_update_transform() { @@ -568,11 +413,6 @@ void NavigationRegion2D::_region_update_transform() { if (current_global_transform != new_global_transform) { current_global_transform = new_global_transform; NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); - } - } } queue_redraw(); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 1482617a64..5a86dd607d 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -46,10 +46,6 @@ class NavigationRegion2D : public Node2D { real_t travel_cost = 1.0; Ref<NavigationPolygon> navigation_polygon; - bool constrain_avoidance = false; - LocalVector<RID> constrain_avoidance_obstacles; - uint32_t avoidance_layers = 1; - Transform2D current_global_transform; void _navigation_polygon_changed(); @@ -65,7 +61,6 @@ private: protected: void _notification(int p_what); - void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); #ifndef DISABLE_DEPRECATED @@ -106,15 +101,6 @@ public: void set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon); Ref<NavigationPolygon> get_navigation_polygon() const; - void set_constrain_avoidance(bool p_enabled); - bool get_constrain_avoidance() const; - - void set_avoidance_layers(uint32_t p_layers); - uint32_t get_avoidance_layers() const; - - void set_avoidance_layer_value(int p_layer_number, bool p_value); - bool get_avoidance_layer_value(int p_layer_number) const; - PackedStringArray get_configuration_warnings() const override; void bake_navigation_polygon(bool p_on_thread); @@ -125,7 +111,6 @@ public: ~NavigationRegion2D(); private: - void _update_avoidance_constrain(); void _region_enter_navigation_map(); void _region_exit_navigation_map(); void _region_update_transform(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index bbf1d09bbc..84d3a5f7fa 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -429,6 +429,7 @@ Color TileMap::get_layer_modulate(int p_layer) const { void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) { TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_enabled, p_y_sort_enabled); + update_configuration_warnings(); } bool TileMap::is_layer_y_sort_enabled(int p_layer) const { @@ -437,6 +438,7 @@ bool TileMap::is_layer_y_sort_enabled(int p_layer) const { void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) { TILEMAP_CALL_FOR_LAYER(p_layer, set_y_sort_origin, p_y_sort_origin); + update_configuration_warnings(); } int TileMap::get_layer_y_sort_origin(int p_layer) const { @@ -518,9 +520,6 @@ void TileMap::set_y_sort_enabled(bool p_enable) { return; } Node2D::set_y_sort_enabled(p_enable); - for (TileMapLayer *layer : layers) { - layer->set_y_sort_enabled(p_enable); - } _emit_changed(); update_configuration_warnings(); } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 56346f5edc..b6dd3ac0b4 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -640,11 +640,17 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) { for (const Rect2 &E : autohide_areas) { if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E.has_point(m->get_position())) { + // The mouse left the safe area, prepare to close. _close_pressed(); return; } } + if (!minimum_lifetime_timer->is_stopped()) { + // The mouse left the safe area, but came back again, so cancel the auto-closing. + minimum_lifetime_timer->stop(); + } + if (!item_clickable_area.has_point(m->get_position())) { return; } diff --git a/servers/physics_2d/godot_shape_2d.cpp b/servers/physics_2d/godot_shape_2d.cpp index db5e6b2353..d77b1a77e3 100644 --- a/servers/physics_2d/godot_shape_2d.cpp +++ b/servers/physics_2d/godot_shape_2d.cpp @@ -123,7 +123,7 @@ void GodotWorldBoundaryShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(arr.size() != 2); normal = arr[0]; d = arr[1]; - configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2))); + configure(Rect2(Vector2(-1e15, -1e15), Vector2(1e15 * 2, 1e15 * 2))); } Variant GodotWorldBoundaryShape2D::get_data() const { diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index ea389ff59c..6eb983d5e0 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -152,7 +152,7 @@ Vector3 GodotWorldBoundaryShape3D::get_moment_of_inertia(real_t p_mass) const { void GodotWorldBoundaryShape3D::_setup(const Plane &p_plane) { plane = p_plane; - configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2))); + configure(AABB(Vector3(-1e15, -1e15, -1e15), Vector3(1e15 * 2, 1e15 * 2, 1e15 * 2))); } void GodotWorldBoundaryShape3D::set_data(const Variant &p_data) { diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index e32164ea98..46c84fd230 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -332,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 child_item_count = ci->ysort_children_count + 1; child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - ci->ysort_xform = final_xform.affine_inverse(); + ci->ysort_xform = ci->xform_curr.affine_inverse(); ci->ysort_pos = Vector2(); ci->ysort_modulate = Color(1, 1, 1, 1); ci->ysort_index = 0; diff --git a/tests/test_main.cpp b/tests/test_main.cpp index bb6837c965..56bd8739c6 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -100,7 +100,6 @@ #include "tests/core/variant/test_variant.h" #include "tests/core/variant/test_variant_utility.h" #include "tests/scene/test_animation.h" -#include "tests/scene/test_arraymesh.h" #include "tests/scene/test_audio_stream_wav.h" #include "tests/scene/test_bit_map.h" #include "tests/scene/test_camera_2d.h" @@ -127,6 +126,7 @@ #include "tests/test_validate_testing.h" #ifndef _3D_DISABLED +#include "tests/scene/test_arraymesh.h" #include "tests/scene/test_camera_3d.h" #include "tests/scene/test_navigation_agent_2d.h" #include "tests/scene/test_navigation_agent_3d.h" |