Commit: 98c242affddf88c524f5c76bc9d6eb8b0ba31181
Author: Bastien Montagne
Date:   Wed Jan 12 10:43:42 2022 +0100
Branches: master
https://developer.blender.org/rB98c242affddf88c524f5c76bc9d6eb8b0ba31181

LibOverride: Add 'hierarchy root ID' info.

This change will make handling of liboverrides hierarchies (especially
resyncing) much easier and efficient. It should also make it more
resilient to 'degenerate' cases, and allow proper support of things like
parenting an override to another override of the same linked data (e.g.
a override character parented to another override of the same
character).

NOTE: this commit only implements minimal changes to add that data and
generate it for existing files on load. Actual refactor of resync code
to take advantage of this new info will happen separately.

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

M       source/blender/blenkernel/intern/lib_override.c

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

diff --git a/source/blender/blenkernel/intern/lib_override.c 
b/source/blender/blenkernel/intern/lib_override.c
index a4cd057d7a9..31e8e105eb6 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -1242,6 +1242,189 @@ void 
BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
   BKE_main_relations_free(bmain);
 }
 
+static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, 
int *r_best_level)
+{
+  if (curr_level > 1000) {
+    CLOG_ERROR(&LOG,
+               "Levels of dependency relationships between library overrides 
IDs is way too high, "
+               "skipping further processing loops (involves at least '%s')",
+               id->name);
+    BLI_assert(0);
+    return NULL;
+  }
+
+  if (!ID_IS_OVERRIDE_LIBRARY(id)) {
+    BLI_assert(0);
+    return NULL;
+  }
+
+  MainIDRelationsEntry *entry = 
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+  BLI_assert(entry != NULL);
+
+  int best_level_candidate = curr_level;
+  ID *best_root_id_candidate = id;
+
+  for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; 
from_id_entry != NULL;
+       from_id_entry = from_id_entry->next) {
+    if ((from_id_entry->usage_flag & 
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
+      /* Never consider non-overridable relationships as actual dependencies. 
*/
+      continue;
+    }
+
+    ID *from_id = from_id_entry->id_pointer.from;
+    if (ELEM(from_id, NULL, id)) {
+      continue;
+    }
+    if (!ID_IS_OVERRIDE_LIBRARY(from_id) || (from_id->lib != id->lib)) {
+      continue;
+    }
+
+    int level_candidate = curr_level + 1;
+    /* Recursively process the parent. */
+    ID *root_id_candidate = lib_override_root_find(
+        bmain, from_id, curr_level + 1, &level_candidate);
+    if (level_candidate > best_level_candidate && root_id_candidate != NULL) {
+      best_root_id_candidate = root_id_candidate;
+      best_level_candidate = level_candidate;
+    }
+  }
+
+  *r_best_level = best_level_candidate;
+  return best_root_id_candidate;
+}
+
+static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, 
ID *id_from)
+{
+  if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+    if (id->override_library->hierarchy_root == id_root) {
+      /* Already set, nothing else to do here, sub-hierarchy is also assumed 
to be properly set
+       * then. */
+      return;
+    }
+
+    /* Hierarchy root already set, and not matching currently propsed one, try 
to find which is
+     * best. */
+    if (id->override_library->hierarchy_root != NULL) {
+      /* Check if given `id_from` matches with the hierarchy of the linked 
reference ID, in which
+       * case we assume that the given hierarchy root is the 'real' one.
+       *
+       * NOTE: This can fail if user mixed dependencies between several 
overrides of a same
+       * reference linked hierarchy. Not much to be done in that case, it's 
virtually impossible to
+       * fix this automatically in a reliable way. */
+      if (id_from == NULL || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) {
+        /* Too complicated to deal with for now. */
+        CLOG_WARN(&LOG,
+                  "Inconsistency in library override hierarchy of ID '%s'.\n"
+                  "\tNot enough data to verify validity of current proposed 
root '%s', assuming "
+                  "already set one '%s' is valid.",
+                  id->name,
+                  id_root->name,
+                  id->override_library->hierarchy_root->name);
+        return;
+      }
+
+      ID *id_from_ref = id_from->override_library->reference;
+      MainIDRelationsEntry *entry = 
BLI_ghash_lookup(bmain->relations->relations_from_pointers,
+                                                     
id->override_library->reference);
+      BLI_assert(entry != NULL);
+
+      bool do_replace_root = false;
+      for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; 
from_id_entry != NULL;
+           from_id_entry = from_id_entry->next) {
+        if ((from_id_entry->usage_flag & 
IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
+          /* Never consider non-overridable relationships as actual 
dependencies. */
+          continue;
+        }
+
+        if (id_from_ref == from_id_entry->id_pointer.from) {
+          /* A matching parent was found in reference linked data, assume 
given hierarchy root is
+           * the valid one. */
+          do_replace_root = true;
+          CLOG_WARN(
+              &LOG,
+              "Inconsistency in library override hierarchy of ID '%s'.\n"
+              "\tCurrent proposed root '%s' detected as valid, will replace 
already set one '%s'.",
+              id->name,
+              id_root->name,
+              id->override_library->hierarchy_root->name);
+          break;
+        }
+      }
+
+      if (!do_replace_root) {
+        CLOG_WARN(
+            &LOG,
+            "Inconsistency in library override hierarchy of ID '%s'.\n"
+            "\tCurrent proposed root '%s' not detected as valid, keeping 
already set one '%s'.",
+            id->name,
+            id_root->name,
+            id->override_library->hierarchy_root->name);
+        return;
+      }
+    }
+
+    id->override_library->hierarchy_root = id_root;
+  }
+
+  MainIDRelationsEntry *entry = 
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
+  BLI_assert(entry != NULL);
+
+  for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != 
NULL;
+       to_id_entry = to_id_entry->next) {
+    if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) 
!= 0) {
+      /* Never consider non-overridable relationships as actual dependencies. 
*/
+      continue;
+    }
+
+    ID *to_id = *to_id_entry->id_pointer.to;
+    if (ELEM(to_id, NULL, id)) {
+      continue;
+    }
+    if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id->lib)) {
+      continue;
+    }
+
+    /* Recursively process the sub-hierarchy. */
+    lib_override_root_hierarchy_set(bmain, id_root, to_id, id);
+  }
+}
+
+void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
+{
+  ID *id;
+
+  BKE_main_relations_create(bmain, 0);
+
+  FOREACH_MAIN_ID_BEGIN (bmain, id) {
+    if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+      continue;
+    }
+    if (id->override_library->hierarchy_root != NULL) {
+      continue;
+    }
+
+    int best_level = 0;
+    ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level);
+
+    if (!ELEM(id_root->override_library->hierarchy_root, id_root, NULL)) {
+      CLOG_WARN(&LOG,
+                "Potential inconsistency in library override hierarchy of ID 
'%s', detected as "
+                "part of the hierarchy of '%s', which has a different root 
'%s'",
+                id->name,
+                id_root->name,
+                id_root->override_library->hierarchy_root->name);
+      continue;
+    }
+
+    lib_override_root_hierarchy_set(bmain, id_root, id_root, NULL);
+
+    BLI_assert(id->override_library->hierarchy_root != NULL);
+  }
+  FOREACH_MAIN_ID_END;
+
+  BKE_main_relations_free(bmain);
+}
+
 static void lib_override_library_remap(Main *bmain,
                                        const ID *id_root_reference,
                                        GHash *linkedref_to_old_override)

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to