diff options
52 files changed, 395 insertions, 232 deletions
diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp index 9ce1c2d4bb..af7c18741d 100644 --- a/core/string/node_path.cpp +++ b/core/string/node_path.cpp @@ -339,7 +339,6 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { data->refcount.init(); data->absolute = p_absolute; data->path = p_path; - data->has_slashes = true; data->hash_cache_valid = false; } @@ -353,7 +352,6 @@ NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p data->absolute = p_absolute; data->path = p_path; data->subpath = p_subpath; - data->has_slashes = true; data->hash_cache_valid = false; } @@ -373,7 +371,6 @@ NodePath::NodePath(const String &p_path) { bool absolute = (path[0] == '/'); bool last_is_slash = true; - bool has_slashes = false; int slices = 0; int subpath_pos = path.find(":"); @@ -402,7 +399,6 @@ NodePath::NodePath(const String &p_path) { for (int i = (int)absolute; i < path.length(); i++) { if (path[i] == '/') { last_is_slash = true; - has_slashes = true; } else { if (last_is_slash) { slices++; @@ -419,7 +415,6 @@ NodePath::NodePath(const String &p_path) { data = memnew(Data); data->refcount.init(); data->absolute = absolute; - data->has_slashes = has_slashes; data->subpath = subpath; data->hash_cache_valid = false; diff --git a/core/string/node_path.h b/core/string/node_path.h index 7053798cb2..876d69924e 100644 --- a/core/string/node_path.h +++ b/core/string/node_path.h @@ -42,7 +42,6 @@ class NodePath { StringName concatenated_path; StringName concatenated_subpath; bool absolute; - bool has_slashes; mutable bool hash_cache_valid; mutable uint32_t hash_cache; }; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 672b030806..04e1561a0c 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3601,15 +3601,6 @@ bool Variant::is_type_shared(Variant::Type p_type) { case OBJECT: case ARRAY: case DICTIONARY: - case PACKED_BYTE_ARRAY: - case PACKED_INT32_ARRAY: - case PACKED_INT64_ARRAY: - case PACKED_FLOAT32_ARRAY: - case PACKED_FLOAT64_ARRAY: - case PACKED_STRING_ARRAY: - case PACKED_VECTOR2_ARRAY: - case PACKED_VECTOR3_ARRAY: - case PACKED_COLOR_ARRAY: return true; default: { } diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index 86562c340d..98256f0a38 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -92,13 +92,6 @@ [/codeblocks] </description> </method> - <method name="rename_parameter"> - <return type="void" /> - <param index="0" name="old_name" type="String" /> - <param index="1" name="new_name" type="String" /> - <description> - </description> - </method> </methods> <members> <member name="active" type="bool" setter="set_active" getter="is_active" default="false"> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 143e1f23e9..792cd38741 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -529,7 +529,7 @@ <return type="bool" /> <param index="0" name="expr" type="String" /> <description> - Does a simple expression match, where [code]*[/code] matches zero or more arbitrary characters and [code]?[/code] matches any single character except a period ([code].[/code]). An empty string or empty expression always evaluates to [code]false[/code]. + Does a simple expression match (also called "glob" or "globbing"), where [code]*[/code] matches zero or more arbitrary characters and [code]?[/code] matches any single character except a period ([code].[/code]). An empty string or empty expression always evaluates to [code]false[/code]. </description> </method> <method name="matchn" qualifiers="const"> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index c387bd435b..5dedea50d0 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -205,7 +205,7 @@ <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" /> <param index="3" name="alternative_tile" type="int" default="-1" /> <description> - Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param source_id]). + Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param alternative_tile]). If a parameter has it's value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default value, this method returns the same result as [method get_used_cells]. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1. </description> @@ -279,8 +279,8 @@ <description> Sets the tile indentifiers for the cell on layer [param layer] at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts: - The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id], - - The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]. For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]), - - The alternative tile identifier [param alternative_tile] identifies a tile alternative the source is a [TileSetAtlasSource], and the scene for a [TileSetScenesCollectionSource]. + - The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]). For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]), + - The alternative tile identifier [param alternative_tile] identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), and the scene for a [TileSetScenesCollectionSource]. If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code] or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code]. </description> </method> diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index aaa07e98c8..f4d293e9f4 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -591,14 +591,12 @@ void ConnectDialog::popup_dialog(const String p_for_signal) { void ConnectDialog::_advanced_pressed() { if (advanced->is_pressed()) { - set_min_size(Size2(900, 500) * EDSCALE); connect_to_label->set_text(TTR("Connect to Node:")); tree->set_connect_to_script_mode(false); vbc_right->show(); error_label->hide(); } else { - set_min_size(Size2(600, 500) * EDSCALE); reset_size(); connect_to_label->set_text(TTR("Connect to Script:")); tree->set_connect_to_script_mode(true); @@ -613,18 +611,15 @@ void ConnectDialog::_advanced_pressed() { } ConnectDialog::ConnectDialog() { - set_min_size(Size2(600, 500) * EDSCALE); - - VBoxContainer *vbc = memnew(VBoxContainer); - add_child(vbc); + set_min_size(Size2(0, 500) * EDSCALE); HBoxContainer *main_hb = memnew(HBoxContainer); - vbc->add_child(main_hb); - main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL); + add_child(main_hb); VBoxContainer *vbc_left = memnew(VBoxContainer); main_hb->add_child(vbc_left); vbc_left->set_h_size_flags(Control::SIZE_EXPAND_FILL); + vbc_left->set_custom_minimum_size(Vector2(400 * EDSCALE, 0)); from_signal = memnew(LineEdit); vbc_left->add_margin_child(TTR("From Signal:"), from_signal); @@ -685,6 +680,7 @@ ConnectDialog::ConnectDialog() { vbc_right = memnew(VBoxContainer); main_hb->add_child(vbc_right); vbc_right->set_h_size_flags(Control::SIZE_EXPAND_FILL); + vbc_right->set_custom_minimum_size(Vector2(150 * EDSCALE, 0)); vbc_right->hide(); HBoxContainer *add_bind_hb = memnew(HBoxContainer); diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp index 3f788627f4..57a0a88810 100644 --- a/editor/editor_layouts_dialog.cpp +++ b/editor/editor_layouts_dialog.cpp @@ -65,6 +65,20 @@ void EditorLayoutsDialog::_line_gui_input(const Ref<InputEvent> &p_event) { } } +void EditorLayoutsDialog::_update_ok_disable_state() { + if (layout_names->is_anything_selected()) { + get_ok_button()->set_disabled(false); + } else { + get_ok_button()->set_disabled(!name->is_visible() || name->get_text().is_empty()); + } +} + +void EditorLayoutsDialog::_deselect_layout_names() { + // The deselect method does not emit any signal, therefore we need update the disable state as well. + layout_names->deselect_all(); + _update_ok_disable_state(); +} + void EditorLayoutsDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("name_confirmed", PropertyInfo(Variant::STRING, "name"))); } @@ -82,8 +96,8 @@ void EditorLayoutsDialog::ok_pressed() { void EditorLayoutsDialog::_post_popup() { ConfirmationDialog::_post_popup(); - name->clear(); layout_names->clear(); + name->clear(); Ref<ConfigFile> config; config.instantiate(); @@ -112,9 +126,9 @@ EditorLayoutsDialog::EditorLayoutsDialog() { makevb->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); layout_names = memnew(ItemList); - layout_names->set_auto_height(true); makevb->add_margin_child(TTR("Select existing layout:"), layout_names); - layout_names->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); + layout_names->set_auto_height(true); + layout_names->set_custom_minimum_size(Size2(300 * EDSCALE, 50 * EDSCALE)); layout_names->set_visible(true); layout_names->set_offset(SIDE_TOP, 5); layout_names->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); @@ -122,16 +136,17 @@ EditorLayoutsDialog::EditorLayoutsDialog() { layout_names->set_v_size_flags(Control::SIZE_EXPAND_FILL); layout_names->set_select_mode(ItemList::SELECT_MULTI); layout_names->set_allow_rmb_select(true); + layout_names->connect("multi_selected", callable_mp(this, &EditorLayoutsDialog::_update_ok_disable_state).unbind(2)); name = memnew(LineEdit); - name->set_placeholder("Or enter new layout name"); makevb->add_child(name); + name->set_placeholder("Or enter new layout name"); name->set_offset(SIDE_TOP, 5); - name->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); name->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); name->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); name->connect("gui_input", callable_mp(this, &EditorLayoutsDialog::_line_gui_input)); - name->connect("focus_entered", callable_mp(layout_names, &ItemList::deselect_all)); + name->connect("focus_entered", callable_mp(this, &EditorLayoutsDialog::_deselect_layout_names)); + name->connect("text_changed", callable_mp(this, &EditorLayoutsDialog::_update_ok_disable_state).unbind(1)); } void EditorLayoutsDialog::set_name_line_enabled(bool p_enabled) { diff --git a/editor/editor_layouts_dialog.h b/editor/editor_layouts_dialog.h index 80a7ed0b53..e3557fbe71 100644 --- a/editor/editor_layouts_dialog.h +++ b/editor/editor_layouts_dialog.h @@ -44,6 +44,8 @@ class EditorLayoutsDialog : public ConfirmationDialog { VBoxContainer *makevb = nullptr; void _line_gui_input(const Ref<InputEvent> &p_event); + void _update_ok_disable_state(); + void _deselect_layout_names(); protected: static void _bind_methods(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index cf3504fcc1..e1924c7994 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2636,7 +2636,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str new_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); p_popup->add_child(new_menu); - p_popup->add_submenu_item(TTR("New"), "New"); + p_popup->add_submenu_item(TTR("New"), "New", FILE_NEW); new_menu->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("Folder..."), FILE_NEW_FOLDER); new_menu->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("Scene..."), FILE_NEW_SCENE); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index ede6869eea..9060f5c0a4 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -90,17 +90,18 @@ private: FILE_DUPLICATE, FILE_REIMPORT, FILE_INFO, - FILE_NEW_FOLDER, - FILE_NEW_SCRIPT, - FILE_NEW_SCENE, + FILE_NEW, FILE_SHOW_IN_EXPLORER, FILE_OPEN_EXTERNAL, FILE_COPY_PATH, FILE_COPY_UID, - FILE_NEW_RESOURCE, - FILE_NEW_TEXTFILE, FOLDER_EXPAND_ALL, FOLDER_COLLAPSE_ALL, + FILE_NEW_RESOURCE, + FILE_NEW_TEXTFILE, + FILE_NEW_FOLDER, + FILE_NEW_SCRIPT, + FILE_NEW_SCENE, }; FileSortOption file_sort = FILE_SORT_NAME; diff --git a/editor/icons/GizmoBakedLightmap.svg b/editor/icons/GizmoLightmapGI.svg index a7828615fd..a7828615fd 100644 --- a/editor/icons/GizmoBakedLightmap.svg +++ b/editor/icons/GizmoLightmapGI.svg diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index f5f9ec11b3..77785b15ca 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -985,8 +985,6 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); - undo_redo->add_do_method(tree, "rename_parameter", base_path + prev_name, base_path + name); - undo_redo->add_undo_method(tree, "rename_parameter", base_path + name, base_path + prev_name); undo_redo->add_do_method(this, "update_graph"); undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); @@ -1111,7 +1109,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { add_options.push_back(AddOption("Add3", "AnimationNodeAdd3", 3)); add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2", 2)); add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3", 3)); - add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek", 1)); + add_options.push_back(AddOption("TimeSeek", "AnimationNodeTimeSeek", 1)); add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale", 1)); add_options.push_back(AddOption("Transition", "AnimationNodeTransition")); add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree")); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index d3e16211f7..26f872421e 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -2404,7 +2404,7 @@ Vector<String> ProjectConverter3To4::check_for_files() { directories_to_check.append(current_dir.path_join(file_name) + "/"); } else { bool proper_extension = false; - if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj")) + if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".gdshader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj")) proper_extension = true; if (proper_extension) { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 1c2b743909..fd04d3c660 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2240,6 +2240,28 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig if (assignee_type.is_constant || (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->is_constant)) { push_error("Cannot assign a new value to a constant.", p_assignment->assignee); + return; + } else if (assignee_type.is_read_only) { + push_error("Cannot assign a new value to a read-only property.", p_assignment->assignee); + return; + } else if (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT) { + GDScriptParser::SubscriptNode *sub = static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee); + while (sub) { + const GDScriptParser::DataType &base_type = sub->base->datatype; + if (base_type.is_hard_type() && base_type.is_read_only) { + if (base_type.kind == GDScriptParser::DataType::BUILTIN && !Variant::is_type_shared(base_type.builtin_type)) { + push_error("Cannot assign a new value to a read-only property.", p_assignment->assignee); + return; + } + } else { + break; + } + if (sub->base->type == GDScriptParser::Node::SUBSCRIPT) { + sub = static_cast<GDScriptParser::SubscriptNode *>(sub->base); + } else { + sub = nullptr; + } + } } // Check if assigned value is an array literal, so we can make it a typed array too if appropriate. @@ -3329,7 +3351,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod StringName getter_name = ClassDB::get_property_getter(native, name); MethodBind *getter = ClassDB::get_method(native, getter_name); if (getter != nullptr) { - p_identifier->set_datatype(type_from_property(getter->get_return_info())); + bool has_setter = ClassDB::get_property_setter(native, name) != StringName(); + p_identifier->set_datatype(type_from_property(getter->get_return_info(), false, !has_setter)); p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE; } return; @@ -4037,6 +4060,10 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op) Variant GDScriptAnalyzer::make_expression_reduced_value(GDScriptParser::ExpressionNode *p_expression, bool &is_reduced) { Variant value; + if (p_expression == nullptr) { + return value; + } + if (p_expression->is_constant) { is_reduced = true; value = p_expression->reduced_value; @@ -4101,6 +4128,10 @@ Variant GDScriptAnalyzer::make_dictionary_reduced_value(GDScriptParser::Dictiona } Variant GDScriptAnalyzer::make_subscript_reduced_value(GDScriptParser::SubscriptNode *p_subscript, bool &is_reduced) { + if (p_subscript->base == nullptr || p_subscript->index == nullptr) { + return Variant(); + } + bool is_base_value_reduced = false; Variant base_value = make_expression_reduced_value(p_subscript->base, is_base_value_reduced); if (!is_base_value_reduced) { @@ -4260,8 +4291,9 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_metatype(const GDScriptPars return result; } -GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg) const { +GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg, bool p_is_readonly) const { GDScriptParser::DataType result; + result.is_read_only = p_is_readonly; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; if (p_property.type == Variant::NIL && (p_is_arg || (p_property.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) { // Variant diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index b51564fb0a..75d52509a4 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -115,7 +115,7 @@ class GDScriptAnalyzer { Array make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node = nullptr); GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source); static GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type); - GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false) const; + GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false, bool p_is_readonly = false) const; GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source); bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index f88ac581ca..12c10642ec 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1953,17 +1953,19 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, case GDScriptParser::DataType::CLASS: if (base_type.class_type->has_function(p_context.current_function->identifier->name)) { GDScriptParser::FunctionNode *parent_function = base_type.class_type->get_member(p_context.current_function->identifier->name).function; - const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier]]; - if ((!id_type.is_set() || id_type.is_variant()) && parameter->get_datatype().is_hard_type()) { - id_type = parameter->get_datatype(); - } - if (parameter->initializer) { - GDScriptParser::CompletionContext c = p_context; - c.current_function = parent_function; - c.current_class = base_type.class_type; - c.base = nullptr; - if (_guess_expression_type(c, parameter->initializer, r_type)) { - return true; + if (parent_function->parameters_indices.has(p_identifier)) { + const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier]]; + if ((!id_type.is_set() || id_type.is_variant()) && parameter->get_datatype().is_hard_type()) { + id_type = parameter->get_datatype(); + } + if (parameter->initializer) { + GDScriptParser::CompletionContext c = p_context; + c.current_function = parent_function; + c.current_class = base_type.class_type; + c.base = nullptr; + if (_guess_expression_type(c, parameter->initializer, r_type)) { + return true; + } } } } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 713ad3ed17..ed2dce471f 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3602,6 +3602,7 @@ bool GDScriptParser::tool_annotation(const AnnotationNode *p_annotation, Node *p bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p_node) { ERR_FAIL_COND_V_MSG(p_node->type != Node::CLASS, false, R"("@icon" annotation can only be applied to classes.)"); + ERR_FAIL_COND_V(p_annotation->resolved_arguments.is_empty(), false); ClassNode *p_class = static_cast<ClassNode *>(p_node); p_class->icon_path = p_annotation->resolved_arguments[0]; return true; @@ -3830,6 +3831,10 @@ template <PropertyUsageFlags t_usage> bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation, Node *p_node) { AnnotationNode *annotation = const_cast<AnnotationNode *>(p_annotation); + if (annotation->resolved_arguments.is_empty()) { + return false; + } + annotation->export_info.name = annotation->resolved_arguments[0]; switch (t_usage) { @@ -3887,7 +3892,7 @@ bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_ Dictionary rpc_config; rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY; - if (p_annotation->resolved_arguments.size()) { + if (!p_annotation->resolved_arguments.is_empty()) { int last = p_annotation->resolved_arguments.size() - 1; if (p_annotation->resolved_arguments[last].get_type() == Variant::INT) { rpc_config["channel"] = p_annotation->resolved_arguments[last].operator int(); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 07dac25ec5..bc0fe58fa7 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -122,6 +122,7 @@ public: TypeSource type_source = UNDETECTED; bool is_constant = false; + bool is_read_only = false; bool is_meta_type = false; bool is_coroutine = false; // For function calls. @@ -206,6 +207,7 @@ public: void operator=(const DataType &p_other) { kind = p_other.kind; type_source = p_other.type_source; + is_read_only = p_other.is_read_only; is_constant = p_other.is_constant; is_meta_type = p_other.is_meta_type; is_coroutine = p_other.is_coroutine; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index e18a4a6190..b99f5d2685 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -811,13 +811,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (!valid) { + Object *obj = dst->get_validated_object(); String v = index->operator String(); - if (!v.is_empty()) { - v = "'" + v + "'"; + bool read_only_property = false; + if (obj) { + read_only_property = ClassDB::has_property(obj->get_class_name(), v) && (ClassDB::get_property_setter(obj->get_class_name(), v) == StringName()); + } + if (read_only_property) { + err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", v, _get_var_type(dst)); } else { - v = "of type '" + _get_var_type(index) + "'"; + if (!v.is_empty()) { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; } - err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; OPCODE_BREAK; } #endif @@ -1003,8 +1012,16 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (!valid) { - String err_type; - err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + Object *obj = dst->get_validated_object(); + bool read_only_property = false; + if (obj) { + read_only_property = ClassDB::has_property(obj->get_class_name(), *index) && (ClassDB::get_property_setter(obj->get_class_name(), *index) == StringName()); + } + if (read_only_property) { + err_text = vformat(R"(Cannot set value into property "%s" (on base "%s") because it is read-only.)", String(*index), _get_var_type(dst)); + } else { + err_text = "Invalid set index '" + String(*index) + "' (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'."; + } OPCODE_BREAK; } #endif diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.gd new file mode 100644 index 0000000000..2b1c4c9594 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.gd @@ -0,0 +1,4 @@ +func test(): + var tree := SceneTree.new() + tree.root = Window.new() + tree.free() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.out new file mode 100644 index 0000000000..b236d70ec8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a read-only property. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.gd new file mode 100644 index 0000000000..c97ee0ea69 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.gd @@ -0,0 +1,4 @@ +func test(): + var state := PhysicsDirectBodyState3DExtension.new() + state.center_of_mass.x += 1.0 + state.free() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.out new file mode 100644 index 0000000000..b236d70ec8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a read-only property. diff --git a/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.gd b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.gd new file mode 100644 index 0000000000..19c4186622 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.gd @@ -0,0 +1,7 @@ +func test(): + var state = PhysicsDirectBodyState3DExtension.new() + assign(state) + state.free() + +func assign(state): + state.center_of_mass.x -= 1.0 diff --git a/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.out b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.out new file mode 100644 index 0000000000..c181c5dd02 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: assign() +>> runtime/assign_to_read_only_property.gd +>> 7 +>> Cannot set value into property "center_of_mass" (on base "PhysicsDirectBodyState3DExtension") because it is read-only. diff --git a/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.gd b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.gd new file mode 100644 index 0000000000..f15f580272 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.gd @@ -0,0 +1,8 @@ +func test(): + var state = PhysicsDirectBodyState3DExtension.new() + var prop = &"center_of_mass" + assign(state, prop) + state.free() + +func assign(state, prop): + state[prop].x = 1.0 diff --git a/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.out b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.out new file mode 100644 index 0000000000..2cdc81aacc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.out @@ -0,0 +1,6 @@ +GDTEST_RUNTIME_ERROR +>> SCRIPT ERROR +>> on function: assign() +>> runtime/assign_to_read_only_property_with_variable_index.gd +>> 8 +>> Cannot set value into property "center_of_mass" (on base "PhysicsDirectBodyState3DExtension") because it is read-only. diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 019504ad66..70b48b0e3a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -185,7 +185,9 @@ namespace GodotTools.Export foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories)) { - AddSharedObject(file, tags: null, projectDataDirName); + AddSharedObject(file, tags: null, + Path.Join(projectDataDirName, + Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file)))); } } } diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index d546c5d3ba..c3cb1c5f13 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -262,7 +262,7 @@ TypedArray<RID> GodotNavigationServer::map_get_agents(RID p_map) const { const NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_COND_V(map == nullptr, agents_rids); - const LocalVector<RvoAgent *> agents = map->get_agents(); + const LocalVector<NavAgent *> agents = map->get_agents(); agents_rids.resize(agents.size()); for (uint32_t i = 0; i < agents.size(); i++) { @@ -282,7 +282,7 @@ RID GodotNavigationServer::region_get_map(RID p_region) const { } RID GodotNavigationServer::agent_get_map(RID p_agent) const { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND_V(agent == nullptr, RID()); if (agent->get_map()) { @@ -579,13 +579,13 @@ RID GodotNavigationServer::agent_create() { MutexLock lock(operations_mutex); RID rid = agent_owner.make_rid(); - RvoAgent *agent = agent_owner.get_or_null(rid); + NavAgent *agent = agent_owner.get_or_null(rid); agent->set_self(rid); return rid; } COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); if (agent->get_map()) { @@ -612,77 +612,77 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) { } COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->neighborDist_ = p_distance; } COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->maxNeighbors_ = p_count; } COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->timeHorizon_ = p_time; } COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->radius_ = p_radius; } COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->maxSpeed_ = p_max_speed; } COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->velocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z); } COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->prefVelocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z); } COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->position_ = RVO::Vector3(p_position.x, p_position.y, p_position.z); } COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->get_agent()->ignore_y_ = p_ignore; } bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND_V(agent == nullptr, false); return agent->is_map_changed(); } COMMAND_2(agent_set_callback, RID, p_agent, Callable, p_callback) { - RvoAgent *agent = agent_owner.get_or_null(p_agent); + NavAgent *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_COND(agent == nullptr); agent->set_callback(p_callback); @@ -713,7 +713,7 @@ COMMAND_1(free, RID, p_object) { } // Remove any assigned agent - for (RvoAgent *agent : map->get_agents()) { + for (NavAgent *agent : map->get_agents()) { map->remove_agent(agent); agent->set_map(nullptr); } @@ -746,7 +746,7 @@ COMMAND_1(free, RID, p_object) { link_owner.free(p_object); } else if (agent_owner.owns(p_object)) { - RvoAgent *agent = agent_owner.get_or_null(p_object); + NavAgent *agent = agent_owner.get_or_null(p_object); // Removes this agent from the map if assigned if (agent->get_map() != nullptr) { diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index eea5713c40..0b113b77d4 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -36,10 +36,10 @@ #include "core/templates/rid_owner.h" #include "servers/navigation_server_3d.h" +#include "nav_agent.h" #include "nav_link.h" #include "nav_map.h" #include "nav_region.h" -#include "rvo_agent.h" /// The commands are functions executed during the `sync` phase. @@ -71,7 +71,7 @@ class GodotNavigationServer : public NavigationServer3D { mutable RID_Owner<NavLink> link_owner; mutable RID_Owner<NavMap> map_owner; mutable RID_Owner<NavRegion> region_owner; - mutable RID_Owner<RvoAgent> agent_owner; + mutable RID_Owner<NavAgent> agent_owner; bool active = true; LocalVector<NavMap *> active_maps; diff --git a/modules/navigation/rvo_agent.cpp b/modules/navigation/nav_agent.cpp index 40f1e925be..293544c0a5 100644 --- a/modules/navigation/rvo_agent.cpp +++ b/modules/navigation/nav_agent.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rvo_agent.cpp */ +/* nav_agent.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "rvo_agent.h" +#include "nav_agent.h" #include "nav_map.h" -void RvoAgent::set_map(NavMap *p_map) { +void NavAgent::set_map(NavMap *p_map) { map = p_map; } -bool RvoAgent::is_map_changed() { +bool NavAgent::is_map_changed() { if (map) { bool is_changed = map->get_map_update_id() != map_update_id; map_update_id = map->get_map_update_id(); @@ -46,15 +46,15 @@ bool RvoAgent::is_map_changed() { } } -void RvoAgent::set_callback(Callable p_callback) { +void NavAgent::set_callback(Callable p_callback) { callback = p_callback; } -bool RvoAgent::has_callback() const { +bool NavAgent::has_callback() const { return callback.is_valid(); } -void RvoAgent::dispatch_callback() { +void NavAgent::dispatch_callback() { if (!callback.is_valid()) { return; } diff --git a/modules/navigation/rvo_agent.h b/modules/navigation/nav_agent.h index 5f377b6079..f154ce14d9 100644 --- a/modules/navigation/rvo_agent.h +++ b/modules/navigation/nav_agent.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* rvo_agent.h */ +/* nav_agent.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef RVO_AGENT_H -#define RVO_AGENT_H +#ifndef NAV_AGENT_H +#define NAV_AGENT_H #include "core/object/class_db.h" #include "nav_rid.h" @@ -38,7 +38,7 @@ class NavMap; -class RvoAgent : public NavRid { +class NavAgent : public NavRid { NavMap *map = nullptr; RVO::Agent agent; Callable callback = Callable(); @@ -62,4 +62,4 @@ public: void dispatch_callback(); }; -#endif // RVO_AGENT_H +#endif // NAV_AGENT_H diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index d763b1d3bc..b1674c8fc5 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -31,9 +31,9 @@ #include "nav_map.h" #include "core/object/worker_thread_pool.h" +#include "nav_agent.h" #include "nav_link.h" #include "nav_region.h" -#include "rvo_agent.h" #include <algorithm> #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) @@ -568,18 +568,18 @@ void NavMap::remove_link(NavLink *p_link) { } } -bool NavMap::has_agent(RvoAgent *agent) const { +bool NavMap::has_agent(NavAgent *agent) const { return (agents.find(agent) != -1); } -void NavMap::add_agent(RvoAgent *agent) { +void NavMap::add_agent(NavAgent *agent) { if (!has_agent(agent)) { agents.push_back(agent); agents_dirty = true; } } -void NavMap::remove_agent(RvoAgent *agent) { +void NavMap::remove_agent(NavAgent *agent) { remove_agent_as_controlled(agent); int64_t agent_index = agents.find(agent); if (agent_index != -1) { @@ -588,7 +588,7 @@ void NavMap::remove_agent(RvoAgent *agent) { } } -void NavMap::set_agent_as_controlled(RvoAgent *agent) { +void NavMap::set_agent_as_controlled(NavAgent *agent) { const bool exist = (controlled_agents.find(agent) != -1); if (!exist) { ERR_FAIL_COND(!has_agent(agent)); @@ -596,7 +596,7 @@ void NavMap::set_agent_as_controlled(RvoAgent *agent) { } } -void NavMap::remove_agent_as_controlled(RvoAgent *agent) { +void NavMap::remove_agent_as_controlled(NavAgent *agent) { int64_t active_avoidance_agent_index = controlled_agents.find(agent); if (active_avoidance_agent_index != -1) { controlled_agents.remove_at_unordered(active_avoidance_agent_index); @@ -895,7 +895,7 @@ void NavMap::sync() { // cannot use LocalVector here as RVO library expects std::vector to build KdTree std::vector<RVO::Agent *> raw_agents; raw_agents.reserve(agents.size()); - for (RvoAgent *agent : agents) { + for (NavAgent *agent : agents) { raw_agents.push_back(agent->get_agent()); } rvo.buildAgentTree(raw_agents); @@ -916,7 +916,7 @@ void NavMap::sync() { pm_edge_free_count = _new_pm_edge_free_count; } -void NavMap::compute_single_step(uint32_t index, RvoAgent **agent) { +void NavMap::compute_single_step(uint32_t index, NavAgent **agent) { (*(agent + index))->get_agent()->computeNeighbors(&rvo); (*(agent + index))->get_agent()->computeNewVelocity(deltatime); } @@ -930,7 +930,7 @@ void NavMap::step(real_t p_deltatime) { } void NavMap::dispatch_callbacks() { - for (RvoAgent *agent : controlled_agents) { + for (NavAgent *agent : controlled_agents) { agent->dispatch_callback(); } } diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index fce7aff3ba..ab6a48dd70 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -42,7 +42,7 @@ class NavLink; class NavRegion; -class RvoAgent; +class NavAgent; class NavMap : public NavRid { /// Map Up @@ -78,10 +78,10 @@ class NavMap : public NavRid { bool agents_dirty = false; /// All the Agents (even the controlled one) - LocalVector<RvoAgent *> agents; + LocalVector<NavAgent *> agents; /// Controlled agents - LocalVector<RvoAgent *> controlled_agents; + LocalVector<NavAgent *> controlled_agents; /// Physics delta time real_t deltatime = 0.0; @@ -144,15 +144,15 @@ public: return links; } - bool has_agent(RvoAgent *agent) const; - void add_agent(RvoAgent *agent); - void remove_agent(RvoAgent *agent); - const LocalVector<RvoAgent *> &get_agents() const { + bool has_agent(NavAgent *agent) const; + void add_agent(NavAgent *agent); + void remove_agent(NavAgent *agent); + const LocalVector<NavAgent *> &get_agents() const { return agents; } - void set_agent_as_controlled(RvoAgent *agent); - void remove_agent_as_controlled(RvoAgent *agent); + void set_agent_as_controlled(NavAgent *agent); + void remove_agent_as_controlled(NavAgent *agent); uint32_t get_map_update_id() const { return map_update_id; @@ -173,7 +173,7 @@ public: int get_pm_edge_free_count() const { return pm_edge_free_count; } private: - void compute_single_step(uint32_t index, RvoAgent **agent); + void compute_single_step(uint32_t index, NavAgent **agent); void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const; }; diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 3b39967ba4..0dd41675b6 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -103,6 +103,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extens 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_openxr.add_source_files(module_obj, "extensions/openxr_ml2_controller_extension.cpp") env.modules_sources += module_obj diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp new file mode 100644 index 0000000000..ae372f69b3 --- /dev/null +++ b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* openxr_ml2_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_ml2_controller_extension.h" +#include "../action_map/openxr_interaction_profile_meta_data.h" + +HashMap<String, bool *> OpenXRML2ControllerExtension::get_requested_extensions() { + HashMap<String, bool *> request_extensions; + + request_extensions[XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME] = &available; + + return request_extensions; +} + +bool OpenXRML2ControllerExtension::is_available() { + return available; +} + +void OpenXRML2ControllerExtension::on_register_metadata() { + OpenXRInteractionProfileMetaData *metadata = OpenXRInteractionProfileMetaData::get_singleton(); + ERR_FAIL_NULL(metadata); + + // Magic Leap 2 Controller + const String profile_path = "/interaction_profiles/ml/ml2_controller"; + metadata->register_interaction_profile("Magic Leap 2 controller", "/interaction_profiles/ml/ml2_controller", XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME); + for (const String user_path : { "/user/hand/left", "/user/hand/right" }) { + metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE); + + metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Shoulder click", user_path, user_path + "/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + + metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path(profile_path, "Trackpad force", user_path, user_path + "/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trackpad X", user_path, user_path + "/input/trackpad/x", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trackpad Y", user_path, user_path + "/input/trackpad/y", "", OpenXRAction::OPENXR_ACTION_FLOAT); + metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_VECTOR2); + + metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); + } +} diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.h b/modules/openxr/extensions/openxr_ml2_controller_extension.h new file mode 100644 index 0000000000..216cd55a2f --- /dev/null +++ b/modules/openxr/extensions/openxr_ml2_controller_extension.h @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* openxr_ml2_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_ML2_CONTROLLER_EXTENSION_H +#define OPENXR_ML2_CONTROLLER_EXTENSION_H + +#include "openxr_extension_wrapper.h" + +class OpenXRML2ControllerExtension : 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_ML2_CONTROLLER_EXTENSION_H diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp index 306a2f1bbd..c39e49387a 100644 --- a/modules/openxr/register_types.cpp +++ b/modules/openxr/register_types.cpp @@ -52,6 +52,7 @@ #include "extensions/openxr_htc_controller_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" #include "extensions/openxr_huawei_controller_extension.h" +#include "extensions/openxr_ml2_controller_extension.h" #include "extensions/openxr_palm_pose_extension.h" #include "extensions/openxr_pico_controller_extension.h" #include "extensions/openxr_wmr_controller_extension.h" @@ -102,6 +103,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) { OpenXRAPI::register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension)); + OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension)); } if (OpenXRAPI::openxr_is_enabled()) { diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 0902be9595..c02acbee83 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -899,10 +899,6 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p bool screen_support_large = p_preset->get("screen/support_large"); bool screen_support_xlarge = p_preset->get("screen/support_xlarge"); - int xr_mode_index = p_preset->get("xr_features/xr_mode"); - int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); - int hand_tracking_frequency_index = p_preset->get("xr_features/hand_tracking_frequency"); - bool backup_allowed = p_preset->get("user_data_backup/allow"); int app_category = p_preset->get("package/app_category"); bool retain_data_on_uninstall = p_preset->get("package/retain_data_on_uninstall"); @@ -1046,25 +1042,6 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p } } - // Hand tracking related configurations - if (xr_mode_index == XR_MODE_OPENXR && hand_tracking_index > XR_HAND_TRACKING_NONE) { - if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_metadata_name") { - string_table.write[attr_value] = "com.oculus.handtracking.frequency"; - } - - if (tname == "meta-data" && attrname == "value" && value == "xr_hand_tracking_metadata_value") { - string_table.write[attr_value] = (hand_tracking_frequency_index == XR_HAND_TRACKING_FREQUENCY_LOW ? "LOW" : "HIGH"); - } - - if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_version_name") { - string_table.write[attr_value] = "com.oculus.handtracking.version"; - } - - if (tname == "meta-data" && attrname == "value" && value == "xr_hand_tracking_version_value") { - string_table.write[attr_value] = "V2.0"; - } - } - iofs += 20; } @@ -1079,23 +1056,6 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p Vector<bool> feature_required_list; Vector<int> feature_versions; - if (xr_mode_index == XR_MODE_OPENXR) { - // Check for hand tracking - if (hand_tracking_index > XR_HAND_TRACKING_NONE) { - feature_names.push_back("oculus.software.handtracking"); - feature_required_list.push_back(hand_tracking_index == XR_HAND_TRACKING_REQUIRED); - feature_versions.push_back(-1); // no version attribute should be added. - } - - // Check for passthrough - int passthrough_mode = p_preset->get("xr_features/passthrough"); - if (passthrough_mode > XR_PASSTHROUGH_NONE) { - feature_names.push_back("com.oculus.feature.PASSTHROUGH"); - feature_required_list.push_back(passthrough_mode == XR_PASSTHROUGH_REQUIRED); - feature_versions.push_back(-1); - } - } - if (feature_names.size() > 0) { ofs += 24; // skip over end tag @@ -2334,6 +2294,12 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit int xr_mode_index = p_preset->get("xr_features/xr_mode"); int hand_tracking = p_preset->get("xr_features/hand_tracking"); int passthrough_mode = p_preset->get("xr_features/passthrough"); + if (xr_mode_index == XR_MODE_OPENXR && !custom_build_enabled) { + valid = false; + err += TTR("OpenXR requires \"Use Custom Build\" to be enabled"); + err += "\n"; + } + if (xr_mode_index != XR_MODE_OPENXR) { if (hand_tracking > XR_HAND_TRACKING_NONE) { valid = false; diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 4fdcca68e9..5e71116c10 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -276,17 +276,39 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) { return manifest_xr_features; } -String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { +String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr) { String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")))); String manifest_activity_text = vformat( " <activity android:name=\"com.godot.game.GodotApp\" " "tools:replace=\"android:screenOrientation,android:excludeFromRecents,android:resizeableActivity\" " + "tools:node=\"mergeOnlyAttributes\" " "android:excludeFromRecents=\"%s\" " "android:screenOrientation=\"%s\" " "android:resizeableActivity=\"%s\">\n", bool_to_string(p_preset->get("package/exclude_from_recents")), orientation, bool_to_string(bool(GLOBAL_GET("display/window/size/resizable")))); + + if (p_uses_xr) { + manifest_activity_text += " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + "\n" + " <!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android\n" + " platforms. -->\n" + " <category android:name=\"com.oculus.intent.category.VR\" />\n" + "\n" + " <!-- OpenXR category tag to indicate the activity starts in an immersive OpenXR mode. \n" + " See https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#android-runtime-category. -->\n" + " <category android:name=\"org.khronos.openxr.intent.category.IMMERSIVE_HMD\" />\n" + " </intent-filter>\n"; + } else { + manifest_activity_text += " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + " </intent-filter>\n"; + } + manifest_activity_text += " </activity>\n"; return manifest_activity_text; } @@ -307,9 +329,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ " android:hasFragileUserData=\"%s\"\n" " android:requestLegacyExternalStorage=\"%s\"\n" " tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n" - " tools:ignore=\"GoogleAppIndexingWarning\">\n\n" - " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_version_name\" />\n" - " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_metadata_name\" />\n", + " tools:ignore=\"GoogleAppIndexingWarning\">\n\n", bool_to_string(p_preset->get("user_data_backup/allow")), _get_app_category_label(app_category_index), bool_to_string(is_game), @@ -327,7 +347,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.version\" android:value=\"V2.0\" />\n"; } } - manifest_application_text += _get_activity_tag(p_preset); + manifest_application_text += _get_activity_tag(p_preset, uses_xr); manifest_application_text += " </application>\n"; return manifest_application_text; } diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 0fa857cb75..fe5888e11c 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -118,7 +118,7 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset); String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset); -String _get_activity_tag(const Ref<EditorExportPreset> &p_preset); +String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr); String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission); diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 1969f9c814..ce4a2ecfe4 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -31,23 +31,6 @@ android:name="org.godotengine.editor.version" android:value="${godotEditorVersion}" /> - <!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. --> - <!-- Do these changes in the export preset. Adding new ones is fine. --> - - <!-- XR hand tracking metadata --> - <!-- This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. --> - <!-- Removed at export time if the xr mode is not VR or hand tracking is disabled. --> - <meta-data - android:name="xr_hand_tracking_metadata_name" - android:value="xr_hand_tracking_metadata_value"/> - - <!-- XR hand tracking version --> - <!-- This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. --> - <!-- Removed at export time if the xr mode is not VR or hand tracking is disabled. --> - <meta-data - android:name="xr_hand_tracking_version_name" - android:value="xr_hand_tracking_version_value"/> - <activity android:name=".GodotApp" android:label="@string/godot_project_name_string" @@ -63,10 +46,6 @@ <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> - - <!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android - platforms. --> - <category android:name="com.oculus.intent.category.VR" /> </intent-filter> </activity> diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 75c23655f2..41d1f1d050 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -81,7 +81,7 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { List<String> args; if (program.ends_with("zenity")) { - args.push_back("--error"); + args.push_back("--warning"); args.push_back("--width"); args.push_back("500"); args.push_back("--title"); @@ -91,7 +91,9 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { } if (program.ends_with("kdialog")) { - args.push_back("--error"); + // `--sorry` uses the same icon as `--warning` in Zenity. + // As of KDialog 22.12.1, its `--warning` options are only available for yes/no questions. + args.push_back("--sorry"); args.push_back(p_alert); args.push_back("--title"); args.push_back(p_title); diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index b1880c2fb6..65546392c1 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3920,6 +3920,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM } } show_window(MAIN_WINDOW_ID); + force_process_and_drop_events(); #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 49c5501e77..fe6bee0f1b 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -250,7 +250,7 @@ void Camera2D::_notification(int p_what) { add_to_group(group_name); add_to_group(canvas_group_name); - if (enabled && !viewport->get_camera_2d()) { + if (!Engine::get_singleton()->is_editor_hint() && enabled && !viewport->get_camera_2d()) { make_current(); } @@ -260,11 +260,11 @@ void Camera2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { + remove_from_group(group_name); + remove_from_group(canvas_group_name); if (is_current()) { clear_current(); } - remove_from_group(group_name); - remove_from_group(canvas_group_name); viewport = nullptr; } break; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 797999625b..12a96c8679 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -518,7 +518,7 @@ void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const { } Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const { - return 0; //for blend amount + return 0; // For blend amount. } String AnimationNodeBlend2::get_caption() const { @@ -531,7 +531,7 @@ double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_is_extern double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync); double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync); - return amount > 0.5 ? rem1 : rem0; //hacky but good enough + return amount > 0.5 ? rem1 : rem0; // Hacky but good enough. } bool AnimationNodeBlend2::has_filter() const { @@ -553,7 +553,7 @@ void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const { } Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const { - return 0; //for blend amount + return 0; // For blend amount. } String AnimationNodeBlend3::get_caption() const { @@ -566,7 +566,7 @@ double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_is_extern double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync); double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync); - return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough + return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough. } void AnimationNodeBlend3::_bind_methods() { @@ -585,7 +585,7 @@ void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) cons } Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const { - return 1.0; //initial timescale + return 1.0; // Initial timescale. } String AnimationNodeTimeScale::get_caption() const { @@ -611,24 +611,24 @@ AnimationNodeTimeScale::AnimationNodeTimeScale() { //////////////////////////////////// void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const { - r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); + r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos_request, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); // It will be reset to -1 after seeking the position immediately. } Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const { - return 1.0; //initial timescale + return -1.0; // Initial seek request. } String AnimationNodeTimeSeek::get_caption() const { - return "Seek"; + return "TimeSeek"; } double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_is_external_seeking) { - double cur_seek_pos = get_parameter(seek_pos); + double cur_seek_pos = get_parameter(seek_pos_request); if (p_seek) { return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true); } else if (cur_seek_pos >= 0) { double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true); - set_parameter(seek_pos, -1.0); //reset + set_parameter(seek_pos_request, -1.0); // Reset. return ret; } else { return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true); @@ -871,7 +871,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex } } - if (cur_prev_index < 0) { // process current animation, check for transition + if (cur_prev_index < 0) { // Process current animation, check for transition. rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true); @@ -885,7 +885,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count())); } - } else { // cross-fading from prev to current + } else { // Cross-fading from prev to current. real_t blend = xfade_time == 0 ? 0 : (cur_prev_xfading / xfade_time); if (xfade_curve.is_valid()) { @@ -894,7 +894,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex // Blend values must be more than CMP_EPSILON to process discrete keys in edge. real_t blend_inv = 1.0 - blend; - if (input_data[cur_current_index].reset && !p_seek && switched) { //just switched, seek to start of current + if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current. rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); } else { rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); @@ -1052,7 +1052,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { nodes.erase(p_name); - //erase connections to name + // Erase connections to name. for (KeyValue<StringName, Node> &E : nodes) { for (int i = 0; i < E.value.connections.size(); i++) { if (E.value.connections[i] == p_name) { @@ -1076,7 +1076,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN nodes[p_new_name] = nodes[p_name]; nodes.erase(p_name); - //rename connections + // Rename connections. for (KeyValue<StringName, Node> &E : nodes) { for (int i = 0; i < E.value.connections.size(); i++) { if (E.value.connections[i] == p_name) { @@ -1084,7 +1084,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN } } } - //connection must be done with new name + // Connection must be done with new name. nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED); emit_signal(SNAME("tree_changed")); diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 20f8e9b190..1e90952564 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -257,7 +257,7 @@ public: class AnimationNodeTimeSeek : public AnimationNode { GDCLASS(AnimationNodeTimeSeek, AnimationNode); - StringName seek_pos = PNAME("seek_position"); + StringName seek_pos_request = PNAME("seek_request"); protected: static void _bind_methods(); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index fa72bbc593..dd5bf31c66 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -2084,20 +2084,6 @@ void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const { } } -void AnimationTree::rename_parameter(const String &p_base, const String &p_new_base) { - //rename values first - for (const PropertyInfo &E : properties) { - if (E.name.begins_with(p_base)) { - String new_name = E.name.replace_first(p_base, p_new_base); - property_map[new_name] = property_map[E.name]; - } - } - - //update tree second - properties_dirty = true; - _update_properties(); -} - real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const { if (!input_activity_map_get.has(p_path)) { return 0; @@ -2143,8 +2129,6 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties); - ClassDB::bind_method(D_METHOD("rename_parameter", "old_name", "new_name"), &AnimationTree::rename_parameter); - ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx"); diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index a6fb4a8430..c5c2790fae 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -389,8 +389,6 @@ public: real_t get_connection_activity(const StringName &p_path, int p_connection) const; void advance(double p_time); - void rename_parameter(const String &p_base, const String &p_new_base); - uint64_t get_last_process_pass() const; AnimationTree(); ~AnimationTree(); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index dba08e16cb..16a718722c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -84,6 +84,7 @@ void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) { } shift_selection_check_post(p_select); + _reset_caret_blink_timer(); } void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) { @@ -116,6 +117,7 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) { } shift_selection_check_post(p_select); + _reset_caret_blink_timer(); } void LineEdit::_move_caret_start(bool p_select) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index c31155bd5c..b0898e2239 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1061,10 +1061,10 @@ void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) { get_tree()->get_nodes_in_group(p_camera_group, &camera_list); Camera2D *new_camera = nullptr; - for (const Node *E : camera_list) { - const Camera2D *cam = Object::cast_to<Camera2D>(E); + for (Node *E : camera_list) { + Camera2D *cam = Object::cast_to<Camera2D>(E); if (cam->is_enabled()) { - new_camera = const_cast<Camera2D *>(cam); + new_camera = cam; break; } } |