From 0df5d74e6eb4d1e49928aded85cb5b3093e874ed Mon Sep 17 00:00:00 2001 From: Maganty Rushyendra Date: Mon, 8 Jun 2020 17:19:50 +0800 Subject: [PATCH] Fix signal duplication bug when duplicating node with instanced children Change error checking in `duplicate_signals()` to check for path to `p_original`, thus adhering to the method used in `duplicate`, instead of checking for ownership. --- scene/main/node.cpp | 75 +++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 350959dcc37..05cd5910a61 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2247,42 +2247,51 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map &p // if the emitter node comes later in tree order than the receiver void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { - if (this != p_original && (get_owner() != p_original && get_owner() != p_original->get_owner())) + if ((this != p_original) && !(p_original->is_a_parent_of(this))) { return; - - List conns; - get_all_signal_connections(&conns); - - for (List::Element *E = conns.front(); E; E = E->next()) { - - if (E->get().flags & CONNECT_PERSIST) { - //user connected - NodePath p = p_original->get_path_to(this); - Node *copy = p_copy->get_node(p); - - Node *target = Object::cast_to(E->get().target); - if (!target) { - continue; - } - NodePath ptarget = p_original->get_path_to(target); - - Node *copytarget = target; - - // Atempt to find a path to the duplicate target, if it seems it's not part - // of the duplicated and not yet parented hierarchy then at least try to connect - // to the same target as the original - - if (p_copy->has_node(ptarget)) - copytarget = p_copy->get_node(ptarget); - - if (copy && copytarget && !copy->is_connected(E->get().signal, copytarget, E->get().method)) { - copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, E->get().flags); - } - } } - for (int i = 0; i < get_child_count(); i++) { - get_child(i)->_duplicate_signals(p_original, p_copy); + List process_list; + process_list.push_back(this); + while (!process_list.empty()) { + + const Node *n = process_list.front()->get(); + process_list.pop_front(); + + List conns; + n->get_all_signal_connections(&conns); + + for (List::Element *E = conns.front(); E; E = E->next()) { + if (E->get().flags & CONNECT_PERSIST) { + //user connected + NodePath p = p_original->get_path_to(n); + Node *copy = p_copy->get_node(p); + + Node *target = Object::cast_to(E->get().target); + if (!target) { + continue; + } + NodePath ptarget = p_original->get_path_to(target); + + Node *copytarget = target; + + // Attempt to find a path to the duplicate target, if it seems it's not part + // of the duplicated and not yet parented hierarchy then at least try to connect + // to the same target as the original + + if (p_copy->has_node(ptarget)) { + copytarget = p_copy->get_node(ptarget); + } + + if (copy && copytarget && !copy->is_connected(E->get().signal, copytarget, E->get().method)) { + copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, E->get().flags); + } + } + } + + for (int i = 0; i < n->get_child_count(); i++) { + process_list.push_back(n->get_child(i)); + } } }