From 1b4f116db14123b4cfab655de40d2e4f81aea517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E9=9D=92=E5=B1=B1?= Date: Sun, 10 Sep 2023 22:04:50 +0800 Subject: [PATCH 1/2] Supplement the case of scene instantiation for "Editable Children" This is a follow-up to #65011. For scenes with **Editable Children** enabled, the main scene will record more information and resource mapping will be valid for multiple nodes. --- scene/resources/packed_scene.cpp | 106 +++++++++++++++---------------- scene/resources/packed_scene.h | 8 +-- 2 files changed, 56 insertions(+), 58 deletions(-) diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 7475a527e41..24df002bb88 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -78,18 +78,22 @@ static Array _sanitize_node_pinned_properties(Node *p_node) { return pinned; } -Ref SceneState::get_remap_resource(const Ref &p_resource, HashMap, Ref> &remap_cache, const Ref &p_fallback, Node *p_for_scene) { +Ref SceneState::get_remap_resource(const Ref &p_resource, HashMap, Ref>> &remap_cache, const Ref &p_fallback, Node *p_for_scene) { ERR_FAIL_COND_V(p_resource.is_null(), Ref()); - Ref remap_resource; + bool reuse_fallback = p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class() == p_resource->get_class(); - // Find the shared copy of the source resource. - HashMap, Ref>::Iterator R = remap_cache.find(p_resource); - 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. + if (reuse_fallback) { + // The fallback resource can only be mapped at most once when it is valid. + for (const KeyValue, Ref> &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. List pi; @@ -113,18 +117,14 @@ Ref SceneState::get_remap_resource(const Ref &p_resource, Ha 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 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 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) { @@ -185,7 +185,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(); - HashMap, Ref> resources_local_to_scene; + HashMap, Ref>> resources_local_to_scenes; // Record the mappings in sub-scenes. LocalVector deferred_node_paths; @@ -359,7 +359,6 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { const NodeData::Property *nprops = &n.properties[0]; Dictionary missing_resource_properties; - HashMap, Ref> resources_local_to_sub_scene; // Record the mappings in the sub-scene. for (int j = 0; j < nprop_count; j++) { bool valid; @@ -430,7 +429,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { //handle resources that are local to scene by duplicating them if needed Ref res = value; 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 { // Making sure that instances of inherited scenes don't share the same @@ -454,7 +453,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) { @@ -471,7 +470,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; @@ -494,12 +493,6 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { if (!missing_resource_properties.is_empty()) { node->set_meta(META_MISSING_RESOURCES, missing_resource_properties); } - - for (KeyValue, Ref> &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 @@ -639,9 +632,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } - for (KeyValue, Ref> &E : resources_local_to_scene) { - if (E.value->get_local_scene() == ret_nodes[0]) { - E.value->setup_local_to_scene(); + for (KeyValue, Ref>> &E : resources_local_to_scenes) { + for (KeyValue, Ref> &R : E.value) { + R.value->setup_local_to_scene(); // Setup may be required for the resource to work properly. } } @@ -702,41 +695,46 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { return ret_nodes[0]; } -Variant SceneState::make_local_resource(Variant &p_value, const SceneState::NodeData &p_node_data, HashMap, Ref> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap, Ref> &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, Ref>> &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 res = p_value; if (res.is_null() || !res->is_local_to_scene()) { 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>::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 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]); + + // Find the shared copy of the source resource. + HashMap, Ref>::Iterator R = p_resources_local_to_scenes[base].find(res); + if (R) { + return R->value; } + + 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); + } + + 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 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> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap, Ref> &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, Ref>> &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++) { 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; } -Dictionary SceneState::setup_resources_in_dictionary(Dictionary &p_dictionary_to_scan, const SceneState::NodeData &p_n, HashMap, Ref> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap, Ref> &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, Ref>> &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 values = p_dictionary_to_scan.values(); @@ -744,8 +742,8 @@ Dictionary SceneState::setup_resources_in_dictionary(Dictionary &p_dictionary_to Array duplicated_keys = keys.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(); for (int i = 0; i < keys.size(); i++) { diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 9b397231552..74ebbd8b612 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -139,7 +139,7 @@ public: }; static void set_disable_placeholders(bool p_disable); - static Ref get_remap_resource(const Ref &p_resource, HashMap, Ref> &remap_cache, const Ref &p_fallback, Node *p_for_scene); + static Ref get_remap_resource(const Ref &p_resource, HashMap, Ref>> &remap_cache, const Ref &p_fallback, Node *p_for_scene); 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; @@ -160,9 +160,9 @@ public: bool can_instantiate() const; Node *instantiate(GenEditState p_edit_state) const; - Array setup_resources_in_array(Array &array_to_scan, const SceneState::NodeData &n, HashMap, Ref> &resources_local_to_sub_scene, Node *node, const StringName sname, HashMap, Ref> &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> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap, Ref> &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> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap, Ref> &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, Ref>> &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, Ref>> &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, Ref>> &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; Ref get_base_scene_state() const; From e0532a711ae0458003c0cf7addeb351bc39a1853 Mon Sep 17 00:00:00 2001 From: Rindbee Date: Mon, 29 Aug 2022 07:50:36 +0800 Subject: [PATCH 2/2] Fix resource shared when duplicating an instanced scene For resources with `resource_local_to_scene` enabled in the sub-scene, the resource is already set when the sub-scene is instantiated, so does not need to be set again. Just needs to update the property of the resource according to the value in the main scene. --- editor/docks/scene_tree_dock.cpp | 30 ++++++++++++++++---- editor/docks/scene_tree_dock.h | 2 +- scene/main/node.cpp | 47 ++++++++++++++++++++++---------- scene/main/node.h | 6 ++-- scene/resources/packed_scene.cpp | 16 +++++++---- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index c2713a1f5da..f0e362ffed6 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -907,6 +907,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } + HashMap, Ref>> &resources_local_to_scenes = clipboard_resource_remap[edited_scene->get_scene_file_path()]; + for (Node *node : selection) { Node *parent = node->get_parent(); @@ -922,7 +924,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } HashMap duplimap; - Node *dup = node->duplicate_from_editor(duplimap); + Node *dup = node->duplicate_from_editor(duplimap, edited_scene, resources_local_to_scenes); ERR_CONTINUE(!dup); @@ -956,6 +958,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { undo_redo->commit_action(); + for (KeyValue, Ref>> &KV : resources_local_to_scenes) { + for (KeyValue, Ref> &R : KV.value) { + if (R.value->is_local_to_scene()) { + R.value->setup_local_to_scene(); + } + } + } + if (dupsingle) { _push_item(dupsingle); } @@ -4334,26 +4344,25 @@ List SceneTreeDock::paste_nodes(bool p_paste_as_sibling) { } ur->add_do_method(editor_selection, "clear"); - HashMap, Ref> resource_remap; String target_scene; if (edited_scene) { target_scene = edited_scene->get_scene_file_path(); } + HashMap, Ref>> &resources_local_to_scenes = clipboard_resource_remap[target_scene]; // Record the mappings in the sub-scene. if (target_scene != clipboard_source_scene) { - if (!clipboard_resource_remap.has(target_scene)) { + if (!resources_local_to_scenes.has(nullptr)) { HashMap, Ref> remap; for (Node *E : node_clipboard) { _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) { HashMap 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); pasted_nodes.push_back(dup); @@ -4396,6 +4405,15 @@ List SceneTreeDock::paste_nodes(bool p_paste_as_sibling) { } ur->commit_action(); + + for (KeyValue, Ref>> &KV : resources_local_to_scenes) { + for (KeyValue, Ref> &R : KV.value) { + if (R.value->is_local_to_scene()) { + R.value->setup_local_to_scene(); + } + } + } + return pasted_nodes; } diff --git a/editor/docks/scene_tree_dock.h b/editor/docks/scene_tree_dock.h index a73dd39ae12..9aa60a5c73a 100644 --- a/editor/docks/scene_tree_dock.h +++ b/editor/docks/scene_tree_dock.h @@ -146,7 +146,7 @@ class SceneTreeDock : public EditorDock { List node_clipboard; HashSet node_clipboard_edited_scene_owned; String clipboard_source_scene; - HashMap, Ref>> clipboard_resource_remap; + HashMap, Ref>>> clipboard_resource_remap; ScriptCreateDialog *script_create_dialog = nullptr; ShaderCreateDialog *shader_create_dialog = nullptr; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 15f33f31dac..668834abad2 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2953,10 +2953,11 @@ Node *Node::duplicate(int p_flags) const { #ifdef TOOLS_ENABLED Node *Node::duplicate_from_editor(HashMap &r_duplimap) const { - return duplicate_from_editor(r_duplimap, HashMap, Ref>()); + HashMap, Ref>> tmp; + return duplicate_from_editor(r_duplimap, nullptr, tmp); } -Node *Node::duplicate_from_editor(HashMap &r_duplimap, const HashMap, Ref> &p_resource_remap) const { +Node *Node::duplicate_from_editor(HashMap &r_duplimap, Node *p_scene_root, HashMap, Ref>> &p_resource_remap) const { int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR; Node *dupe = _duplicate(flags, &r_duplimap); @@ -2969,8 +2970,8 @@ Node *Node::duplicate_from_editor(HashMap &r_duplimap, con _duplicate_properties(this, this, dupe, flags); // 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, @@ -2981,7 +2982,9 @@ Node *Node::duplicate_from_editor(HashMap &r_duplimap, con return dupe; } -void Node::remap_node_resources(Node *p_node, const HashMap, Ref> &p_resource_remap) const { +void Node::remap_node_resources(Node *p_node, Node *p_scene_root, HashMap, Ref>> &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 props; p_node->get_property_list(&props); @@ -2991,23 +2994,39 @@ void Node::remap_node_resources(Node *p_node, const HashMap, Refget(E.name); - if (v.is_ref_counted()) { - Ref 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 res = v; + if (res.is_null()) { + continue; + } + + if (res->is_local_to_scene()) { + if (local_scene == res->get_local_scene()) { + continue; + } + Ref 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++) { - 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 p_resource, const HashMap, Ref> &p_resource_remap) const { +void Node::remap_nested_resources(Ref p_resource, HashMap, Ref> &p_resource_remap) const { List props; p_resource->get_property_list(&props); diff --git a/scene/main/node.h b/scene/main/node.h index a8c0b24c620..d0aaea2c855 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -721,9 +721,9 @@ public: Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const; #ifdef TOOLS_ENABLED Node *duplicate_from_editor(HashMap &r_duplimap) const; - Node *duplicate_from_editor(HashMap &r_duplimap, const HashMap, Ref> &p_resource_remap) const; - void remap_node_resources(Node *p_node, const HashMap, Ref> &p_resource_remap) const; - void remap_nested_resources(Ref p_resource, const HashMap, Ref> &p_resource_remap) const; + Node *duplicate_from_editor(HashMap &r_duplimap, Node *p_scene_root, HashMap, Ref>> &p_resource_remap) const; + void remap_node_resources(Node *p_node, Node *p_scene_root, HashMap, Ref>> &p_resource_remap) const; + void remap_nested_resources(Ref p_resource, HashMap, Ref> &p_resource_remap) const; #endif // used by editors, to save what has changed only diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 24df002bb88..05650a44d01 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -81,7 +81,13 @@ static Array _sanitize_node_pinned_properties(Node *p_node) { Ref SceneState::get_remap_resource(const Ref &p_resource, HashMap, Ref>> &remap_cache, const Ref &p_fallback, Node *p_for_scene) { ERR_FAIL_COND_V(p_resource.is_null(), Ref()); - bool reuse_fallback = p_fallback.is_valid() && p_fallback->is_local_to_scene() && p_fallback->get_class() == p_resource->get_class(); + // Find the shared copy of the source resource. + HashMap, Ref>::Iterator R = remap_cache[p_for_scene].find(p_resource); + if (R) { + 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. @@ -703,16 +709,16 @@ Variant SceneState::make_local_resource(Variant &p_value, const SceneState::Node 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>::Iterator R = p_resources_local_to_scenes[base].find(res); if (R) { return R->value; } - 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); - } - 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;