diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index 943e3a4f931..8ecd10e628c 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -1815,7 +1815,7 @@ static bool lib_override_root_is_valid(Main *bmain, ID *id) return false; } ID *id_root = id->override_library->hierarchy_root; - if (!id_root || !ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + if (!id_root || !ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { BLI_assert_unreachable(); return false; } @@ -1901,7 +1901,7 @@ static void lib_override_root_hierarchy_set( for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr; from_id_entry = from_id_entry->next) { - if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) { + if (lib_override_hierarchy_dependencies_relationship_skip_check(from_id_entry)) { /* Never consider non-overridable relationships as actual dependencies. */ continue; } @@ -1964,6 +1964,77 @@ static void lib_override_root_hierarchy_set( } } +static void lib_override_library_main_hierarchy_id_root_ensure(Main *bmain, + ID *id, + blender::Set &processed_ids) +{ + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id)); + + if (id->override_library->hierarchy_root != nullptr) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) || + id->override_library->hierarchy_root->lib != id->lib) + { + CLOG_ERROR( + &LOG, + "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a " + "new valid one", + id->override_library->hierarchy_root != nullptr ? + id->override_library->hierarchy_root->name : + "", + id->name); + id->override_library->hierarchy_root = nullptr; + } + else if (!lib_override_root_is_valid(bmain, id)) { + /* Serious invalid cases (likely resulting from bugs or invalid operations) should have + * been caught by the first check above. Invalid hierarchy roots detected here can happen + * in normal situations, e.g. when breaking a hierarchy by making one of its components + * local. See also #137412. */ + CLOG_DEBUG( + &LOG, + "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a " + "new valid one", + id->override_library->hierarchy_root != nullptr ? + id->override_library->hierarchy_root->name : + "", + id->name); + id->override_library->hierarchy_root = nullptr; + } + else { + /* This ID is considered as having a valid hierarchy root. */ + processed_ids.add(id); + return; + } + } + + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); + BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS, false); + + int best_level = 0; + ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level); + + if (!ELEM(id->override_library->hierarchy_root, id_root, nullptr)) { + /* In case the detected hierarchy root does not match with the currently defined one, this is + * likely an issue and is worth a warning. */ + CLOG_WARN(&LOG, + "Potential inconsistency in library override hierarchy of ID '%s' (current root " + "%s), detected as part of the hierarchy of '%s' (current root '%s')", + id->name, + id->override_library->hierarchy_root != nullptr ? + id->override_library->hierarchy_root->name : + "", + id_root->name, + id_root->override_library->hierarchy_root != nullptr ? + id_root->override_library->hierarchy_root->name : + ""); + processed_ids.add(id); + return; + } + + lib_override_root_hierarchy_set(bmain, id_root, id, nullptr, processed_ids); + + BLI_assert(id->override_library->hierarchy_root != nullptr); +} + void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) { ID *id; @@ -1976,69 +2047,8 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain) processed_ids.add(id); continue; } - if (id->override_library->hierarchy_root != nullptr) { - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) || - id->override_library->hierarchy_root->lib != id->lib) - { - CLOG_ERROR( - &LOG, - "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a " - "new valid one", - id->override_library->hierarchy_root != nullptr ? - id->override_library->hierarchy_root->name : - "", - id->name); - id->override_library->hierarchy_root = nullptr; - } - else if (!lib_override_root_is_valid(bmain, id)) { - /* Serious invalid cases (likely resulting from bugs or invalid operations) should have - * been caught by the first check above. Invalid hierarchy roots detected here can happen - * in normal situations, e.g. when breaking a hierarchy by making one of its components - * local. See also #137412. */ - CLOG_DEBUG( - &LOG, - "Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a " - "new valid one", - id->override_library->hierarchy_root != nullptr ? - id->override_library->hierarchy_root->name : - "", - id->name); - id->override_library->hierarchy_root = nullptr; - } - else { - /* This ID is considered as having a valid hierarchy root. */ - processed_ids.add(id); - continue; - } - } - BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false); - BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS, false); - - int best_level = 0; - ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level); - - if (!ELEM(id->override_library->hierarchy_root, id_root, nullptr)) { - /* In case the detected hierarchy root does not match with the currently defined one, this is - * likely an issue and is worth a warning. */ - CLOG_WARN(&LOG, - "Potential inconsistency in library override hierarchy of ID '%s' (current root " - "%s), detected as part of the hierarchy of '%s' (current root '%s')", - id->name, - id->override_library->hierarchy_root != nullptr ? - id->override_library->hierarchy_root->name : - "", - id_root->name, - id_root->override_library->hierarchy_root != nullptr ? - id_root->override_library->hierarchy_root->name : - ""); - processed_ids.add(id); - continue; - } - - lib_override_root_hierarchy_set(bmain, id_root, id, nullptr, processed_ids); - - BLI_assert(id->override_library->hierarchy_root != nullptr); + lib_override_library_main_hierarchy_id_root_ensure(bmain, id, processed_ids); } FOREACH_MAIN_ID_END; @@ -3694,7 +3704,25 @@ static bool lib_override_library_main_resync_on_library_indirect_level( /* In some fairly rare (and degenerate) cases, some root ID from other liboverrides may have been * freed, and therefore set to nullptr. Attempt to fix this as best as possible. */ - BKE_lib_override_library_main_hierarchy_root_ensure(bmain); + /* WARNING: Cannot use directly #BKE_lib_override_library_main_hierarchy_root_ensure here, as it + * processes the whole Main content - only the IDs matching current resync scope should be + * checked here. */ + { + BKE_main_relations_create(bmain, 0); + blender::Set processed_ids; + + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (lib_override_library_main_resync_id_skip_check(id, library_indirect_level)) { + processed_ids.add(id); + continue; + } + + lib_override_library_main_hierarchy_id_root_ensure(bmain, id, processed_ids); + } + FOREACH_MAIN_ID_END; + + BKE_main_relations_free(bmain); + } if (do_reports_recursive_resync_timing) { reports->duration.lib_overrides_recursive_resync += BLI_time_now_seconds() - init_time;