Browse Source

Merge pull request #64487 from Rindbee/fix-instantiated-scene-duplicate

Fix resource shared when duplicating an instanced scene
Thaddeus Crews 1 week ago
parent
commit
dec0b22f7d

+ 24 - 6
editor/docks/scene_tree_dock.cpp

@@ -907,6 +907,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				}
 				}
 			}
 			}
 
 
+			HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[edited_scene->get_scene_file_path()];
+
 			for (Node *node : selection) {
 			for (Node *node : selection) {
 				Node *parent = node->get_parent();
 				Node *parent = node->get_parent();
 
 
@@ -922,7 +924,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				}
 				}
 
 
 				HashMap<const Node *, Node *> duplimap;
 				HashMap<const Node *, Node *> duplimap;
-				Node *dup = node->duplicate_from_editor(duplimap);
+				Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
 
 
 				ERR_CONTINUE(!dup);
 				ERR_CONTINUE(!dup);
 
 
@@ -956,6 +958,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 
 
 			undo_redo->commit_action();
 			undo_redo->commit_action();
 
 
+			for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
+				for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
+					if (R.value->is_local_to_scene()) {
+						R.value->setup_local_to_scene();
+					}
+				}
+			}
+
 			if (dupsingle) {
 			if (dupsingle) {
 				_push_item(dupsingle);
 				_push_item(dupsingle);
 			}
 			}
@@ -4334,26 +4344,25 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
 	}
 	}
 	ur->add_do_method(editor_selection, "clear");
 	ur->add_do_method(editor_selection, "clear");
 
 
-	HashMap<Ref<Resource>, Ref<Resource>> resource_remap;
 	String target_scene;
 	String target_scene;
 	if (edited_scene) {
 	if (edited_scene) {
 		target_scene = edited_scene->get_scene_file_path();
 		target_scene = edited_scene->get_scene_file_path();
 	}
 	}
+	HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &resources_local_to_scenes = clipboard_resource_remap[target_scene]; // Record the mappings in the sub-scene.
 	if (target_scene != clipboard_source_scene) {
 	if (target_scene != clipboard_source_scene) {
-		if (!clipboard_resource_remap.has(target_scene)) {
+		if (!resources_local_to_scenes.has(nullptr)) {
 			HashMap<Ref<Resource>, Ref<Resource>> remap;
 			HashMap<Ref<Resource>, Ref<Resource>> remap;
 			for (Node *E : node_clipboard) {
 			for (Node *E : node_clipboard) {
 				_create_remap_for_node(E, remap);
 				_create_remap_for_node(E, remap);
 			}
 			}
-			clipboard_resource_remap[target_scene] = remap;
+			resources_local_to_scenes[nullptr] = remap;
 		}
 		}
-		resource_remap = clipboard_resource_remap[target_scene];
 	}
 	}
 
 
 	for (Node *node : node_clipboard) {
 	for (Node *node : node_clipboard) {
 		HashMap<const Node *, Node *> duplimap;
 		HashMap<const Node *, Node *> duplimap;
 
 
-		Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
+		Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes);
 		ERR_CONTINUE(!dup);
 		ERR_CONTINUE(!dup);
 
 
 		pasted_nodes.push_back(dup);
 		pasted_nodes.push_back(dup);
@@ -4396,6 +4405,15 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
 	}
 	}
 
 
 	ur->commit_action();
 	ur->commit_action();
+
+	for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &KV : resources_local_to_scenes) {
+		for (KeyValue<Ref<Resource>, Ref<Resource>> &R : KV.value) {
+			if (R.value->is_local_to_scene()) {
+				R.value->setup_local_to_scene();
+			}
+		}
+	}
+
 	return pasted_nodes;
 	return pasted_nodes;
 }
 }
 
 

+ 1 - 1
editor/docks/scene_tree_dock.h

