From d9fe565c852135edbe51ec632df593db2579cc9b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Feb 2022 16:06:15 +0100 Subject: 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. --- source/blender/blenkernel/intern/lib_override.c | 44 +++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 8a988bd30b5..08ff1eb80de 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -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)) { -- cgit v1.2.3