From 35cd6397d5bc8c45b8ef84f43cd8a3e46735146f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 16 Nov 2023 16:22:29 +0100 Subject: [PATCH] Fix 'Make LibOverride' from 3DView failing in some trivial cases. Slightly non-trivial linked collections hierarchy could cause 'Make LibOverride' operation from 3DView fail, reporting that more than one potential root collections were found. Logic here was way to simple, now this error should only happen when there are effectively more than one potential 'good' root collection (i.e. when two unrelated collections both contain (directly or not) the selected objects(s). --- .../editors/object/object_relations.cc | 60 +++++++++++++++---- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/source/blender/editors/object/object_relations.cc b/source/blender/editors/object/object_relations.cc index a658788d8a0..576305feb99 100644 --- a/source/blender/editors/object/object_relations.cc +++ b/source/blender/editors/object/object_relations.cc @@ -37,6 +37,7 @@ #include "BLI_math_vector.h" #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLI_vector_set.hh" #include "BLT_translation.h" @@ -2568,33 +2569,68 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve return OPERATOR_CANCELLED; } - int potential_root_collections_num = 0; - uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET; + blender::VectorSet potential_root_collections; LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - /* Only check for directly linked collections. */ - if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 || + /* Only check for linked collections from the same library, in the current viewlayer. */ + if (!ID_IS_LINKED(&collection->id) || collection->id.lib != obact->id.lib || !BKE_view_layer_has_collection(view_layer, collection)) { continue; } - if (BKE_collection_has_object_recursive(collection, obact)) { - if (potential_root_collections_num == 0) { - collection_session_uuid = collection->id.session_uuid; + if (!BKE_collection_has_object_recursive(collection, obact)) { + continue; + } + if (potential_root_collections.is_empty()) { + potential_root_collections.add_new(collection); + } + else { + bool has_parents_in_potential_roots = false; + bool is_potential_root = false; + for (auto collection_root_iter : potential_root_collections) { + if (BKE_collection_has_collection(collection_root_iter, collection)) { + BLI_assert_msg(!BKE_collection_has_collection(collection, collection_root_iter), + "Invalid loop in collection hierarchy"); + /* Current potential root is already 'better' (higher up in the collection hierarchy) + * than current collection, nothing else to do. */ + has_parents_in_potential_roots = true; + } + else if (BKE_collection_has_collection(collection, collection_root_iter)) { + BLI_assert_msg(!BKE_collection_has_collection(collection_root_iter, collection), + "Invalid loop in collection hierarchy"); + /* Current potential root is in the current collection's hierarchy, so the later is a + * better candidate as root collection. */ + is_potential_root = true; + potential_root_collections.remove(collection_root_iter); + } + else { + /* Current potential root is not found in current collection's hierarchy, so the later is + * a potential candidate as root collection. */ + is_potential_root = true; + } + } + /* Only add the current collection as potential root if it is not a descendant of any already + * known potential root collections. */ + if (is_potential_root && !has_parents_in_potential_roots) { + potential_root_collections.add_new(collection); } - potential_root_collections_num++; } } - if (potential_root_collections_num <= 1) { - RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid)); + if (potential_root_collections.is_empty()) { + RNA_property_int_set(op->ptr, op->type->prop, MAIN_ID_SESSION_UUID_UNSET); + return make_override_library_exec(C, op); + } + if (potential_root_collections.size() == 1) { + Collection *collection_root = potential_root_collections.pop(); + RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_root->id.session_uuid)); return make_override_library_exec(C, op); } BKE_reportf(op->reports, RPT_ERROR, - "Too many potential root collections (%d) for the override hierarchy, " + "Too many potential root collections (%ld) for the override hierarchy, " "please use the Outliner instead", - potential_root_collections_num); + potential_root_collections.size()); return OPERATOR_CANCELLED; }