diff options
author | Bastien Montagne <bastien@blender.org> | 2020-07-20 18:04:16 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2020-07-20 18:04:16 +0300 |
commit | 7484e4529717a61277525bbb6bc9ac7a747e42f1 (patch) | |
tree | a5cd70a140ed167b9b26cb84e29163546a61d9e3 /source/blender | |
parent | ccc2a7996b836cd255fbb7d7f693f5b958442043 (diff) |
Fix T78960: 2.83.2 not opening a 2.82a project correctly.
That project cannot be opened correctly ayway, it has recursive
collections intanciating themselves...
But at least now we have a check at startup to detect and 'fix' those
nasty cycles in collections.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_collection.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 83 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_290.c | 8 | ||||
-rw-r--r-- | source/blender/editors/object/object_add.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_collections.c | 2 |
5 files changed, 87 insertions, 11 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index db2fe651c91..25bc2006ee3 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -153,7 +153,8 @@ bool BKE_collection_move(struct Main *bmain, bool relative_after, struct Collection *collection); -bool BKE_collection_find_cycle(struct Collection *new_ancestor, struct Collection *collection); +bool BKE_collection_cycle_find(struct Collection *new_ancestor, struct Collection *collection); +bool BKE_collection_cycles_fix(struct Main *bmain, struct Collection *collection); bool BKE_collection_has_collection(struct Collection *parent, struct Collection *collection); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 4bd0c77af28..6118325c231 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1147,7 +1147,7 @@ void BKE_collections_after_lib_link(Main *bmain) /** \name Collection Children * \{ */ -static bool collection_find_instance_recursive(Collection *collection, +static bool collection_instance_find_recursive(Collection *collection, Collection *instance_collection) { LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) { @@ -1159,7 +1159,7 @@ static bool collection_find_instance_recursive(Collection *collection, } LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) { - if (collection_find_instance_recursive(collection_child->collection, instance_collection)) { + if (collection_instance_find_recursive(collection_child->collection, instance_collection)) { return true; } } @@ -1167,21 +1167,88 @@ static bool collection_find_instance_recursive(Collection *collection, return false; } -bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection) +/** + * Find potential cycles in collections. + * + * \param new_ancestor the potential new owner of given \a collection, or the collection to check + * if the later is NULL. + * \param collection the collection we want to add to \a new_ancestor, may be NULL if we just want + * to ensure \a new_ancestor does not already have cycles. + * \return true if a cycle is found. + */ +bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection) { if (collection == new_ancestor) { return true; } + if (collection == NULL) { + collection = new_ancestor; + } + LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->parents) { - if (BKE_collection_find_cycle(parent->collection, collection)) { + if (BKE_collection_cycle_find(parent->collection, collection)) { return true; } } /* Find possible objects in collection or its children, that would instantiate the given ancestor * collection (that would also make a fully invalid cycle of dependencies) .*/ - return collection_find_instance_recursive(collection, new_ancestor); + return collection_instance_find_recursive(collection, new_ancestor); +} + +static bool collection_instance_fix_recursive(Collection *parent_collection, + Collection *collection) +{ + bool cycles_found = false; + + LISTBASE_FOREACH (CollectionObject *, collection_object, &parent_collection->gobject) { + if (collection_object->ob != NULL && + collection_object->ob->instance_collection == collection) { + id_us_min(&collection->id); + collection_object->ob->instance_collection = NULL; + cycles_found = true; + } + } + + LISTBASE_FOREACH (CollectionChild *, collection_child, &parent_collection->children) { + if (collection_instance_fix_recursive(collection_child->collection, collection)) { + cycles_found = true; + } + } + + return cycles_found; +} + +static bool collection_cycle_fix_recursive(Main *bmain, + Collection *parent_collection, + Collection *collection) +{ + bool cycles_found = false; + + LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &parent_collection->parents) { + if (BKE_collection_cycle_find(parent->collection, collection)) { + BKE_collection_child_remove(bmain, parent->collection, parent_collection); + cycles_found = true; + } + else if (collection_cycle_fix_recursive(bmain, parent->collection, collection)) { + cycles_found = true; + } + } + + return cycles_found; +} + +/** + * Find and fix potential cycles in collections. + * + * \param collection the collection to check for existing cycles. + * \return true if cycles are found and fixed. + */ +bool BKE_collection_cycles_fix(Main *bmain, Collection *collection) +{ + return collection_cycle_fix_recursive(bmain, collection, collection) || + collection_instance_fix_recursive(collection, collection); } static CollectionChild *collection_find_child(Collection *parent, Collection *collection) @@ -1223,7 +1290,7 @@ static bool collection_child_add(Collection *parent, if (child) { return false; } - if (BKE_collection_find_cycle(parent, collection)) { + if (BKE_collection_cycle_find(parent, collection)) { return false; } @@ -1301,7 +1368,7 @@ void BKE_collection_parent_relations_rebuild(Collection *collection) child = child_next) { child_next = child->next; - if (child->collection == NULL || BKE_collection_find_cycle(collection, child->collection)) { + if (child->collection == NULL || BKE_collection_cycle_find(collection, child->collection)) { BLI_freelinkN(&collection->children, child); } else { @@ -1464,7 +1531,7 @@ bool BKE_collection_move(Main *bmain, if (collection->flag & COLLECTION_IS_MASTER) { return false; } - if (BKE_collection_find_cycle(to_parent, collection)) { + if (BKE_collection_cycle_find(to_parent, collection)) { return false; } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index ba92e11cc2a..a84d9711491 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -196,6 +196,14 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) * \note Keep this message at the bottom of the function. */ { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_cycles_fix(bmain, collection)) { + printf( + "WARNING: Cycle detected in collection '%s', fixed as best as possible.\n" + "You may have to reconstruct your View Layers...\n", + collection->id.name); + } + } /* Keep this block, even when empty. */ } } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ff49e0a9c5a..aa9d6234d1f 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1395,7 +1395,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) /* Avoid dependency cycles. */ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); - while (BKE_collection_find_cycle(active_lc->collection, collection)) { + while (BKE_collection_cycle_find(active_lc->collection, collection)) { active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); } diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 4b012934ab7..0964e0c753e 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -717,7 +717,7 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - while (BKE_collection_find_cycle(active_lc->collection, collection)) { + while (BKE_collection_cycle_find(active_lc->collection, collection)) { active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); } } |