Repository: godotengine/godot
File: scene/main/node.cpp (C++)

Code before:

	for (const Node *&E : hidden_roots) {
		Node *parent = node->get_node(get_path_to(E->data.parent));
		if (!parent) {
			memdelete(node);
			return nullptr;
		}

		Node *dup = E->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);
			return nullptr;
		}

		parent->add_child(dup);
		int pos = E->get_index();

		if (pos < parent->get_child_count() - 1) {
			parent->move_child(dup, pos);
		}
	}

	return node;
}

Node *Node::duplicate(int p_flags) const {
	ERR_THREAD_GUARD_V(nullptr);
	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(HashMap<const Node *, Node *> &r_duplimap) const {
	return duplicate_from_editor(r_duplimap, HashMap<Ref<Resource>, Ref<Resource>>());
}

Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
	Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR, &r_duplimap);

	// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
	if (!p_resource_remap.is_empty()) {
		remap_node_resources(dupe, p_resource_remap);
	}

	// 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

Review comment (suggestion):
This won't handle non-typed Arrays, which can hold Objects too, but I guess it's not that important (and the current code is more performant).

Code after:
			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;
}

Node *Node::duplicate(int p_flags) const {
	ERR_THREAD_GUARD_V(nullptr);
	Node *dupe = _duplicate(p_flags);

	if (dupe && (p_flags & DUPLICATE_SIGNALS)) {
		_duplicate_signals(this, dupe);
	}