Jelajahi Sumber

Merge pull request #13041 from RandomShaper/unify-node-duplicate

 Let SceneTreeDock duplicate nodes via Node::duplicate()
Rémi Verschelde 7 tahun lalu
induk
melakukan
49a73182d3
4 mengubah file dengan 45 tambahan dan 88 penghapusan
  1. 2 78
      editor/scene_tree_dock.cpp
  2. 0 1
      editor/scene_tree_dock.h
  3. 35 7
      scene/main/node.cpp
  4. 8 2
      scene/main/node.h

+ 2 - 78
editor/scene_tree_dock.cpp

@@ -443,8 +443,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				List<Node *> owned;
 				node->get_owned_by(node->get_owner(), &owned);
 
-				Map<Node *, Node *> duplimap;
-				Node *dup = _duplicate(node, duplimap);
+				Map<const Node *, Node *> duplimap;
+				Node *dup = node->duplicate_from_editor(duplimap);
 
 				ERR_CONTINUE(!dup);
 
@@ -821,82 +821,6 @@ void SceneTreeDock::_node_renamed() {
 	_node_selected();
 }
 
-Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node *, Node *> &duplimap) {
-
-	Node *node = NULL;
-
-	if (p_node->get_filename() != "") { //an instance
-
-		Ref<PackedScene> sd = ResourceLoader::load(p_node->get_filename());
-		ERR_FAIL_COND_V(!sd.is_valid(), NULL);
-		node = sd->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
-		ERR_FAIL_COND_V(!node, NULL);
-		node->set_scene_instance_load_placeholder(p_node->get_scene_instance_load_placeholder());
-	} else {
-		Object *obj = ClassDB::instance(p_node->get_class());
-		ERR_FAIL_COND_V(!obj, NULL);
-		node = Object::cast_to<Node>(obj);
-		if (!node)
-			memdelete(obj);
-		ERR_FAIL_COND_V(!node, NULL);
-	}
-
-	List<PropertyInfo> plist;
-
-	p_node->get_property_list(&plist);
-
-	for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
-
-		if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
-			continue;
-		String name = E->get().name;
-		Variant value = p_node->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();
-		}
-		node->set(name, value);
-	}
-
-	List<Connection> conns;
-	p_node->get_all_signal_connections(&conns);
-	for (List<Connection>::Element *E = conns.front(); E; E = E->next()) {
-		if (E->get().flags & CONNECT_PERSIST) {
-			node->connect(E->get().signal, E->get().target, E->get().method, E->get().binds, E->get().flags);
-		}
-	}
-
-	List<Node::GroupInfo> group_info;
-	p_node->get_groups(&group_info);
-	for (List<Node::GroupInfo>::Element *E = group_info.front(); E; E = E->next()) {
-
-		if (E->get().persistent)
-			node->add_to_group(E->get().name, true);
-	}
-
-	node->set_name(p_node->get_name());
-	duplimap[p_node] = node;
-
-	for (int i = 0; i < p_node->get_child_count(); i++) {
-
-		Node *child = p_node->get_child(i);
-		if (p_node->get_owner() != child->get_owner())
-			continue; //don't bother with not in-scene nodes.
-
-		Node *dup = _duplicate(child, duplimap);
-		if (!dup) {
-			memdelete(node);
-			return NULL;
-		}
-
-		node->add_child(dup);
-	}
-
-	return node;
-}
-
 void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) {
 
 	for (int i = 0; i < p_nodes.size(); i++) {

+ 0 - 1
editor/scene_tree_dock.h

@@ -130,7 +130,6 @@ class SceneTreeDock : public VBoxContainer {
 
 	void _add_children_to_popup(Object *p_obj, int p_depth);
 
-	Node *_duplicate(Node *p_node, Map<Node *, Node *> &duplimap);
 	void _node_reparent(NodePath p_path, bool p_keep_global_xform);
 	void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
 

+ 35 - 7
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;
@@ -2099,10 +2104,6 @@ Node *Node::_duplicate(int p_flags) const {
 		ERR_FAIL_COND_V(!node, NULL);
 	}
 
-	if (get_filename() != "") { //an instance
-		node->set_filename(get_filename());
-	}
-
 	List<PropertyInfo> plist;
 
 	get_property_list(&plist);
@@ -2138,11 +2139,21 @@ Node *Node::_duplicate(int p_flags) const {
 
 	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);
 		}
 	}
@@ -2154,7 +2165,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);
@@ -2178,6 +2189,20 @@ Node *Node::duplicate(int p_flags) const {
 	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())
@@ -2325,6 +2350,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;
 }

+ 8 - 2
scene/main/node.h

@@ -58,7 +58,10 @@ public:
 		DUPLICATE_SIGNALS = 1,
 		DUPLICATE_GROUPS = 2,
 		DUPLICATE_SCRIPTS = 4,
-		DUPLICATE_USE_INSTANCING = 8
+		DUPLICATE_USE_INSTANCING = 8,
+#ifdef TOOLS_ENABLED
+		DUPLICATE_FROM_EDITOR = 16,
+#endif
 	};
 
 	enum RPCMode {
@@ -169,7 +172,7 @@ private:
 
 	void _duplicate_signals(const Node *p_original, Node *p_copy) const;
 	void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
-	Node *_duplicate(int p_flags) const;
+	Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = NULL) const;
 
 	Array _get_children() const;
 	Array _get_groups() const;
@@ -326,6 +329,9 @@ public:
 
 	Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
 	Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;
+#ifdef TOOLS_ENABLED
+	Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;
+#endif
 
 	//Node *clone_tree() const;