mirror of
https://github.com/blender/blender
synced 2026-09-26 16:15:47 +03:00
LibOverride: Cleanup unused&missing data after resync.
Often when the reference linked data is significantly modified, a lot of 'ghost' linked data remain referenced by liboverrides, even after resync. This is due to the fact that missing data is ignored (skipped) during resync process, to avoid potential destruction of data in case the linked data is actually missing. However, after all resync has been done, we can consider that missing linked references and their liboverrides can be safely deleted, if the later are not user-edited or hierarchy roots.
This commit is contained in:
parent
d067cdd94b
commit
bef276ab0b
2 changed files with 58 additions and 6 deletions
|
|
@ -2666,6 +2666,56 @@ static bool lib_override_library_resync(Main *bmain,
|
|||
return success;
|
||||
}
|
||||
|
||||
/** Clenup: Remove unused 'place holder' linked IDs. */
|
||||
static void lib_override_cleanup_after_resync(Main *bmain)
|
||||
{
|
||||
LibQueryUnusedIDsData parameters;
|
||||
parameters.do_local_ids = true;
|
||||
parameters.do_linked_ids = true;
|
||||
parameters.do_recursive = true;
|
||||
parameters.filter_fn = [](const ID *id) -> bool {
|
||||
if (ID_IS_LINKED(id) && (id->tag & LIB_TAG_MISSING) != 0) {
|
||||
return true;
|
||||
}
|
||||
/* This is a fairly complex case.
|
||||
*
|
||||
* LibOverride resync process takes care of removing 'no more valid' liboverrides (see at the
|
||||
* end of #lib_override_library_main_resync_on_library_indirect_level). However, since it does
|
||||
* not resync data which linked reference is missing (see
|
||||
* #lib_override_library_main_resync_id_skip_check), these are kept 'as is'. Indeed,
|
||||
* liboverride resync code cannot know if a specific liboverride data is only part of its
|
||||
* hierarchy, or if it is also used by some other data (in which case it should be preserved if
|
||||
* the linked reference goes missing).
|
||||
*
|
||||
* So instead, we consider these cases as also valid candidates for deletion here, since the
|
||||
* whole recursive process in `BKE_lib_query_unused_ids_tag` will ensure that if there is still
|
||||
* any valid user of these, they won't get tagged for deletion.
|
||||
*
|
||||
* Also, do not delete 'orphaned' liboverrides if it's a hierarchy root, or if its hierarchy
|
||||
* root's reference is missing, since this is much more likely a case of actual missing data,
|
||||
* rather than changes in the liboverride's hierarchy in the linked data.
|
||||
*/
|
||||
if (ID_IS_OVERRIDE_LIBRARY(id)) {
|
||||
const IDOverrideLibrary *override_library = BKE_lib_override_library_get(
|
||||
nullptr, id, nullptr, nullptr);
|
||||
const ID *root = override_library->hierarchy_root;
|
||||
if (root == id || (root->override_library->reference->tag & LIB_TAG_MISSING) != 0) {
|
||||
return false;
|
||||
}
|
||||
return ((override_library->reference->tag & LIB_TAG_MISSING) != 0);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
BKE_lib_query_unused_ids_tag(bmain, LIB_TAG_DOIT, parameters);
|
||||
CLOG_INFO(&LOG_RESYNC,
|
||||
2,
|
||||
"Deleting %d unused linked missing IDs and their unused liboverrides (including %d "
|
||||
"local ones)\n",
|
||||
parameters.num_total[INDEX_ID_NULL],
|
||||
parameters.num_local[INDEX_ID_NULL]);
|
||||
BKE_id_multi_tagged_delete(bmain);
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_resync(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
|
|
@ -2698,6 +2748,8 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
* re-create the global namemap on demand. */
|
||||
BKE_main_namemap_destroy(&bmain->name_map_global);
|
||||
|
||||
lib_override_cleanup_after_resync(bmain);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
@ -3665,6 +3717,8 @@ void BKE_lib_override_library_main_resync(Main *bmain,
|
|||
* re-create the global namemap on demand. */
|
||||
BKE_main_namemap_destroy(&bmain->name_map_global);
|
||||
|
||||
lib_override_cleanup_after_resync(bmain);
|
||||
|
||||
BLI_assert(BKE_main_namemap_validate(bmain));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -742,9 +742,8 @@ class TestLibraryOverridesComplex(TestHelper, unittest.TestCase):
|
|||
# Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data.
|
||||
assert len(bpy.data.collections) == 3 * 3 + 3
|
||||
assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:3 * 3])
|
||||
# Note that the 'missing' renamed objects from the library are still here as empty placeholders,
|
||||
# hence the 8 linked ones instead of 6.
|
||||
assert len(bpy.data.objects) == 3 * 6 + 8
|
||||
# Note that the 'missing' renamed objects from the library are now cleared as part of the resync process.
|
||||
assert len(bpy.data.objects) == 3 * 6 + 6
|
||||
assert all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:3 * 6])
|
||||
assert len(bpy.data.meshes) == 0 + 1
|
||||
assert len(bpy.data.armatures) == 0 + 1
|
||||
|
|
@ -774,9 +773,8 @@ class TestLibraryOverridesComplex(TestHelper, unittest.TestCase):
|
|||
assert len(bpy.data.collections) == 3 + 6
|
||||
assert all((id_.override_library is not None)
|
||||
for id_ in bpy.data.collections if id_.library == test_output_path_lib)
|
||||
# Note that the 'missing' renamed objects from the library are still here as empty placeholders,
|
||||
# hence the 8 + 6 linked ones instead of 6 + 6.
|
||||
assert len(bpy.data.objects) == 6 + 14
|
||||
# Note that the 'missing' renamed objects from the library are now cleared as part of the resync process.
|
||||
assert len(bpy.data.objects) == 6 + 12
|
||||
assert all((id_.override_library is not None)
|
||||
for id_ in bpy.data.objects if id_.library == test_output_path_lib)
|
||||
assert len(bpy.data.meshes) == 0 + 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue