Fix (unreported) incorrect behavior of liboverride hierarchy fixing code.

Code in charge of fixing invalid liboverride hierarchy roots would be
too agressive in re-assigning new root in replacement of old one. When
the invalid initial case was a 'low-level' type of ID (like a nodetree
e.g.), it could 'contaminate' many valid data (objects etc.) and force
them into its own local hierarchy.

This commit fixes the issue by storing all 'processed as valid' IDs into
a set, and ensuring that once an ID has been put into that set, its
hierarchy root is not changed anymore.

in other words, it changes the old behavior of 'last encountered hierarchy
wins' to 'first encountered hierarchy wins'. Since higher-level types of
IDs (like collections or objects) are processed first, this is the
most logical behavior too.
This commit is contained in:
Bastien Montagne 2023-07-12 19:06:31 +02:00
parent 1f1c39b980
commit bf93fb0f46
1 changed files with 29 additions and 5 deletions

View File

@ -49,6 +49,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_memarena.h"
#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@ -1617,8 +1618,14 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
return best_root_id_candidate;
}
static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID *id_from)
static void lib_override_root_hierarchy_set(
Main *bmain, ID *id_root, ID *id, ID *id_from, blender::Set<ID *> &processed_ids)
{
if (processed_ids.contains(id)) {
/* This ID has already been checked as having a valid hierarchy root, do not attempt to replace
* it with another one just because it is also used by another liboverride hierarchy. */
return;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
if (id->override_library->hierarchy_root == id_root) {
/* Already set, nothing else to do here, sub-hierarchy is also assumed to be properly set
@ -1688,6 +1695,15 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
}
CLOG_INFO(&LOG,
3,
"Modifying library override hierarchy of ID '%s'.\n"
"\tFrom old root '%s' to new root '%s'.",
id->name,
id->override_library->hierarchy_root ? id->override_library->hierarchy_root->name :
"<NONE>",
id_root->name);
id->override_library->hierarchy_root = id_root;
}
@ -1712,7 +1728,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
/* Recursively process the sub-hierarchy. */
lib_override_root_hierarchy_set(bmain, id_root, to_id, id);
lib_override_root_hierarchy_set(bmain, id_root, to_id, id, processed_ids);
}
}
@ -1721,9 +1737,11 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
ID *id;
BKE_main_relations_create(bmain, 0);
blender::Set<ID *> processed_ids;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
processed_ids.add(id);
continue;
}
if (id->override_library->hierarchy_root != nullptr) {
@ -1741,6 +1759,8 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
id->override_library->hierarchy_root = nullptr;
}
else {
/* This ID is considered as having a valid hierarchy root. */
processed_ids.add(id);
continue;
}
}
@ -1751,16 +1771,20 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level);
if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) {
/* FIXME This is probably never actually reached with current code? Check above for non-null
* hierarchy root pointer either skip the rest of the loop, or reset it to nullptr. */
CLOG_WARN(&LOG,
"Potential inconsistency in library override hierarchy of ID '%s', detected as "
"part of the hierarchy of '%s', which has a different root '%s'",
"Potential inconsistency in library override hierarchy of ID '%s' (current root "
"%s), detected as part of the hierarchy of '%s' (current root '%s')",
id->name,
id->override_library->hierarchy_root->name,
id_root->name,
id_root->override_library->hierarchy_root->name);
processed_ids.add(id);
continue;
}
lib_override_root_hierarchy_set(bmain, id_root, id, nullptr);
lib_override_root_hierarchy_set(bmain, id_root, id, nullptr, processed_ids);
BLI_assert(id->override_library->hierarchy_root != nullptr);
}