@@ -146,7 +146,7 @@ class SceneTreeDock : public EditorDock {
 	List<Node *> node_clipboard;
 	List<Node *> node_clipboard;
 	HashSet<Node *> node_clipboard_edited_scene_owned;
 	HashSet<Node *> node_clipboard_edited_scene_owned;
 	String clipboard_source_scene;
 	String clipboard_source_scene;
-	HashMap<String, HashMap<Ref<Resource>, Ref<Resource>>> clipboard_resource_remap;
+	HashMap<String, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>>> clipboard_resource_remap;
 
 
 	ScriptCreateDialog *script_create_dialog = nullptr;
 	ScriptCreateDialog *script_create_dialog = nullptr;
 	ShaderCreateDialog *shader_create_dialog = nullptr;
 	ShaderCreateDialog *shader_create_dialog = nullptr;

+ 33 - 14
scene/main/node.cpp

@@ -2953,10 +2953,11 @@ Node *Node::duplicate(int p_flags) const {
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const {
 Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const {
-	return duplicate_from_editor(r_duplimap, HashMap<Ref<Resource>, Ref<Resource>>());
+	HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> tmp;
+	return duplicate_from_editor(r_duplimap, nullptr, tmp);
 }
 }
 
 
-Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
+Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const {
 	int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR;
 	int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR;
 	Node *dupe = _duplicate(flags, &r_duplimap);
 	Node *dupe = _duplicate(flags, &r_duplimap);
 
 
@@ -2969,8 +2970,8 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con
 	_duplicate_properties(this, this, dupe, flags);
 	_duplicate_properties(this, this, dupe, flags);
 
 
 	// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
 	// 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);
+	if (p_scene_root) {
+		remap_node_resources(dupe, p_scene_root, p_resource_remap);
 	}
 	}
 
 
 	// Duplication of signals must happen after all the node descendants have been copied,
 	// Duplication of signals must happen after all the node descendants have been copied,
@@ -2981,7 +2982,9 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con
 	return dupe;
 	return dupe;
 }
 }
 
 
-void Node::remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
+void Node::remap_node_resources(Node *p_node, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const {
+	Node *local_scene = p_node->is_instance() ? p_node : (p_node->get_owner() ? p_node->get_owner() : p_scene_root);
+
 	List<PropertyInfo> props;
 	List<PropertyInfo> props;
 	p_node->get_property_list(&props);
 	p_node->get_property_list(&props);
 
 
@@ -2991,23 +2994,39 @@ void Node::remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<R
 		}
 		}
 
 
 		Variant v = p_node->get(E.name);
 		Variant v = p_node->get(E.name);
