diff options
Diffstat (limited to 'scene/main/node.cpp')
-rw-r--r-- | scene/main/node.cpp | 107 |
1 files changed, 69 insertions, 38 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e730f47607..820cb7571f 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -202,6 +202,11 @@ void Node::_notification(int p_notification) { _clean_up_owner(); } + while (!data.owned.is_empty()) { + Node *n = data.owned.back()->get(); + n->_clean_up_owner(); // This will change data.owned. So it's impossible to loop over the list in the usual manner. + } + if (data.parent) { data.parent->remove_child(this); } @@ -1415,6 +1420,14 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead."); _validate_child_name(p_child, p_force_readable_name); + +#ifdef DEBUG_ENABLED + if (p_child->data.owner && !p_child->data.owner->is_ancestor_of(p_child)) { + // Owner of p_child should be ancestor of p_child. + WARN_PRINT(vformat("Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand.", p_child->get_name(), get_name(), p_child->data.owner->get_name())); + } +#endif // DEBUG_ENABLED + _add_child_nocheck(p_child, p_child->data.name, p_internal); } @@ -2515,44 +2528,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } - for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { - Node *current_node = node->get_node(get_path_to(N->get())); - ERR_CONTINUE(!current_node); - - if (p_flags & DUPLICATE_SCRIPTS) { - bool is_valid = false; - Variant scr = N->get()->get(script_property_name, &is_valid); - if (is_valid) { - current_node->set(script_property_name, scr); - } - } - - List<PropertyInfo> plist; - N->get()->get_property_list(&plist); - - for (const PropertyInfo &E : plist) { - if (!(E.usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - String name = E.name; - if (name == script_property_name) { - continue; - } - - Variant value = N->get()->get(name).duplicate(true); - - if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { - Resource *res = Object::cast_to<Resource>(value); - if (res) { // Duplicate only if it's a resource - current_node->set(name, res->duplicate()); - } - - } else { - current_node->set(name, value); - } - } - } - if (get_name() != String()) { node->set_name(get_name()); } @@ -2618,6 +2593,62 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } + for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { + Node *current_node = node->get_node(get_path_to(N->get())); + ERR_CONTINUE(!current_node); + + if (p_flags & DUPLICATE_SCRIPTS) { + bool is_valid = false; + Variant scr = N->get()->get(script_property_name, &is_valid); + if (is_valid) { + current_node->set(script_property_name, scr); + } + } + + List<PropertyInfo> plist; + N->get()->get_property_list(&plist); + + for (const PropertyInfo &E : plist) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + String name = E.name; + if (name == script_property_name) { + continue; + } + + Variant value = N->get()->get(name).duplicate(true); + + if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) { + Resource *res = Object::cast_to<Resource>(value); + if (res) { // Duplicate only if it's a resource + current_node->set(name, res->duplicate()); + } + + } else { + // If property points to a node which is owned by a node we are duplicating, update its path. + if (value.get_type() == Variant::OBJECT) { + Node *property_node = Object::cast_to<Node>(value); + if (property_node && is_ancestor_of(property_node)) { + value = current_node->get_node_or_null(get_path_to(property_node)); + } + } else if (value.get_type() == Variant::ARRAY) { + Array arr = value; + if (arr.get_typed_builtin() == Variant::OBJECT) { + for (int i = 0; i < arr.size(); i++) { + Node *property_node = Object::cast_to<Node>(arr[i]); + if (property_node && is_ancestor_of(property_node)) { + arr[i] = current_node->get_node_or_null(get_path_to(property_node)); + } + } + value = arr; + } + } + current_node->set(name, value); + } + } + } + return node; } |