From 608b5d2e0712ed7d494bc1a1bc32a472c0f64e4d Mon Sep 17 00:00:00 2001 From: RedMser Date: Tue, 17 Jan 2023 21:14:19 +0100 Subject: [PATCH] Fix recursive resource local to scene Any resource that contains other local to scene resources inside of arrays or dictionaries will now be duplicated and configured. The case where a scene's node has an exported array/dictionary property containing local to scene resources is NOT handled here. --- core/io/resource.cpp | 118 ++++++++++++++++++++++++++++++++++--------- core/io/resource.h | 7 ++- 2 files changed, 98 insertions(+), 27 deletions(-) diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 04ecabaf27b..daa57be76fd 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -204,7 +204,58 @@ void Resource::reload_from_file() { copy_from(s); } -Ref Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap, Ref> &remap_cache) { +void Resource::_dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap, Ref> &p_remap_cache) { + switch (r_variant.get_type()) { + case Variant::ARRAY: { + Array a = r_variant; + for (int i = 0; i < a.size(); i++) { + _dupe_sub_resources(a[i], p_for_scene, p_remap_cache); + } + } break; + case Variant::DICTIONARY: { + Dictionary d = r_variant; + List keys; + d.get_key_list(&keys); + for (Variant &k : keys) { + if (k.get_type() == Variant::OBJECT) { + // Replace in dictionary key. + Ref sr = k; + if (sr.is_valid() && sr->is_local_to_scene()) { + if (p_remap_cache.has(sr)) { + d[p_remap_cache[sr]] = d[k]; + d.erase(k); + } else { + Ref dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache); + d[dupe] = d[k]; + d.erase(k); + p_remap_cache[sr] = dupe; + } + } + } else { + _dupe_sub_resources(k, p_for_scene, p_remap_cache); + } + + _dupe_sub_resources(d[k], p_for_scene, p_remap_cache); + } + } break; + case Variant::OBJECT: { + Ref sr = r_variant; + if (sr.is_valid() && sr->is_local_to_scene()) { + if (p_remap_cache.has(sr)) { + r_variant = p_remap_cache[sr]; + } else { + Ref dupe = sr->duplicate_for_local_scene(p_for_scene, p_remap_cache); + r_variant = dupe; + p_remap_cache[sr] = dupe; + } + } + } break; + default: { + } + } +} + +Ref Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap, Ref> &p_remap_cache) { List plist; get_property_list(&plist); @@ -217,21 +268,9 @@ Ref Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap sr = p; - if (sr.is_valid()) { - if (sr->is_local_to_scene()) { - if (remap_cache.has(sr)) { - p = remap_cache[sr]; - } else { - Ref dupe = sr->duplicate_for_local_scene(p_for_scene, remap_cache); - p = dupe; - remap_cache[sr] = dupe; - } - } - } - } + Variant p = get(E.name).duplicate(true); + + _dupe_sub_resources(p, p_for_scene, p_remap_cache); r->set(E.name, p); } @@ -239,7 +278,35 @@ Ref Resource::duplicate_for_local_scene(Node *p_for_scene, HashMap, Ref> &remap_cache) { +void Resource::_find_sub_resources(const Variant &p_variant, HashSet> &p_resources_found) { + switch (p_variant.get_type()) { + case Variant::ARRAY: { + Array a = p_variant; + for (int i = 0; i < a.size(); i++) { + _find_sub_resources(a[i], p_resources_found); + } + } break; + case Variant::DICTIONARY: { + Dictionary d = p_variant; + List keys; + d.get_key_list(&keys); + for (const Variant &k : keys) { + _find_sub_resources(k, p_resources_found); + _find_sub_resources(d[k], p_resources_found); + } + } break; + case Variant::OBJECT: { + Ref r = p_variant; + if (r.is_valid()) { + p_resources_found.insert(r); + } + } break; + default: { + } + } +} + +void Resource::configure_for_local_scene(Node *p_for_scene, HashMap, Ref> &p_remap_cache) { List plist; get_property_list(&plist); @@ -251,14 +318,15 @@ void Resource::configure_for_local_scene(Node *p_for_scene, HashMap sr = p; - if (sr.is_valid()) { - if (sr->is_local_to_scene()) { - if (!remap_cache.has(sr)) { - sr->configure_for_local_scene(p_for_scene, remap_cache); - remap_cache[sr] = sr; - } + + HashSet> sub_resources; + _find_sub_resources(p, sub_resources); + + for (Ref sr : sub_resources) { + if (sr->is_local_to_scene()) { + if (!p_remap_cache.has(sr)) { + sr->configure_for_local_scene(p_for_scene, p_remap_cache); + p_remap_cache[sr] = sr; } } } diff --git a/core/io/resource.h b/core/io/resource.h index 610c2150dba..b885b773acd 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -74,6 +74,9 @@ private: SelfList remapped_list; + void _dupe_sub_resources(Variant &r_variant, Node *p_for_scene, HashMap, Ref> &p_remap_cache); + void _find_sub_resources(const Variant &p_variant, HashSet> &p_resources_found); + protected: virtual void _resource_path_changed(); static void _bind_methods(); @@ -111,8 +114,8 @@ public: String get_scene_unique_id() const; virtual Ref duplicate(bool p_subresources = false) const; - Ref duplicate_for_local_scene(Node *p_for_scene, HashMap, Ref> &remap_cache); - void configure_for_local_scene(Node *p_for_scene, HashMap, Ref> &remap_cache); + Ref duplicate_for_local_scene(Node *p_for_scene, HashMap, Ref> &p_remap_cache); + void configure_for_local_scene(Node *p_for_scene, HashMap, Ref> &p_remap_cache); void set_local_to_scene(bool p_enable); bool is_local_to_scene() const;