-		if (v.is_ref_counted()) {
-			Ref<Resource> res = v;
-			if (res.is_valid()) {
-				if (p_resource_remap.has(res)) {
-					p_node->set(E.name, p_resource_remap[res]);
-					remap_nested_resources(res, p_resource_remap);
-				}
+		if (!v.is_ref_counted()) {
+			continue;
+		}
+		Ref<Resource> res = v;
+		if (res.is_null()) {
+			continue;
+		}
+
+		if (res->is_local_to_scene()) {
+			if (local_scene == res->get_local_scene()) {
+				continue;
+			}
+			Ref<Resource> dup = SceneState::get_remap_resource(res, p_resource_remap, nullptr, local_scene);
+			p_node->set(E.name, dup);
+			continue;
+		}
+
+		if (res->is_built_in()) {
+			// Use nullptr instead of a specific node (current scene root node) to represent the scene,
+			// as the Make Scene Root operation may be executed.
+			if (p_resource_remap[nullptr].has(res)) {
+				p_node->set(E.name, p_resource_remap[nullptr][res]);
+				remap_nested_resources(res, p_resource_remap[nullptr]);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	for (int i = 0; i < p_node->get_child_count(); i++) {
 	for (int i = 0; i < p_node->get_child_count(); i++) {
-		remap_node_resources(p_node->get_child(i), p_resource_remap);
+		remap_node_resources(p_node->get_child(i), p_scene_root, p_resource_remap);
 	}
 	}
 }
 }
 
 
-void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
+void Node::remap_nested_resources(Ref<Resource> p_resource, HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const {
 	List<PropertyInfo> props;
 	List<PropertyInfo> props;
 	p_resource->get_property_list(&props);
 	p_resource->get_property_list(&props);
 
 

+ 3 - 3
scene/main/node.h

@@ -721,9 +721,9 @@ public:
 	Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
 	Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const;
 	Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap) const;
-	Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
-	void remap_node_resources(Node *p_node, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
-	void remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
+	Node *duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const;
+	void remap_node_resources(Node *p_node, Node *p_scene_root, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resource_remap) const;
+	void remap_nested_resources(Ref<Resource> p_resource, HashMap<Ref<Resource>, Ref<Resource>> &p_resource_remap) const;
 #endif
 #endif
 
 
 	// used by editors, to save what has changed only
 	// used by editors, to save what has changed only

+ 57 - 53
scene/resources/packed_scene.cpp

@@ -78,18 +78,28 @@ static Array _sanitize_node_pinned_properties(Node *p_node) {
 	return pinned;
 	return pinned;
 }
 }
 
 
-Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene) {
+Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene) {
 	ERR_FAIL_COND_V(p_resource.is_null(), Ref<Resource>());
 	ERR_FAIL_COND_V(p_resource.is_null(), Ref<Resource>());
 
 
-	Ref<Resource> remap_resource;
-
 	// Find the shared copy of the source resource.
 	// Find the shared copy of the source resource.
-	HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = remap_cache.find(p_resource);
+	HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = remap_cache[p_for_scene].find(p_resource);
 	if (R) {
 	if (R) {
-		remap_resource = R->value;
-	} else if (p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class() == p_resource->get_class()) {
-		// Simply copy the data from the source resource to update the fallback resource that was previously set.
+		return R->value;
+	}
+
+	bool reuse_fallback = p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class_name() == p_resource->get_class_name();
+
+	if (reuse_fallback) {
+		// The fallback resource can only be mapped at most once when it is valid.
+		for (const KeyValue<Ref<Resource>, Ref<Resource>> &E : remap_cache[p_for_scene]) {
+			if (E.value == p_fallback) {
+				reuse_fallback = false;
+				break;
+			}
+		}
+	}
 
 
+	if (reuse_fallback) { // Simply copy the data from the source resource to update the fallback resource that was previously set.
 		p_fallback->reset_state(); // May want to reset state.
 		p_fallback->reset_state(); // May want to reset state.
 
 
 		List<PropertyInfo> pi;
 		List<PropertyInfo> pi;
@@ -113,18 +123,14 @@ Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, Ha
 
 
 			p_fallback->set(E.name, value);
 			p_fallback->set(E.name, value);
 		}
 		}
-
-		p_fallback->set_scene_unique_id(p_resource->get_scene_unique_id()); // Get the id from the main scene, in case the id changes again when saving the scene.
-
-		remap_cache[p_resource] = p_fallback;
-		remap_resource = p_fallback;
-	} else { // A copy of the source resource is required to overwrite the previous one.
-		Ref<Resource> local_dupe = p_resource->duplicate_for_local_scene(p_for_scene, remap_cache);
-		remap_cache[p_resource] = local_dupe;
-		remap_resource = local_dupe;
+		remap_cache[p_for_scene][p_resource] = p_fallback;
+		return p_fallback;
 	}
 	}
 
 
-	return remap_resource;
+	// A copy of the source resource is required to overwrite the previous one.
+	Ref<Resource> local_dupe = p_resource->duplicate_for_local_scene(p_for_scene, remap_cache[p_for_scene]);
+	remap_cache[p_for_scene][p_resource] = local_dupe;
+	return local_dupe;
 }
 }
 
 
 static Node *_find_node_by_id(Node *p_owner, Node *p_node, int32_t p_id) {
 static Node *_find_node_by_id(Node *p_owner, Node *p_node, int32_t p_id) {
@@ -185,7 +191,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 
 
 	bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.is_empty();
 	bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.is_empty();
 
 
-	HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
+	HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> resources_local_to_scenes; // Record the mappings in sub-scenes.
 
 
 	LocalVector<DeferredNodePathProperties> deferred_node_paths;
 	LocalVector<DeferredNodePathProperties> deferred_node_paths;
 
 
@@ -359,7 +365,6 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 				const NodeData::Property *nprops = &n.properties[0];
 				const NodeData::Property *nprops = &n.properties[0];
 
 
 				Dictionary missing_resource_properties;
 				Dictionary missing_resource_properties;
-				HashMap<Ref<Resource>, Ref<Resource>> resources_local_to_sub_scene; // Record the mappings in the sub-scene.
 
 
 				for (int j = 0; j < nprop_count; j++) {
 				for (int j = 0; j < nprop_count; j++) {
 					bool valid;
 					bool valid;
@@ -430,7 +435,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 							//handle resources that are local to scene by duplicating them if needed
 							//handle resources that are local to scene by duplicating them if needed
 							Ref<Resource> res = value;
 							Ref<Resource> res = value;
 							if (res.is_valid()) {
 							if (res.is_valid()) {
-								value = make_local_resource(value, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state);
+								value = make_local_resource(value, n, resources_local_to_scenes, node, snames[nprops[j].name], i, ret_nodes, p_edit_state);
 							}
 							}
 						} else {
 						} else {
 							// Making sure that instances of inherited scenes don't share the same
 							// Making sure that instances of inherited scenes don't share the same
@@ -454,7 +459,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 								}
 								}
 							}
 							}
 
 
