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.
This commit is contained in:
Bastien Montagne 2022-07-27 15:29:49 +02:00
parent 9f53272df4
commit 9ac81ed6ab
Notes: blender-bot 2023-02-14 06:21:59 +01:00
Referenced by commit 415f88d8b0, Fix wrong fileversion usage in own recent rB9ac81ed6abfb.
4 changed files with 101 additions and 42 deletions

View File

@ -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);

View File

@ -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

View File

@ -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<Uniqueness_Key> 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 : "<None>");
}
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 : "<None>");
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_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_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 : "<None>");
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 : "<None>");
}
}
}
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<Library *>((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);
}

View File

@ -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. */
}
}