Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5392,6 +5392,73 @@ void EditorNode::add_io_warning(const String &p_warning) {
}
}

bool EditorNode::find_recursive_resources(const Variant &p_variant, HashSet<Resource *> &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<Variant, Variant> &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<Resource> 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<PropertyInfo> 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;
Expand Down
1 change: 1 addition & 0 deletions editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ class EditorNode : public Node {
static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &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<Resource *> &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);
Expand Down
11 changes: 11 additions & 0 deletions editor/gui/editor_quick_open_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -232,6 +233,16 @@ void EditorQuickOpenDialog::preview_property() {
Ref<Resource> 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<Resource>(property_object);
if (res) {
HashSet<Resource *> 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);
Comment thread
KoBeWi marked this conversation as resolved.
loaded_resource = Ref<Resource>();
}
}

// 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.
Expand Down
71 changes: 2 additions & 69 deletions editor/inspector/editor_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3339,82 +3339,15 @@ void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource,
}
}

static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &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<Variant, Variant> &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<Resource> r = v;

if (r.is_null()) {
return false;
}

if (resources_found.has(r.ptr())) {
return true;
}

resources_found.insert(r.ptr());

List<PropertyInfo> 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<Resource> &p_resource) {
Resource *r = Object::cast_to<Resource>(get_edited_object());
if (r) {
// Check for recursive setting of resource
HashSet<Resource *> 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<Resource>());
update_property();
return;
Expand Down