-							value = setup_resources_in_array(set_array, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state);
+							value = setup_resources_in_array(set_array, n, resources_local_to_scenes, node, snames[nprops[j].name], i, ret_nodes, p_edit_state);
 						}
 						}
 
 
 						if (value.get_type() == Variant::DICTIONARY) {
 						if (value.get_type() == Variant::DICTIONARY) {
@@ -471,7 +476,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 								}
 								}
 							}
 							}
 
 
-							value = setup_resources_in_dictionary(set_dict, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state);
+							value = setup_resources_in_dictionary(set_dict, n, resources_local_to_scenes, node, snames[nprops[j].name], i, ret_nodes, p_edit_state);
 						}
 						}
 
 
 						bool set_valid = true;
 						bool set_valid = true;
@@ -494,12 +499,6 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 				if (!missing_resource_properties.is_empty()) {
 				if (!missing_resource_properties.is_empty()) {
 					node->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
 					node->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
 				}
 				}
-
-				for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_sub_scene) {
-					if (E.value->get_local_scene() == node) {
-						E.value->setup_local_to_scene(); // Setup may be required for the resource to work properly.
-					}
-				}
 			}
 			}
 
 
 			//name
 			//name
@@ -639,9 +638,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 		}
 		}
 	}
 	}
 
 
-	for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
-		if (E.value->get_local_scene() == ret_nodes[0]) {
-			E.value->setup_local_to_scene();
+	for (KeyValue<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &E : resources_local_to_scenes) {
+		for (KeyValue<Ref<Resource>, Ref<Resource>> &R : E.value) {
+			R.value->setup_local_to_scene(); // Setup may be required for the resource to work properly.
 		}
 		}
 	}
 	}
 
 
@@ -702,41 +701,46 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
 	return ret_nodes[0];
 	return ret_nodes[0];
 }
 }
 
 
