LibOverride: Fix potential broken cases re ShapeKeys when finding hierarchy root ID.

In some cases broken files could lead to selecting a shapekey as
hierarchy root ID, which is not allowed.

Found while investigating Blender studio issues in Snow parkour short.
This commit is contained in:
Bastien Montagne 2022-02-18 16:06:15 +01:00
parent 303b566b10
commit d9fe565c85
1 changed files with 34 additions and 10 deletions

View File

@ -72,12 +72,19 @@ static void lib_override_library_property_operation_clear(
IDOverrideLibraryPropertyOperation *opop);
/** Get override data for a given ID. Needed because of our beloved shape keys snowflake. */
BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id)
BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id)
{
if (r_owner_id != NULL) {
*r_owner_id = id;
}
if (id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
if (id_type->owner_get != NULL) {
return id_type->owner_get(bmain, id)->override_library;
ID *owner_id = id_type->owner_get(bmain, id);
if (r_owner_id != NULL) {
*r_owner_id = owner_id;
}
return owner_id->override_library;
}
BLI_assert_msg(0, "IDTypeInfo of liboverride-embedded ID with no owner getter");
}
@ -832,8 +839,8 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
continue;
}
Library *reference_lib = lib_override_get(bmain, id_owner)->reference->lib;
ID *to_id_reference = lib_override_get(bmain, to_id)->reference;
Library *reference_lib = lib_override_get(bmain, id_owner, NULL)->reference->lib;
ID *to_id_reference = lib_override_get(bmain, to_id, NULL)->reference;
if (to_id_reference->lib != reference_lib) {
/* We do not override data-blocks from other libraries, nor do we process them. */
continue;
@ -1102,11 +1109,18 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
BLI_assert(entry != NULL);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED && ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
/* This ID has already been processed. */
BLI_assert(id->override_library != NULL);
*r_best_level = curr_level;
return id->override_library->hierarchy_root;
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
/* This ID has already been processed. */
*r_best_level = curr_level;
return id->override_library->hierarchy_root;
}
BLI_assert(id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
ID *id_owner;
int best_level_placeholder = 0;
lib_override_get(bmain, id, &id_owner);
return lib_override_root_find(bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
/* This way we won't process again that ID, should we encounter it again through another
* relationship hierarchy. */
@ -1140,7 +1154,17 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
}
}
if (!ID_IS_OVERRIDE_LIBRARY_REAL(best_root_id_candidate)) {
BLI_assert(id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
ID *id_owner;
int best_level_placeholder = 0;
lib_override_get(bmain, best_root_id_candidate, &id_owner);
best_root_id_candidate = lib_override_root_find(
bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
BLI_assert(best_root_id_candidate != NULL);
BLI_assert((best_root_id_candidate->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) == 0);
*r_best_level = best_level_candidate;
return best_root_id_candidate;
@ -1430,7 +1454,7 @@ static bool lib_override_library_resync(Main *bmain,
/* While this should not happen in typical cases (and won't be properly supported here),
* user is free to do all kind of very bad things, including having different local
* overrides of a same linked ID in a same hierarchy. */
IDOverrideLibrary *id_override_library = lib_override_get(bmain, id);
IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, NULL);
ID *reference_id = id_override_library->reference;
if (GS(reference_id->name) != GS(id->name)) {
switch (GS(id->name)) {