Răsfoiți Sursa

Merge pull request #81506 from twobitadder/reparent_keep_owner

Fix `reparent()` losing owner
Rémi Verschelde 1 an în urmă
părinte
comite
f3fc35eb17
2 a modificat fișierele cu 34 adăugiri și 2 ștergeri
  1. 1 1
      doc/classes/Node.xml
  2. 33 1
      scene/main/node.cpp

+ 1 - 1
doc/classes/Node.xml

@@ -739,7 +739,7 @@
 			<param index="0" name="new_parent" type="Node" />
 			<param index="0" name="new_parent" type="Node" />
 			<param index="1" name="keep_global_transform" type="bool" default="true" />
 			<param index="1" name="keep_global_transform" type="bool" default="true" />
 			<description>
 			<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).
 				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>
 			</description>
 		</method>
 		</method>

+ 33 - 1
scene/main/node.cpp

@@ -1736,8 +1736,40 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) {
 		return;
 		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);
 	data.parent->remove_child(this);
 	p_parent->add_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 {
 Node *Node::get_parent() const {
@@ -1925,7 +1957,7 @@ void Node::set_owner(Node *p_owner) {
 		return;
 		return;
 	}
 	}
 
 
-	Node *check = this->get_parent();
+	Node *check = get_parent();
 	bool owner_valid = false;
 	bool owner_valid = false;
 
 
 	while (check) {
 	while (check) {