-Variant SceneState::make_local_resource(Variant &p_value, const SceneState::NodeData &p_node_data, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
+Variant SceneState::make_local_resource(Variant &p_value, const SceneState::NodeData &p_node_data, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *p_node, const StringName p_sname, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
 	Ref<Resource> res = p_value;
 	Ref<Resource> res = p_value;
 	if (res.is_null() || !res->is_local_to_scene()) {
 	if (res.is_null() || !res->is_local_to_scene()) {
 		return p_value;
 		return p_value;
 	}
 	}
 
 
-	if (p_node_data.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene.
-		return get_remap_resource(res, p_resources_local_to_sub_scene, p_node->get(p_sname), p_node);
-	} else {
-		HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(res);
-		Node *base = p_i == 0 ? p_node : p_ret_nodes[0];
-		if (E) {
-			return E->value;
-		} else if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is
-			res->configure_for_local_scene(base, p_resources_local_to_scene);
-			p_resources_local_to_scene[res] = res;
-			return res;
-		} else { // For instances, a copy must be made.
-			Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, p_resources_local_to_scene);
-			p_resources_local_to_scene[res] = local_dupe;
-			return local_dupe;
-		}
+	Node *base = (p_i == 0 || p_node->is_instance()) ? p_node : (p_node->get_owner() ? p_node->get_owner() : p_ret_nodes[0]);
+
+	if (p_node_data.type == TYPE_INSTANTIATED) { // For the (root) nodes of sub-scenes, treat them as parts of the sub-scenes.
+		return get_remap_resource(res, p_resources_local_to_scenes, p_node->get(p_sname), base);
+	}
+
+	// Find the shared copy of the source resource.
+	HashMap<Ref<Resource>, Ref<Resource>>::Iterator R = p_resources_local_to_scenes[base].find(res);
+	if (R) {
+		return R->value;
 	}
 	}
+
+	if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is
+		res->configure_for_local_scene(base, p_resources_local_to_scenes[base]);
+		p_resources_local_to_scenes[base][res] = res;
+		return res;
+	}
+
+	// For instances, a copy must be made.
+	Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, p_resources_local_to_scenes[base]);
+	p_resources_local_to_scenes[base][res] = local_dupe;
+	return local_dupe;
 }
 }
 
 
-Array SceneState::setup_resources_in_array(Array &p_array_to_scan, const SceneState::NodeData &p_n, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
+Array SceneState::setup_resources_in_array(Array &p_array_to_scan, const SceneState::NodeData &p_n, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *p_node, const StringName p_sname, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
 	for (int i = 0; i < p_array_to_scan.size(); i++) {
 	for (int i = 0; i < p_array_to_scan.size(); i++) {
 		if (p_array_to_scan[i].get_type() == Variant::OBJECT) {
 		if (p_array_to_scan[i].get_type() == Variant::OBJECT) {
-			p_array_to_scan[i] = make_local_resource(p_array_to_scan[i], p_n, p_resources_local_to_sub_scene, p_node, p_sname, p_resources_local_to_scene, p_i, p_ret_nodes, p_edit_state);
+			p_array_to_scan[i] = make_local_resource(p_array_to_scan[i], p_n, p_resources_local_to_scenes, p_node, p_sname, p_i, p_ret_nodes, p_edit_state);
 		}
 		}
 	}
 	}
 	return p_array_to_scan;
 	return p_array_to_scan;
 }
 }
 
 
