From 9ac81ed6abfbd431aafd75969f8590703ebe122f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 27 Jul 2022 15:29:49 +0200 Subject: Fix corrupted blend files after issues from new name_map code. Add a version of #BKE_main_namemap_validate that also fixes the issues, and call it in a do_version to fix recent .blend files saved after the regression introduced in rB7f8d05131a77. This is mandatory to fix some production files here at the studio, among other things. --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_main_namemap.h | 7 ++ source/blender/blenkernel/intern/main_namemap.cc | 108 +++++++++++++++------- source/blender/blenloader/intern/versioning_300.c | 28 +++--- 4 files changed, 102 insertions(+), 43 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index efe44ec657b..8b924bfc71d 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -31,7 +31,7 @@ extern "C" { * version. Older Blender versions will test this and show a warning if the file * was written with too new a version. */ #define BLENDER_FILE_MIN_VERSION 300 -#define BLENDER_FILE_MIN_SUBVERSION 43 +#define BLENDER_FILE_MIN_SUBVERSION 44 /** User readable version string. */ const char *BKE_blender_version_string(void); diff --git a/source/blender/blenkernel/BKE_main_namemap.h b/source/blender/blenkernel/BKE_main_namemap.h index c5fce803a03..d6f184b4b30 100644 --- a/source/blender/blenkernel/BKE_main_namemap.h +++ b/source/blender/blenkernel/BKE_main_namemap.h @@ -54,6 +54,13 @@ void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char */ bool BKE_main_namemap_validate(struct Main *bmain) ATTR_NONNULL(); +/** Same as #BKE_main_namemap_validate, but also fixes any issue by re-generating all name maps, + * and ensuring again all ID names are unique. + * + * This is typically only used in `do_versions` code to fix broken files. + */ +bool BKE_main_namemap_validate_and_fix(struct Main *bmain) ATTR_NONNULL(); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/main_namemap.cc b/source/blender/blenkernel/intern/main_namemap.cc index 3a7b325b3d2..a164633af09 100644 --- a/source/blender/blenkernel/intern/main_namemap.cc +++ b/source/blender/blenkernel/intern/main_namemap.cc @@ -5,6 +5,7 @@ */ #include "BKE_idtype.h" +#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_main_namemap.h" @@ -382,43 +383,60 @@ struct Uniqueness_Key { } }; -bool BKE_main_namemap_validate(Main *bmain) +static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix) { Set id_names_libs; bool is_valid = true; - ID *id_iter; - FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - Uniqueness_Key key; - BLI_strncpy(key.name, id_iter->name, MAX_ID_NAME); - key.lib = id_iter->lib; - if (!id_names_libs.add(key)) { - is_valid = false; - CLOG_ERROR(&LOG, - "ID name '%s' (from library '%s') is found more than once", - id_iter->name, - id_iter->lib != nullptr ? id_iter->lib->filepath : ""); - } - - UniqueName_Map *name_map = get_namemap_for(bmain, id_iter, false); - if (name_map == nullptr) { - continue; - } - UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id_iter->name)); - BLI_assert(type_map != nullptr); + ListBase *lb_iter; + FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb_iter) { + LISTBASE_FOREACH_MUTABLE (ID *, id_iter, lb_iter) { + Uniqueness_Key key; + BLI_strncpy(key.name, id_iter->name, MAX_ID_NAME); + key.lib = id_iter->lib; + if (!id_names_libs.add(key)) { + is_valid = false; + CLOG_ERROR(&LOG, + "ID name '%s' (from library '%s') is found more than once", + id_iter->name, + id_iter->lib != nullptr ? id_iter->lib->filepath : ""); + if (do_fix) { + /* NOTE: this may imply moving this ID in its listbase, however re-checking it later is + * not really an issue. */ + BKE_id_new_name_validate( + bmain, which_libbase(bmain, GS(id_iter->name)), id_iter, nullptr, true); + BLI_strncpy(key.name, id_iter->name, MAX_ID_NAME); + if (!id_names_libs.add(key)) { + CLOG_ERROR(&LOG, + "\tID has been renamed to '%s', but it still seems to be already in use", + id_iter->name); + } + else { + CLOG_WARN(&LOG, "\tID has been renamed to '%s'", id_iter->name); + } + } + } - UniqueName_Key key_namemap; - /* Remove full name from the set. */ - BLI_strncpy(key_namemap.name, id_iter->name + 2, MAX_NAME); - if (!type_map->full_names.contains(key_namemap)) { - is_valid = false; - CLOG_ERROR(&LOG, - "ID name '%s' (from library '%s') exists in current Main, but is not listed in " - "the namemap", - id_iter->name, - id_iter->lib != nullptr ? id_iter->lib->filepath : ""); + UniqueName_Map *name_map = get_namemap_for(bmain, id_iter, false); + if (name_map == nullptr) { + continue; + } + UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id_iter->name)); + BLI_assert(type_map != nullptr); + + UniqueName_Key key_namemap; + /* Remove full name from the set. */ + BLI_strncpy(key_namemap.name, id_iter->name + 2, MAX_NAME); + if (!type_map->full_names.contains(key_namemap)) { + is_valid = false; + CLOG_ERROR(&LOG, + "ID name '%s' (from library '%s') exists in current Main, but is not listed in " + "the namemap", + id_iter->name, + id_iter->lib != nullptr ? id_iter->lib->filepath : ""); + } } } - FOREACH_MAIN_ID_END; + FOREACH_MAIN_LISTBASE_END; Library *lib = nullptr; UniqueName_Map *name_map = bmain->name_map; @@ -450,5 +468,33 @@ bool BKE_main_namemap_validate(Main *bmain) name_map = (lib != nullptr) ? lib->runtime.name_map : nullptr; } while (lib != nullptr); + if (is_valid || !do_fix) { + return is_valid; + } + + /* Clear all existing namemaps. */ + lib = nullptr; + UniqueName_Map **name_map_p = &bmain->name_map; + do { + BLI_assert(name_map_p != nullptr); + if (*name_map_p != nullptr) { + BKE_main_namemap_destroy(name_map_p); + } + lib = static_cast((lib == nullptr) ? bmain->libraries.first : lib->id.next); + name_map_p = (lib != nullptr) ? &lib->runtime.name_map : nullptr; + } while (lib != nullptr); + + return is_valid; +} + +bool BKE_main_namemap_validate_and_fix(Main *bmain) +{ + const bool is_valid = main_namemap_validate_and_fix(bmain, true); + BLI_assert(main_namemap_validate_and_fix(bmain, false)); return is_valid; } + +bool BKE_main_namemap_validate(Main *bmain) +{ + return main_namemap_validate_and_fix(bmain, false); +} diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index fa3789ea590..fd5f93c3e29 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -57,6 +57,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_main.h" +#include "BKE_main_namemap.h" #include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -3285,18 +3286,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!MAIN_VERSION_ATLEAST(bmain, 303, 44)) { /* Initialize brush curves sculpt settings. */ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { if (brush->ob_mode != OB_MODE_SCULPT_CURVES) { @@ -3312,5 +3303,20 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) ob->dtx &= ~OB_DRAWBOUNDOX; } } + + BKE_main_namemap_validate_and_fix(bmain); + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ } } -- cgit v1.2.3