diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 575cce96f72..d299e8bb4b8 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -1439,9 +1439,32 @@ void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem * item = _find(tree->get_root(), p_node->get_path()); } ERR_FAIL_NULL(item); - String new_name = p_name.validate_node_name(); + bool check_for_unique_name_token = !p_name.is_empty() && p_name[0] == '%'; + String substr_name = p_name; - if (new_name != p_name) { + if (check_for_unique_name_token) { + substr_name = p_name.substr(1); + + // No need to do anything else with this if already unique. + if (p_node->is_unique_name_in_owner()) { + check_for_unique_name_token = false; + // Do not set scene root as unique. + } else if (get_tree()->get_edited_scene_root() == p_node) { + check_for_unique_name_token = false; + String text = TTR("Root nodes cannot be accessed as unique names in their own scene. Instantiate in another scene and set as unique name there."); + if (error->is_visible()) { + error->set_text(error->get_text() + "\n\n" + text); + } else { + error->set_text(text); + error->popup_centered(); + } + } + } + + String new_name = substr_name.validate_node_name(); + + // If p_name only has "%" at the beginning and no other invalid characters, do not error. + if (new_name != substr_name) { String text = TTR("Invalid node name, the following characters are not allowed:") + "\n" + String::get_invalid_node_name_characters(); if (error->is_visible()) { if (!error->get_meta("invalid_character", false)) { @@ -1482,12 +1505,16 @@ void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem * new_name = p_node->get_parent()->prevalidate_child_name(p_node, new_name); if (new_name == p_node->get_name()) { item->set_text(0, new_name); - return; + // If setting name as unique, check for existing unique node below first. + if (!check_for_unique_name_token) { + return; + } } // We previously made sure name is not the same as current name // so that it won't complain about already used unique name when not changing name. - if (p_node->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name)) { + if ((check_for_unique_name_token || p_node->is_unique_name_in_owner()) && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name)) { + check_for_unique_name_token = false; String text = vformat(TTR("A node with the unique name %s already exists in this scene."), new_name); if (error->is_visible()) { if (!error->get_meta("same_unique_name", false)) { @@ -1501,17 +1528,43 @@ void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem * error->popup_centered(); } item->set_text(0, p_node->get_name()); + if (p_node->is_unique_name_in_owner()) { + return; + } + } + + // If same name and check_for_unique_name_token is still true, now set as unique. + // This is separate from final action so "Rename Node" is not added to undo history. + if (new_name == p_node->get_name()) { + if (check_for_unique_name_token) { + if (!is_scene_tree_dock) { + p_node->set_unique_name_in_owner(true); + } else { + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Enable Scene Unique Name(s)")); + undo_redo->add_undo_method(p_node, "set_unique_name_in_owner", false); + undo_redo->add_do_method(p_node, "set_unique_name_in_owner", true); + undo_redo->commit_action(); + } + } return; } if (!is_scene_tree_dock) { p_node->set_name(new_name); + if (check_for_unique_name_token) { + p_node->set_unique_name_in_owner(true); + } item->set_metadata(0, p_node->get_path()); emit_signal(SNAME("node_renamed")); } else { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Rename Node"), UndoRedo::MERGE_DISABLE, p_node); + if (check_for_unique_name_token) { + undo_redo->add_undo_method(p_node, "set_unique_name_in_owner", false); + } + emit_signal(SNAME("node_prerename"), p_node, new_name); undo_redo->add_undo_method(p_node, "set_name", p_node->get_name()); @@ -1523,6 +1576,10 @@ void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem * undo_redo->add_do_method(item, "set_metadata", 0, p_node->get_path()); undo_redo->add_do_method(item, "set_text", 0, new_name); + if (check_for_unique_name_token) { + undo_redo->add_do_method(p_node, "set_unique_name_in_owner", true); + } + undo_redo->commit_action(); } }