diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index f82078c7b7..4181885534 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5392,6 +5392,73 @@ void EditorNode::add_io_warning(const String &p_warning) { } } +bool EditorNode::find_recursive_resources(const Variant &p_variant, HashSet &r_resources_found) { + switch (p_variant.get_type()) { + case Variant::ARRAY: { + Array a = p_variant; + for (int i = 0; i < a.size(); i++) { + Variant v2 = a[i]; + if (v2.get_type() != Variant::ARRAY && v2.get_type() != Variant::DICTIONARY && v2.get_type() != Variant::OBJECT) { + continue; + } + if (find_recursive_resources(v2, r_resources_found)) { + return true; + } + } + } break; + case Variant::DICTIONARY: { + Dictionary d = p_variant; + for (const KeyValue &kv : d) { + const Variant &k = kv.key; + const Variant &v2 = kv.value; + if (k.get_type() == Variant::ARRAY || k.get_type() == Variant::DICTIONARY || k.get_type() == Variant::OBJECT) { + if (find_recursive_resources(k, r_resources_found)) { + return true; + } + } + if (v2.get_type() == Variant::ARRAY || v2.get_type() == Variant::DICTIONARY || v2.get_type() == Variant::OBJECT) { + if (find_recursive_resources(v2, r_resources_found)) { + return true; + } + } + } + } break; + case Variant::OBJECT: { + Ref r = p_variant; + + if (r.is_null()) { + return false; + } + + if (r_resources_found.has(r.ptr())) { + return true; + } + + r_resources_found.insert(r.ptr()); + + List plist; + r->get_property_list(&plist); + for (const PropertyInfo &pinfo : plist) { + if (!(pinfo.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + + if (pinfo.type != Variant::ARRAY && pinfo.type != Variant::DICTIONARY && pinfo.type != Variant::OBJECT) { + continue; + } + if (find_recursive_resources(r->get(pinfo.name), r_resources_found)) { + return true; + } + } + + r_resources_found.erase(r.ptr()); + } break; + default: { + } + } + return false; +} + bool EditorNode::_find_scene_in_use(Node *p_node, const String &p_path) const { if (p_node->get_scene_file_path() == p_path) { return true; diff --git a/editor/editor_node.h b/editor/editor_node.h index 21634f59f9..07f0e5c59c 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -767,6 +767,7 @@ public: static void disambiguate_filenames(const Vector p_full_paths, Vector &r_filenames); static void add_io_error(const String &p_error); static void add_io_warning(const String &p_warning); + static bool find_recursive_resources(const Variant &p_variant, HashSet &r_resources_found); static void progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false); static bool progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true); diff --git a/editor/gui/editor_quick_open_dialog.cpp b/editor/gui/editor_quick_open_dialog.cpp index 5d26b204ea..61e06b6d5c 100644 --- a/editor/gui/editor_quick_open_dialog.cpp +++ b/editor/gui/editor_quick_open_dialog.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/file_system/editor_file_system.h" #include "editor/file_system/editor_paths.h" +#include "editor/gui/editor_toaster.h" #include "editor/inspector/editor_resource_preview.h" #include "editor/inspector/multi_node_edit.h" #include "editor/settings/editor_settings.h" @@ -232,6 +233,16 @@ void EditorQuickOpenDialog::preview_property() { Ref loaded_resource = ResourceLoader::load(container->get_selected()); ERR_FAIL_COND_MSG(loaded_resource.is_null(), "Cannot load resource from path '" + container->get_selected() + "'."); + Resource *res = Object::cast_to(property_object); + if (res) { + HashSet resources_found; + resources_found.insert(res); + if (EditorNode::find_recursive_resources(loaded_resource, resources_found)) { + EditorToaster::get_singleton()->popup_str(TTR("Recursion detected, quick preview failed."), EditorToaster::SEVERITY_ERROR); + loaded_resource = Ref(); + } + } + // MultiNodeEdit has adding to the undo/redo stack baked into its set function. // As such, we have to specifically call a version of its setter that doesn't // create undo/redo actions. diff --git a/editor/inspector/editor_properties.cpp b/editor/inspector/editor_properties.cpp index a63b92e504..8d5da85a95 100644 --- a/editor/inspector/editor_properties.cpp +++ b/editor/inspector/editor_properties.cpp @@ -3339,82 +3339,15 @@ void EditorPropertyResource::_resource_selected(const Ref &p_resource, } } -static bool _find_recursive_resources(const Variant &v, HashSet &resources_found) { - switch (v.get_type()) { - case Variant::ARRAY: { - Array a = v; - for (int i = 0; i < a.size(); i++) { - Variant v2 = a[i]; - if (v2.get_type() != Variant::ARRAY && v2.get_type() != Variant::DICTIONARY && v2.get_type() != Variant::OBJECT) { - continue; - } - if (_find_recursive_resources(v2, resources_found)) { - return true; - } - } - } break; - case Variant::DICTIONARY: { - Dictionary d = v; - for (const KeyValue &kv : d) { - const Variant &k = kv.key; - const Variant &v2 = kv.value; - if (k.get_type() == Variant::ARRAY || k.get_type() == Variant::DICTIONARY || k.get_type() == Variant::OBJECT) { - if (_find_recursive_resources(k, resources_found)) { - return true; - } - } - if (v2.get_type() == Variant::ARRAY || v2.get_type() == Variant::DICTIONARY || v2.get_type() == Variant::OBJECT) { - if (_find_recursive_resources(v2, resources_found)) { - return true; - } - } - } - } break; - case Variant::OBJECT: { - Ref r = v; - - if (r.is_null()) { - return false; - } - - if (resources_found.has(r.ptr())) { - return true; - } - - resources_found.insert(r.ptr()); - - List plist; - r->get_property_list(&plist); - for (const PropertyInfo &pinfo : plist) { - if (!(pinfo.usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - - if (pinfo.type != Variant::ARRAY && pinfo.type != Variant::DICTIONARY && pinfo.type != Variant::OBJECT) { - continue; - } - if (_find_recursive_resources(r->get(pinfo.name), resources_found)) { - return true; - } - } - - resources_found.erase(r.ptr()); - } break; - default: { - } - } - return false; -} - void EditorPropertyResource::_resource_changed(const Ref &p_resource) { Resource *r = Object::cast_to(get_edited_object()); if (r) { // Check for recursive setting of resource HashSet resources_found; resources_found.insert(r); - bool found = _find_recursive_resources(p_resource, resources_found); + bool found = EditorNode::find_recursive_resources(p_resource, resources_found); if (found) { - EditorNode::get_singleton()->show_warning(TTR("Recursion detected, unable to assign resource to property.")); + callable_mp(EditorNode::get_singleton(), &EditorNode::show_warning).call_deferred(TTR("Recursion detected, unable to assign resource to property."), TTR("Warning!")); emit_changed(get_edited_property(), Ref()); update_property(); return;