From b4aa6ad36eb1d523eb5eef41f8572ea654ac0745 Mon Sep 17 00:00:00 2001 From: twobit Date: Sun, 10 Sep 2023 00:09:24 -0400 Subject: [PATCH] Fix `reparent` losing owner if relationship to original owner is not broken --- doc/classes/Node.xml | 2 +- scene/main/node.cpp | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 7510d6bb640..be5931926a6 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -679,7 +679,7 @@ - Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent. + Changes the parent of this [Node] to the [param new_parent]. The node needs to already have a parent. The node's [member owner] is preserved if its owner is still reachable from the new location (i.e., the node is still a descendant of the new parent after the operation). If [param keep_global_transform] is [code]true[/code], the node's global transform will be preserved if supported. [Node2D], [Node3D] and [Control] support this argument (but [Control] keeps only position). diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d8a50c4313a..973650c27b0 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1715,8 +1715,40 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) { return; } + bool preserve_owner = data.owner && (data.owner == p_parent || data.owner->is_ancestor_of(p_parent)); + Node *owner_temp = data.owner; + LocalVector common_parents; + + // If the new parent is related to the owner, find all children of the reparented node who have the same owner so that we can reassign them. + if (preserve_owner) { + LocalVector to_visit; + + to_visit.push_back(this); + common_parents.push_back(this); + + while (to_visit.size() > 0) { + Node *check = to_visit[to_visit.size() - 1]; + to_visit.resize(to_visit.size() - 1); + + for (int i = 0; i < check->get_child_count(); i++) { + Node *child = check->get_child(i, false); + to_visit.push_back(child); + if (child->data.owner == owner_temp) { + common_parents.push_back(child); + } + } + } + } + data.parent->remove_child(this); p_parent->add_child(this); + + // Reassign the old owner to those found nodes. + if (preserve_owner) { + for (Node *E : common_parents) { + E->set_owner(owner_temp); + } + } } Node *Node::get_parent() const { @@ -1904,7 +1936,7 @@ void Node::set_owner(Node *p_owner) { return; } - Node *check = this->get_parent(); + Node *check = get_parent(); bool owner_valid = false; while (check) {