Merge pull request #109816 from SatLess/ArraysArePeopleToo

Add `Make_Unique_Recursive` option for `Resources` with `Arrays` and `Dictionaries`
This commit is contained in:
Thaddeus Crews
2025-10-13 12:30:11 -05:00

View File

@@ -53,8 +53,26 @@ static bool _has_sub_resources(const Ref<Resource> &p_res) {
List<PropertyInfo> property_list;
p_res->get_property_list(&property_list);
for (const PropertyInfo &p : property_list) {
Variant value = p_res->get(p.name);
if (p.type == Variant::OBJECT && p.hint == PROPERTY_HINT_RESOURCE_TYPE && !(p.usage & PROPERTY_USAGE_NEVER_DUPLICATE) && p_res->get(p.name).get_validated_object()) {
return true;
} else if (p.type == Variant::ARRAY) {
Array arr = value;
for (Variant &var : arr) {
Ref<Resource> res = var;
if (res.is_valid()) {
return true;
}
}
} else if (p.type == Variant::DICTIONARY) {
Dictionary dict = value;
for (const KeyValue<Variant, Variant> &kv : dict) {
Ref<Resource> resk = kv.key;
Ref<Resource> resv = kv.value;
if (resk.is_valid() || resv.is_valid()) {
return true;
}
}
}
}
return false;
@@ -1097,9 +1115,9 @@ void EditorResourcePicker::_gather_resources_to_duplicate(const Ref<Resource> p_
}
if (res_name.is_empty()) {
p_item->set_text(0, p_resource->get_class());
p_item->set_text(0, _get_resource_type(p_resource));
} else {
p_item->set_text(0, vformat("%s (%s)", p_resource->get_class(), res_name));
p_item->set_text(0, vformat("%s (%s)", _get_resource_type(p_resource), res_name));
}
p_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(p_resource.ptr()));
@@ -1122,7 +1140,47 @@ void EditorResourcePicker::_gather_resources_to_duplicate(const Ref<Resource> p_
p_resource->get_property_list(&plist);
for (const PropertyInfo &E : plist) {
if (!(E.usage & PROPERTY_USAGE_STORAGE) || E.type != Variant::OBJECT || E.hint != PROPERTY_HINT_RESOURCE_TYPE) {
if (!(E.usage & PROPERTY_USAGE_STORAGE) || (E.type != Variant::OBJECT && E.type != Variant::ARRAY && E.type != Variant::DICTIONARY)) {
continue;
}
Variant value = p_resource->get(E.name);
TreeItem *child = nullptr;
if (E.type == Variant::ARRAY) {
Array arr = value;
for (int i = 0; i < arr.size(); i++) {
Ref<Resource> res = arr[i];
if (res.is_valid()) {
child = p_item->create_child();
_gather_resources_to_duplicate(res, child, E.name);
meta = child->get_metadata(0);
meta.push_back(E.name);
meta.push_back(i); // Remember index.
}
}
continue;
} else if (E.type == Variant::DICTIONARY) {
Dictionary dict = value;
for (const KeyValue<Variant, Variant> &kv : dict) {
Ref<Resource> key_res = kv.key;
Ref<Resource> value_res = kv.value;
if (key_res.is_valid()) {
child = p_item->create_child();
_gather_resources_to_duplicate(key_res, child, E.name);
meta = child->get_metadata(0);
meta.push_back(E.name);
meta.push_back(key_res);
}
if (value_res.is_valid()) {
child = p_item->create_child();
_gather_resources_to_duplicate(value_res, child, E.name);
meta = child->get_metadata(0);
meta.push_back(E.name);
meta.push_back(value_res);
meta.push_back(kv.key);
}
}
continue;
}
@@ -1130,13 +1188,11 @@ void EditorResourcePicker::_gather_resources_to_duplicate(const Ref<Resource> p_
if (res.is_null()) {
continue;
}
TreeItem *child = p_item->create_child();
child = p_item->create_child();
_gather_resources_to_duplicate(res, child, E.name);
meta = child->get_metadata(0);
// Remember property name.
meta.append(E.name);
meta.push_back(E.name);
if ((E.usage & PROPERTY_USAGE_NEVER_DUPLICATE)) {
// The resource can't be duplicated, but make it appear on the list anyway.
@@ -1161,10 +1217,47 @@ void EditorResourcePicker::_duplicate_selected_resources() {
if (meta.size() == 1) { // Root.
edited_resource = unique_resource;
_resource_changed();
} else {
Array parent_meta = item->get_parent()->get_metadata(0);
Ref<Resource> parent = parent_meta[0];
continue;
}
Array parent_meta = item->get_parent()->get_metadata(0);
Ref<Resource> parent = parent_meta[0];
Variant::Type property_type = parent->get(meta[1]).get_type();
if (property_type == Variant::OBJECT) {
parent->set(meta[1], unique_resource);
continue;
}
Variant property = parent->get(meta[1]);
if (!parent_meta.has(property)) {
property = property.duplicate();
parent->set(meta[1], property);
parent_meta.push_back(property); // Append Duplicated Type so we can check if it's already been duplicated.
}
if (property_type == Variant::ARRAY) {
Array arr = property;
arr[meta[2]] = unique_resource;
continue;
}
Dictionary dict = property;
LocalVector<Variant> keys = dict.get_key_list();
if (meta[2].get_type() == Variant::OBJECT) {
if (keys.has(meta[2])) {
//It's a key.
dict[unique_resource] = dict[meta[2]];
dict.erase(meta[2]);
parent_meta.push_back(unique_resource);
} else {
// If key has been erased, use last appended Resource key instead.
Variant key = keys.has(meta[3]) ? meta[3] : parent_meta.back();
dict[key] = unique_resource;
}
} else {
dict[meta[2]] = unique_resource;
}
}
}