summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/string/node_path.cpp5
-rw-r--r--core/string/node_path.h1
-rw-r--r--core/variant/variant.cpp9
-rw-r--r--doc/classes/AnimationTree.xml7
-rw-r--r--doc/classes/String.xml2
-rw-r--r--doc/classes/TileMap.xml6
-rw-r--r--editor/connections_dialog.cpp12
-rw-r--r--editor/editor_layouts_dialog.cpp27
-rw-r--r--editor/editor_layouts_dialog.h2
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/filesystem_dock.h11
-rw-r--r--editor/icons/GizmoLightmapGI.svg (renamed from editor/icons/GizmoBakedLightmap.svg)0
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp4
-rw-r--r--editor/project_converter_3_to_4.cpp2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp36
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_editor.cpp24
-rw-r--r--modules/gdscript/gdscript_parser.cpp7
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_vm.cpp29
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/assign_to_read_only_property_indirectly.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.gd7
-rw-r--r--modules/gdscript/tests/scripts/runtime/assign_to_read_only_property.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.gd8
-rw-r--r--modules/gdscript/tests/scripts/runtime/assign_to_read_only_property_with_variable_index.out6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs4
-rw-r--r--modules/navigation/godot_navigation_server.cpp34
-rw-r--r--modules/navigation/godot_navigation_server.h4
-rw-r--r--modules/navigation/nav_agent.cpp (renamed from modules/navigation/rvo_agent.cpp)14
-rw-r--r--modules/navigation/nav_agent.h (renamed from modules/navigation/rvo_agent.h)10
-rw-r--r--modules/navigation/nav_map.cpp18
-rw-r--r--modules/navigation/nav_map.h20
-rw-r--r--modules/openxr/SCsub1
-rw-r--r--modules/openxr/extensions/openxr_ml2_controller_extension.cpp71
-rw-r--r--modules/openxr/extensions/openxr_ml2_controller_extension.h48
-rw-r--r--modules/openxr/register_types.cpp2
-rw-r--r--platform/android/export/export_plugin.cpp46
-rw-r--r--platform/android/export/gradle_export_util.cpp30
-rw-r--r--platform/android/export/gradle_export_util.h2
-rw-r--r--platform/android/java/app/AndroidManifest.xml21
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp6
-rw-r--r--platform/macos/display_server_macos.mm1
-rw-r--r--scene/2d/camera_2d.cpp6
-rw-r--r--scene/animation/animation_blend_tree.cpp32
-rw-r--r--scene/animation/animation_blend_tree.h2
-rw-r--r--scene/animation/animation_tree.cpp16
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/main/viewport.cpp6
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;
}
}