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.
This commit is contained in:
parent
ccc2a7996b
commit
7484e45297
Notes:
blender-bot
2023-04-14 09:18:04 +02:00
Referenced by issue #78960, 2.83.2 not opening a 2.82a project correctly
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue