diff options
Diffstat (limited to 'scene/main/node.cpp')
-rw-r--r--[-rwxr-xr-x] | scene/main/node.cpp | 162 |
1 files changed, 119 insertions, 43 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d38c688241..31d423c808 100755..100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2067,7 +2067,7 @@ int Node::get_position_in_parent() const { return data.pos; } -Node *Node::duplicate(int p_flags) const { +Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const { Node *node = NULL; @@ -2084,7 +2084,12 @@ Node *Node::duplicate(int p_flags) const { Ref<PackedScene> res = ResourceLoader::load(get_filename()); ERR_FAIL_COND_V(res.is_null(), NULL); - node = res->instance(); + PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED; +#ifdef TOOLS_ENABLED + if (p_flags & DUPLICATE_FROM_EDITOR) + ges = PackedScene::GEN_EDIT_STATE_INSTANCE; +#endif + node = res->instance(ges); ERR_FAIL_COND_V(!node, NULL); instanced = true; @@ -2103,53 +2108,78 @@ Node *Node::duplicate(int p_flags) const { node->set_filename(get_filename()); } - List<PropertyInfo> plist; - - get_property_list(&plist); - StringName script_property_name = CoreStringNames::get_singleton()->_script; - if (p_flags & DUPLICATE_SCRIPTS) { - bool is_valid = false; - Variant script = get(script_property_name, &is_valid); - if (is_valid) { - node->set(script_property_name, script); + List<const Node *> node_tree; + node_tree.push_front(this); + + if (instanced) { + for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { + for (int i = 0; i < N->get()->get_child_count(); ++i) { + node_tree.push_back(N->get()->get_child(i)); + } } } - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) - continue; - String name = E->get().name; - if (name == script_property_name) - continue; + Node *current_node = node->get_node(get_path_to(N->get())); - Variant value = get(name); - // Duplicate dictionaries and arrays, mainly needed for __meta__ - if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).copy(); - } else if (value.get_type() == Variant::ARRAY) { - value = Array(value).duplicate(); + if (p_flags & DUPLICATE_SCRIPTS) { + bool is_valid = false; + Variant script = N->get()->get(script_property_name, &is_valid); + if (is_valid) { + current_node->set(script_property_name, script); + } } - node->set(name, value); + List<PropertyInfo> plist; + N->get()->get_property_list(&plist); + + if (!current_node) + continue; + + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + String name = E->get().name; + if (name == script_property_name) + continue; + + Variant value = N->get()->get(name); + // Duplicate dictionaries and arrays, mainly needed for __meta__ + if (value.get_type() == Variant::DICTIONARY) { + value = Dictionary(value).copy(); + } else if (value.get_type() == Variant::ARRAY) { + value = Array(value).duplicate(); + } + + current_node->set(name, value); + } } node->set_name(get_name()); +#ifdef TOOLS_ENABLED + if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) + r_duplimap->insert(this, node); +#endif + if (p_flags & DUPLICATE_GROUPS) { List<GroupInfo> gi; get_groups(&gi); for (List<GroupInfo>::Element *E = gi.front(); E; E = E->next()) { +#ifdef TOOLS_ENABLED + if ((p_flags & DUPLICATE_FROM_EDITOR) && !E->get().persistent) + continue; +#endif + node->add_to_group(E->get().name, E->get().persistent); } } - if (p_flags & DUPLICATE_SIGNALS) - _duplicate_signals(this, node); - for (int i = 0; i < get_child_count(); i++) { if (get_child(i)->data.parent_owned) @@ -2157,7 +2187,7 @@ Node *Node::duplicate(int p_flags) const { if (instanced && get_child(i)->data.owner == this) continue; //part of instance - Node *dup = get_child(i)->duplicate(p_flags); + Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap); if (!dup) { memdelete(node); @@ -2170,6 +2200,31 @@ Node *Node::duplicate(int p_flags) const { return node; } +Node *Node::duplicate(int p_flags) const { + + Node *dupe = _duplicate(p_flags); + + if (dupe && (p_flags & DUPLICATE_SIGNALS)) { + _duplicate_signals(this, dupe); + } + + return dupe; +} + +#ifdef TOOLS_ENABLED +Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const { + + Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap); + + // Duplication of signals must happen after all the node descendants have been copied, + // because re-targeting of connections from some descendant to another is not possible + // if the emitter node comes later in tree order than the receiver + _duplicate_signals(this, dupe); + + return dupe; +} +#endif + void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const { if (get_owner() != get_parent()->get_owner()) @@ -2240,6 +2295,9 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p } } +// Duplication of signals must happen after all the node descendants have been copied, +// because re-targeting of connections from some descendant to another is not possible +// 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())) @@ -2262,8 +2320,14 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { NodePath ptarget = p_original->get_path_to(target); Node *copytarget = p_copy->get_node(ptarget); + // Cannot find a path to the duplicate target, so it seems it's not part + // of the duplicated and not yet parented hierarchy, so at least try to connect + // to the same target as the original + if (!copytarget) + copytarget = target; + if (copy && copytarget) { - copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, CONNECT_PERSIST); + copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, E->get().flags); } } } @@ -2308,6 +2372,9 @@ Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const { get_child(i)->_duplicate_and_reown(node, p_reown_map); } + // Duplication of signals must happen after all the node descendants have been copied, + // because re-targeting of connections from some descendant to another is not possible + // if the emitter node comes later in tree order than the receiver _duplicate_signals(this, node); return node; } @@ -2457,24 +2524,19 @@ bool Node::has_node_and_resource(const NodePath &p_path) const { return false; Node *node = get_node(p_path); - if (p_path.get_subname_count()) { + bool result = false; - RES r; - for (int j = 0; j < p_path.get_subname_count(); j++) { - r = j == 0 ? node->get(p_path.get_subname(j)) : r->get(p_path.get_subname(j)); - if (r.is_null()) - return false; - } - } + node->get_indexed(p_path.get_subnames(), &result); - return true; + return result; } Array Node::_get_node_and_resource(const NodePath &p_path) { Node *node; RES res; - node = get_node_and_resource(p_path, res); + Vector<StringName> leftover_path; + node = get_node_and_resource(p_path, res, leftover_path); Array result; if (node) @@ -2487,21 +2549,35 @@ Array Node::_get_node_and_resource(const NodePath &p_path) { else result.push_back(Variant()); + result.push_back(NodePath(Vector<StringName>(), leftover_path, false)); + return result; } -Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res) const { +Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property) const { Node *node = get_node(p_path); r_res = RES(); + r_leftover_subpath = Vector<StringName>(); if (!node) return NULL; if (p_path.get_subname_count()) { - for (int j = 0; j < p_path.get_subname_count(); j++) { - r_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j)); - ERR_FAIL_COND_V(r_res.is_null(), node); + int j = 0; + // If not p_last_is_property, we shouldn't consider the last one as part of the resource + for (; j < p_path.get_subname_count() - p_last_is_property; j++) { + RES new_res = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j)); + + if (new_res.is_null()) { + break; + } + + r_res = new_res; + } + for (; j < p_path.get_subname_count(); j++) { + // Put the rest of the subpath in the leftover path + r_leftover_subpath.push_back(p_path.get_subname(j)); } } |