summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-01-11 17:34:19 +0100
committerRémi Verschelde <rverschelde@gmail.com>2024-01-11 17:34:19 +0100
commitf3fc35eb1756496e81bf0eb3a086494aa2271cf0 (patch)
tree05d89fae0e16dcab1fa06ac554747bd7b7bbe29c
parent352434668923978f54f2236f20116fc96ebc9173 (diff)
parentb4aa6ad36eb1d523eb5eef41f8572ea654ac0745 (diff)
downloadredot-engine-f3fc35eb1756496e81bf0eb3a086494aa2271cf0.tar.gz
Merge pull request #81506 from twobitadder/reparent_keep_owner
Fix `reparent()` losing owner
-rw-r--r--doc/classes/Node.xml2
-rw-r--r--scene/main/node.cpp34
2 files changed, 34 insertions, 2 deletions
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 8fb2e65faf..5dd3d22062 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -739,7 +739,7 @@
<param index="0" name="new_parent" type="Node" />
<param index="1" name="keep_global_transform" type="bool" default="true" />
<description>
- 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).
</description>
</method>
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 1dd3b8bd1b..a6b7ca8188 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1736,8 +1736,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<Node *> 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<Node *> 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 {
@@ -1925,7 +1957,7 @@ void Node::set_owner(Node *p_owner) {
return;
}
- Node *check = this->get_parent();
+ Node *check = get_parent();
bool owner_valid = false;
while (check) {