Commit: 7484e4529717a61277525bbb6bc9ac7a747e42f1
Author: Bastien Montagne
Date:   Mon Jul 20 17:04:16 2020 +0200
Branches: master
https://developer.blender.org/rB7484e4529717a61277525bbb6bc9ac7a747e42f1

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.

===================================================================

M       source/blender/blenkernel/BKE_collection.h
M       source/blender/blenkernel/intern/collection.c
M       source/blender/blenloader/intern/versioning_290.c
M       source/blender/editors/object/object_add.c
M       source/blender/editors/space_outliner/outliner_collections.c

===================================================================

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);
     }
   }

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to