summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/NodePath.xml1
-rw-r--r--editor/scene_tree_dock.cpp163
-rw-r--r--editor/scene_tree_dock.h3
3 files changed, 113 insertions, 54 deletions
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 817ccd5160..0ba2e73ad4 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -20,6 +20,7 @@
@"/root/Main" # If your main scene's root node were named "Main".
@"/root/MyAutoload" # If you have an autoloaded node or scene.
[/codeblock]
+ [b]Note:[/b] In the editor, [NodePath] properties are automatically updated when moving, renaming or deleting a node in the scene tree, but they are never updated at runtime.
</description>
<tutorials>
<link title="2D Role Playing Game Demo">https://godotengine.org/asset-library/asset/520</link>
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 8d6b7f3389..36ea5aea29 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1409,9 +1409,102 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
_fill_path_renames(base_path, new_base_path, p_node, p_renames);
}
+bool SceneTreeDock::_update_node_path(const NodePath &p_root_path, NodePath &p_node_path, List<Pair<NodePath, NodePath>> *p_renames) {
+ NodePath root_path_new = p_root_path;
+ for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
+ if (p_root_path == F->get().first) {
+ root_path_new = F->get().second;
+ break;
+ }
+ }
+
+ // Goes through all paths to check if it's matching.
+ for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
+ NodePath rel_path_old = p_root_path.rel_path_to(F->get().first);
+
+ // If old path detected, then it needs to be replaced with the new one.
+ if (p_node_path == rel_path_old) {
+ NodePath rel_path_new = F->get().second;
+
+ // If not empty, get new relative path.
+ if (!rel_path_new.is_empty()) {
+ rel_path_new = root_path_new.rel_path_to(rel_path_new);
+ }
+
+ p_node_path = rel_path_new;
+ return true;
+ }
+
+ // Update the node itself if it has a valid node path and has not been deleted.
+ if (p_root_path == F->get().first && p_node_path != NodePath() && F->get().second != NodePath()) {
+ NodePath abs_path = NodePath(String(root_path_new).plus_file(p_node_path)).simplified();
+ NodePath rel_path_new = F->get().second.rel_path_to(abs_path);
+
+ p_node_path = rel_path_new;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SceneTreeDock::_check_node_path_recursive(const NodePath &p_root_path, Variant &p_variant, List<Pair<NodePath, NodePath>> *p_renames) {
+ switch (p_variant.get_type()) {
+ case Variant::NODE_PATH: {
+ NodePath node_path = p_variant;
+ if (_update_node_path(p_root_path, node_path, p_renames)) {
+ p_variant = node_path;
+ return true;
+ }
+ } break;
+
+ case Variant::ARRAY: {
+ Array a = p_variant;
+ bool updated = false;
+ for (int i = 0; i < a.size(); i++) {
+ Variant value = a[i];
+ if (_check_node_path_recursive(p_root_path, value, p_renames)) {
+ if (!updated) {
+ a = a.duplicate(); // Need to duplicate for undo-redo to work.
+ updated = true;
+ }
+ a[i] = value;
+ }
+ }
+ if (updated) {
+ p_variant = a;
+ return true;
+ }
+ } break;
+
+ case Variant::DICTIONARY: {
+ Dictionary d = p_variant;
+ bool updated = false;
+ for (int i = 0; i < d.size(); i++) {
+ Variant value = d.get_value_at_index(i);
+ if (_check_node_path_recursive(p_root_path, value, p_renames)) {
+ if (!updated) {
+ d = d.duplicate(); // Need to duplicate for undo-redo to work.
+ updated = true;
+ }
+ d[d.get_key_at_index(i)] = value;
+ }
+ }
+ if (updated) {
+ p_variant = d;
+ return true;
+ }
+ } break;
+
+ default: {
+ }
+ }
+
+ return false;
+}
+
void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) {
Map<Ref<Animation>, Set<int>> rem_anims;
-
if (!r_rem_anims) {
r_rem_anims = &rem_anims;
}
@@ -1424,60 +1517,22 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
return;
}
- // Renaming node paths used in script instances
- if (p_base->get_script_instance()) {
- ScriptInstance *si = p_base->get_script_instance();
-
- if (si) {
- List<PropertyInfo> properties;
- si->get_property_list(&properties);
- NodePath root_path = p_base->get_path();
-
- for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- String propertyname = E->get().name;
- Variant p = p_base->get(propertyname);
- if (p.get_type() == Variant::NODE_PATH) {
- NodePath root_path_new = root_path;
- for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
- if (root_path == F->get().first) {
- root_path_new = F->get().second;
- break;
- }
- }
-
- // Goes through all paths to check if its matching
- for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
- NodePath rel_path_old = root_path.rel_path_to(F->get().first);
+ // Renaming node paths used in node properties.
+ List<PropertyInfo> properties;
+ p_base->get_property_list(&properties);
+ NodePath base_root_path = p_base->get_path();
- // if old path detected, then it needs to be replaced with the new one
- if (p == rel_path_old) {
- NodePath rel_path_new = F->get().second;
-
- // if not empty, get new relative path
- if (!rel_path_new.is_empty()) {
- rel_path_new = root_path_new.rel_path_to(F->get().second);
- }
-
- editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new);
- editor_data->get_undo_redo().add_undo_property(p_base, propertyname, rel_path_old);
-
- p_base->set(propertyname, rel_path_new);
- break;
- }
-
- // update the node itself if it has a valid node path and has not been deleted
- if (root_path == F->get().first && p != NodePath() && F->get().second != NodePath()) {
- NodePath abs_path = NodePath(String(root_path).plus_file(p)).simplified();
- NodePath rel_path_new = F->get().second.rel_path_to(abs_path);
-
- editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new);
- editor_data->get_undo_redo().add_undo_property(p_base, propertyname, p);
-
- p_base->set(propertyname, rel_path_new);
- }
- }
- }
- }
+ for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ if (!(E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
+ continue;
+ }
+ String propertyname = E->get().name;
+ Variant old_variant = p_base->get(propertyname);
+ Variant updated_variant = old_variant;
+ if (_check_node_path_recursive(base_root_path, updated_variant, p_renames)) {
+ editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant);
+ editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant);
+ p_base->set(propertyname, updated_variant);
}
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 53f31375f8..6d48949519 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -247,6 +247,9 @@ class SceneTreeDock : public VBoxContainer {
static SceneTreeDock *singleton;
static void _update_configuration_warning();
+ static bool _update_node_path(const NodePath &p_root_path, NodePath &p_node_path, List<Pair<NodePath, NodePath>> *p_renames);
+ static bool _check_node_path_recursive(const NodePath &p_root_path, Variant &p_variant, List<Pair<NodePath, NodePath>> *p_renames);
+
protected:
void _notification(int p_what);
static void _bind_methods();