-Dictionary SceneState::setup_resources_in_dictionary(Dictionary &p_dictionary_to_scan, const SceneState::NodeData &p_n, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
+Dictionary SceneState::setup_resources_in_dictionary(Dictionary &p_dictionary_to_scan, const SceneState::NodeData &p_n, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *p_node, const StringName p_sname, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const {
 	const Array keys = p_dictionary_to_scan.keys();
 	const Array keys = p_dictionary_to_scan.keys();
 	const Array values = p_dictionary_to_scan.values();
 	const Array values = p_dictionary_to_scan.values();
 
 
@@ -744,8 +748,8 @@ Dictionary SceneState::setup_resources_in_dictionary(Dictionary &p_dictionary_to
 		Array duplicated_keys = keys.duplicate(true);
 		Array duplicated_keys = keys.duplicate(true);
 		Array duplicated_values = values.duplicate(true);
 		Array duplicated_values = values.duplicate(true);
 
 
-		duplicated_keys = setup_resources_in_array(duplicated_keys, p_n, p_resources_local_to_sub_scene, p_node, p_sname, p_resources_local_to_scene, p_i, p_ret_nodes, p_edit_state);
-		duplicated_values = setup_resources_in_array(duplicated_values, p_n, p_resources_local_to_sub_scene, p_node, p_sname, p_resources_local_to_scene, p_i, p_ret_nodes, p_edit_state);
+		duplicated_keys = setup_resources_in_array(duplicated_keys, p_n, p_resources_local_to_scenes, p_node, p_sname, p_i, p_ret_nodes, p_edit_state);
+		duplicated_values = setup_resources_in_array(duplicated_values, p_n, p_resources_local_to_scenes, p_node, p_sname, p_i, p_ret_nodes, p_edit_state);
 		p_dictionary_to_scan.clear();
 		p_dictionary_to_scan.clear();
 
 
 		for (int i = 0; i < keys.size(); i++) {
 		for (int i = 0; i < keys.size(); i++) {

+ 4 - 4
scene/resources/packed_scene.h

@@ -139,7 +139,7 @@ public:
 	};
 	};
 
 
 	static void set_disable_placeholders(bool p_disable);
 	static void set_disable_placeholders(bool p_disable);
-	static Ref<Resource> get_remap_resource(const Ref<Resource> &p_resource, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene);
+	static Ref<Resource> get_remap_resource(const Ref<Resource> &p_resource, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene);
 
 
 	int find_node_by_path(const NodePath &p_node) const;
 	int find_node_by_path(const NodePath &p_node) const;
 	Variant get_property_value(int p_node, const StringName &p_property, bool &r_found, bool &r_node_deferred) const;
 	Variant get_property_value(int p_node, const StringName &p_property, bool &r_found, bool &r_node_deferred) const;
@@ -160,9 +160,9 @@ public:
 	bool can_instantiate() const;
 	bool can_instantiate() const;
 	Node *instantiate(GenEditState p_edit_state) const;
 	Node *instantiate(GenEditState p_edit_state) const;
 
 
-	Array setup_resources_in_array(Array &array_to_scan, const SceneState::NodeData &n, HashMap<Ref<Resource>, Ref<Resource>> &resources_local_to_sub_scene, Node *node, const StringName sname, HashMap<Ref<Resource>, Ref<Resource>> &resources_local_to_scene, int i, Node **ret_nodes, SceneState::GenEditState p_edit_state) const;
-	Dictionary setup_resources_in_dictionary(Dictionary &p_dictionary_to_scan, const SceneState::NodeData &p_n, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const;
-	Variant make_local_resource(Variant &value, const SceneState::NodeData &p_node_data, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const;
+	Array setup_resources_in_array(Array &array_to_scan, const SceneState::NodeData &n, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *node, const StringName sname, int i, Node **ret_nodes, SceneState::GenEditState p_edit_state) const;
+	Dictionary setup_resources_in_dictionary(Dictionary &p_dictionary_to_scan, const SceneState::NodeData &p_n, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *p_node, const StringName p_sname, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const;
+	Variant make_local_resource(Variant &value, const SceneState::NodeData &p_node_data, HashMap<Node *, HashMap<Ref<Resource>, Ref<Resource>>> &p_resources_local_to_scenes, Node *p_node, const StringName p_sname, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const;
 	bool has_local_resource(const Array &p_array) const;
 	bool has_local_resource(const Array &p_array) const;
 
 
 	Ref<SceneState> get_base_scene_state() const;
 	Ref<SceneState> get_base_scene_state() const;