LibOverride: Add ID pointer to operations over ID pointers.
In RNA collections storing ID references, the name of the collection item may not always be unique, when several IDs from different libraries are present. While rare, this situation can become deadly to liboverride, by causing random but exponential liboverride hierarchies corruptions. This has already been alleviated by using preferably both name and index in items lookup (a05419f18b) and by reducing the risk of name collision in general between liboverrides and their linked reference (b9becc47de). This commit goes further, by ensuring that references to items of RNA collections of IDs stored in liboverride operations become completely unambiguous. This is achieved by storing an extra pointer to the item's ID itself, when relevant. Lookup then requires a complete match `name + ID` to be successful, which is guaranteed to match at most a single item in the whole RNA collection (since RNA collection of IDs do not allow duplicates, and the ID pointer is always unique). Note that this ID pointer is implemented as an `std::optional` one (either directly in C++ code, or using an new liboverride operation `flag` in DNA). This allows to smoothly transition from existing data to the added ID pointer info (when needed), without needing any dedicated versioning. This solution also preserves forward compatibility as much as possible. It may also provide marginal performances improvements in some cases, as looking up for ID items in RNA collections will first check for the ID pointer, which should be faster than a string comparision. Implements #110421. Pull Request: https://projects.blender.org/blender/blender/pulls/110773
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
* of IDs in a given Main data-base.
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
|
||||
struct BlendFileReadReport;
|
||||
struct Collection;
|
||||
struct ID;
|
||||
@@ -338,11 +340,17 @@ bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
|
||||
|
||||
/**
|
||||
* Find override property operation from given sub-item(s), if it exists.
|
||||
*
|
||||
* \param subitem_refid:
|
||||
* \param subitem_locid: Only for RNA collections of ID pointers, the ID pointers
|
||||
* referenced by the given names. Note that both must be set, or left unset.
|
||||
*/
|
||||
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
|
||||
IDOverrideLibraryProperty *liboverride_property,
|
||||
const char *subitem_refname,
|
||||
const char *subitem_locname,
|
||||
const std::optional<const ID *> &subitem_refid,
|
||||
const std::optional<const ID *> &subitem_locid,
|
||||
int subitem_refindex,
|
||||
int subitem_locindex,
|
||||
bool strict,
|
||||
@@ -355,6 +363,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
|
||||
short operation,
|
||||
const char *subitem_refname,
|
||||
const char *subitem_locname,
|
||||
const std::optional<ID *> &subitem_refid,
|
||||
const std::optional<ID *> &subitem_locid,
|
||||
int subitem_refindex,
|
||||
int subitem_locindex,
|
||||
bool strict,
|
||||
|
||||
@@ -3752,15 +3752,73 @@ void BKE_lib_override_library_property_delete(IDOverrideLibrary *liboverride,
|
||||
lib_override_library_property_delete(liboverride, liboverride_property, true);
|
||||
}
|
||||
|
||||
static IDOverrideLibraryPropertyOperation *liboverride_opop_find_name_lib_iterative(
|
||||
ListBase *liboverride_operations,
|
||||
const char *subitem_main_name,
|
||||
const char *subitem_other_name,
|
||||
const std::optional<const ID *> &subitem_main_id,
|
||||
const std::optional<const ID *> &subitem_other_id,
|
||||
const size_t offesetof_opop_main_name,
|
||||
const size_t offesetof_opop_other_name,
|
||||
const size_t offesetof_opop_main_id,
|
||||
const size_t offesetof_opop_other_id)
|
||||
{
|
||||
const bool do_ids(subitem_main_id);
|
||||
IDOverrideLibraryPropertyOperation *opop;
|
||||
for (opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_findstring_ptr(
|
||||
liboverride_operations, subitem_main_name, int(offesetof_opop_main_name)));
|
||||
opop;
|
||||
opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_findafter_string_ptr(
|
||||
reinterpret_cast<Link *>(opop), subitem_main_name, int(offesetof_opop_main_name))))
|
||||
{
|
||||
const char *opop_other_name = *reinterpret_cast<const char **>(reinterpret_cast<char *>(opop) +
|
||||
offesetof_opop_other_name);
|
||||
const bool opop_use_id = (opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID) != 0;
|
||||
|
||||
if (do_ids && opop_use_id) {
|
||||
/* Skip if ID pointers are expected valid and they do not exactly match. */
|
||||
const ID *opop_main_id = *reinterpret_cast<const ID **>(reinterpret_cast<char *>(opop) +
|
||||
offesetof_opop_main_id);
|
||||
if (*subitem_main_id != opop_main_id) {
|
||||
continue;
|
||||
}
|
||||
const ID *opop_other_id = *reinterpret_cast<const ID **>(reinterpret_cast<char *>(opop) +
|
||||
offesetof_opop_other_id);
|
||||
if (*subitem_other_id != opop_other_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only check other name if ID handling is matching between given search parameters and
|
||||
* current liboverride operation (i.e. if both have valid ID pointers, or both have none). */
|
||||
if ((do_ids && opop_use_id) || (!do_ids && !opop_use_id)) {
|
||||
if (!subitem_other_name && !opop_other_name) {
|
||||
return opop;
|
||||
}
|
||||
if (subitem_other_name && opop_other_name && STREQ(subitem_other_name, opop_other_name)) {
|
||||
return opop;
|
||||
}
|
||||
}
|
||||
|
||||
/* No exact match found, keep cheking the rest of the list of operations. */
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
|
||||
IDOverrideLibraryProperty *liboverride_property,
|
||||
const char *subitem_refname,
|
||||
const char *subitem_locname,
|
||||
const std::optional<const ID *> &subitem_refid,
|
||||
const std::optional<const ID *> &subitem_locid,
|
||||
const int subitem_refindex,
|
||||
const int subitem_locindex,
|
||||
const bool strict,
|
||||
bool *r_strict)
|
||||
{
|
||||
BLI_assert(!subitem_refid == !subitem_locid);
|
||||
|
||||
IDOverrideLibraryPropertyOperation *opop;
|
||||
const int subitem_defindex = -1;
|
||||
|
||||
@@ -3769,41 +3827,37 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
|
||||
}
|
||||
|
||||
if (subitem_locname != nullptr) {
|
||||
opop = static_cast<IDOverrideLibraryPropertyOperation *>(
|
||||
BLI_findstring_ptr(&liboverride_property->operations,
|
||||
subitem_locname,
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name)));
|
||||
opop = liboverride_opop_find_name_lib_iterative(
|
||||
&liboverride_property->operations,
|
||||
subitem_locname,
|
||||
subitem_refname,
|
||||
subitem_locid,
|
||||
subitem_refid,
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_local_id),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_id));
|
||||
|
||||
if (opop == nullptr) {
|
||||
return nullptr;
|
||||
if (opop != nullptr) {
|
||||
return opop;
|
||||
}
|
||||
|
||||
if (subitem_refname == nullptr || opop->subitem_reference_name == nullptr) {
|
||||
return subitem_refname == opop->subitem_reference_name ? opop : nullptr;
|
||||
}
|
||||
return (subitem_refname != nullptr && opop->subitem_reference_name != nullptr &&
|
||||
STREQ(subitem_refname, opop->subitem_reference_name)) ?
|
||||
opop :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
if (subitem_refname != nullptr) {
|
||||
opop = static_cast<IDOverrideLibraryPropertyOperation *>(
|
||||
BLI_findstring_ptr(&liboverride_property->operations,
|
||||
subitem_refname,
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name)));
|
||||
opop = liboverride_opop_find_name_lib_iterative(
|
||||
&liboverride_property->operations,
|
||||
subitem_refname,
|
||||
subitem_locname,
|
||||
subitem_refid,
|
||||
subitem_locid,
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_id),
|
||||
offsetof(IDOverrideLibraryPropertyOperation, subitem_local_id));
|
||||
|
||||
if (opop == nullptr) {
|
||||
return nullptr;
|
||||
if (opop != nullptr) {
|
||||
return opop;
|
||||
}
|
||||
|
||||
if (subitem_locname == nullptr || opop->subitem_local_name == nullptr) {
|
||||
return subitem_locname == opop->subitem_local_name ? opop : nullptr;
|
||||
}
|
||||
return (subitem_locname != nullptr && opop->subitem_local_name != nullptr &&
|
||||
STREQ(subitem_locname, opop->subitem_local_name)) ?
|
||||
opop :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
|
||||
@@ -3847,16 +3901,22 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
|
||||
const short operation,
|
||||
const char *subitem_refname,
|
||||
const char *subitem_locname,
|
||||
const std::optional<ID *> &subitem_refid,
|
||||
const std::optional<ID *> &subitem_locid,
|
||||
const int subitem_refindex,
|
||||
const int subitem_locindex,
|
||||
const bool strict,
|
||||
bool *r_strict,
|
||||
bool *r_created)
|
||||
{
|
||||
BLI_assert(!subitem_refid == !subitem_locid);
|
||||
|
||||
IDOverrideLibraryPropertyOperation *opop = BKE_lib_override_library_property_operation_find(
|
||||
liboverride_property,
|
||||
subitem_refname,
|
||||
subitem_locname,
|
||||
subitem_refid,
|
||||
subitem_locid,
|
||||
subitem_refindex,
|
||||
subitem_locindex,
|
||||
strict,
|
||||
@@ -3874,6 +3934,12 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
|
||||
opop->subitem_local_index = subitem_locindex;
|
||||
opop->subitem_reference_index = subitem_refindex;
|
||||
|
||||
if (subitem_refid) {
|
||||
opop->subitem_reference_id = *subitem_refid;
|
||||
opop->subitem_local_id = *subitem_locid;
|
||||
opop->flag |= LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID;
|
||||
}
|
||||
|
||||
BLI_addtail(&liboverride_property->operations, opop);
|
||||
|
||||
if (r_created) {
|
||||
@@ -4816,8 +4882,8 @@ void BKE_lib_override_debug_print(IDOverrideLibrary *liboverride, const char *in
|
||||
}
|
||||
std::cout << "] ";
|
||||
if (opop->subitem_reference_name || opop->subitem_local_name) {
|
||||
std::cout << "(" << opop->subitem_reference_name << " -> " << opop->subitem_local_name
|
||||
<< ")";
|
||||
std::cout << "(" << opop->subitem_reference_name << " <" << opop->subitem_reference_id
|
||||
<< "> -> " << opop->subitem_local_name << " <" << opop->subitem_local_id << ">)";
|
||||
}
|
||||
else if (opop->subitem_reference_index >= 0 || opop->subitem_local_index >= 0) {
|
||||
std::cout << "(" << opop->subitem_reference_index << " -> " << opop->subitem_local_index
|
||||
|
||||
@@ -323,6 +323,14 @@ static bool library_foreach_ID_link(Main *bmain,
|
||||
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
||||
|
||||
CALLBACK_INVOKE_ID(id->override_library->hierarchy_root, IDWALK_CB_LOOPBACK);
|
||||
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
|
||||
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
CALLBACK_INVOKE_ID(opop->subitem_reference_id,
|
||||
IDWALK_CB_DIRECT_WEAK_LINK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
||||
CALLBACK_INVOKE_ID(opop->subitem_local_id,
|
||||
IDWALK_CB_DIRECT_WEAK_LINK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IDP_foreach_property(id->properties,
|
||||
|
||||
@@ -63,6 +63,12 @@ void *BLI_findstring(const struct ListBase *listbase,
|
||||
void *BLI_findstring_ptr(const struct ListBase *listbase,
|
||||
const char *id,
|
||||
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
|
||||
/**
|
||||
* Finds the first element in the listbase after the given \a link element which contains a pointer
|
||||
* to the null-terminated string \a id at the specified offset, returning NULL if not found.
|
||||
*/
|
||||
void *BLI_listbase_findafter_string_ptr(struct Link *link, const char *id, const int offset);
|
||||
|
||||
/**
|
||||
* Finds the first element of listbase which contains the specified pointer value
|
||||
* at the specified offset, returning NULL if not found.
|
||||
|
||||
@@ -660,6 +660,22 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_listbase_findafter_string_ptr(Link *link, const char *id, const int offset)
|
||||
{
|
||||
const char *id_iter;
|
||||
|
||||
for (link = link->next; link; link = link->next) {
|
||||
/* exact copy of BLI_findstring(), except for this line */
|
||||
id_iter = *((const char **)(((const char *)link) + offset));
|
||||
|
||||
if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
|
||||
{
|
||||
LISTBASE_FOREACH (Link *, link, listbase) {
|
||||
|
||||
@@ -1922,6 +1922,13 @@ static void lib_link_id(BlendLibReader *reader, ID *id)
|
||||
BLO_read_id_address(reader, id, &id->override_library->reference);
|
||||
BLO_read_id_address(reader, id, &id->override_library->storage);
|
||||
BLO_read_id_address(reader, id, &id->override_library->hierarchy_root);
|
||||
|
||||
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
|
||||
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
||||
BLO_read_id_address(reader, id, &opop->subitem_reference_id);
|
||||
BLO_read_id_address(reader, id, &opop->subitem_local_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lib_link_id_embedded_id(reader, id);
|
||||
|
||||
@@ -699,7 +699,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
|
||||
/* Remove override operation for given item,
|
||||
* add singular operations for the other items as needed. */
|
||||
IDOverrideLibraryPropertyOperation *opop = BKE_lib_override_library_property_operation_find(
|
||||
oprop, nullptr, nullptr, index, index, false, &is_strict_find);
|
||||
oprop, nullptr, nullptr, {}, {}, index, index, false, &is_strict_find);
|
||||
BLI_assert(opop != nullptr);
|
||||
if (!is_strict_find) {
|
||||
/* No specific override operation, we have to get generic one,
|
||||
@@ -708,7 +708,7 @@ static int override_remove_button_exec(bContext *C, wmOperator *op)
|
||||
for (int idx = RNA_property_array_length(&ptr, prop); idx--;) {
|
||||
if (idx != index) {
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
oprop, opop->operation, nullptr, nullptr, idx, idx, true, nullptr, nullptr);
|
||||
oprop, opop->operation, nullptr, nullptr, {}, {}, idx, idx, true, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,8 +403,15 @@ void OverrideRNAPathTreeBuilder::ensure_entire_collection(
|
||||
item_idx,
|
||||
nullptr);
|
||||
IDOverrideLibraryPropertyOperation *item_operation =
|
||||
BKE_lib_override_library_property_operation_find(
|
||||
&override_data.override_property, nullptr, nullptr, -1, item_idx, false, nullptr);
|
||||
BKE_lib_override_library_property_operation_find(&override_data.override_property,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
item_idx,
|
||||
false,
|
||||
nullptr);
|
||||
TreeElement *current_te = nullptr;
|
||||
|
||||
TreeElement *existing_te = path_te_map.lookup_default(coll_item_path, nullptr);
|
||||
|
||||
@@ -244,6 +244,11 @@ typedef struct IDOverrideLibraryPropertyOperation {
|
||||
char *subitem_local_name;
|
||||
int subitem_reference_index;
|
||||
int subitem_local_index;
|
||||
/** Additional pointer to an ID. Only used and relevant when the related RNA collection stores ID
|
||||
* pointers, to help disambiguate cases where several IDs from different libraries have the exact
|
||||
* same name. */
|
||||
struct ID *subitem_reference_id;
|
||||
struct ID *subitem_local_id;
|
||||
} IDOverrideLibraryPropertyOperation;
|
||||
|
||||
/* IDOverrideLibraryPropertyOperation->operation. */
|
||||
@@ -278,6 +283,12 @@ enum {
|
||||
* reference linked data.
|
||||
*/
|
||||
LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE = 1 << 8,
|
||||
/**
|
||||
* For overrides of ID pointers within RNA collections: this override is using the ID
|
||||
* pointer in addition to the item name (to fully disambiguate the reference, since IDs from
|
||||
* different libraries can have a same name).
|
||||
*/
|
||||
LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID = 1 << 9,
|
||||
};
|
||||
|
||||
/** A single overridden property, contain all operations on this one. */
|
||||
|
||||
@@ -104,14 +104,14 @@ static const EnumPropertyItem rna_enum_override_library_property_operation_items
|
||||
"INSERT_AFTER",
|
||||
0,
|
||||
"Insert After",
|
||||
"Insert a new item into collection after the one referenced in subitem_reference_name or "
|
||||
"_index"},
|
||||
"Insert a new item into collection after the one referenced in "
|
||||
"subitem_reference_name/_id or _index"},
|
||||
{LIBOVERRIDE_OP_INSERT_BEFORE,
|
||||
"INSERT_BEFORE",
|
||||
0,
|
||||
"Insert Before",
|
||||
"Insert a new item into collection before the one referenced in subitem_reference_name or "
|
||||
"_index (NOT USED)"},
|
||||
"Insert a new item into collection before the one referenced in "
|
||||
"subitem_reference_name/_id or _index (NOT USED)"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
@@ -931,8 +931,11 @@ static IDOverrideLibraryPropertyOperation *rna_ID_override_library_property_oper
|
||||
IDOverrideLibraryProperty *override_property,
|
||||
ReportList *reports,
|
||||
int operation,
|
||||
const bool use_id,
|
||||
const char *subitem_refname,
|
||||
const char *subitem_locname,
|
||||
ID *subitem_refid,
|
||||
ID *subitem_locid,
|
||||
int subitem_refindex,
|
||||
int subitem_locindex)
|
||||
{
|
||||
@@ -943,6 +946,8 @@ static IDOverrideLibraryPropertyOperation *rna_ID_override_library_property_oper
|
||||
operation,
|
||||
subitem_refname,
|
||||
subitem_locname,
|
||||
use_id ? std::optional(subitem_refid) : std::nullopt,
|
||||
use_id ? std::optional(subitem_locid) : std::nullopt,
|
||||
subitem_refindex,
|
||||
subitem_locindex,
|
||||
false,
|
||||
@@ -1732,6 +1737,12 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
|
||||
0,
|
||||
"Match Reference",
|
||||
"The ID pointer overridden by this operation is expected to match the reference hierarchy"},
|
||||
{LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID,
|
||||
"IDPOINTER_ITEM_USE_ID",
|
||||
0,
|
||||
"ID Item Use ID Pointer",
|
||||
"RNA collections of IDs only, the reference to the item also uses the ID pointer itself, "
|
||||
"not only its name"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
@@ -1758,7 +1769,7 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
|
||||
nullptr,
|
||||
INT_MAX,
|
||||
"Subitem Reference Name",
|
||||
"Used to handle insertions into collection");
|
||||
"Used to handle changes into collection");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_ID_override_library_property_operation_refname_get",
|
||||
@@ -1770,20 +1781,36 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
|
||||
nullptr,
|
||||
INT_MAX,
|
||||
"Subitem Local Name",
|
||||
"Used to handle insertions into collection");
|
||||
"Used to handle changes into collection");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_ID_override_library_property_operation_locname_get",
|
||||
"rna_ID_override_library_property_operation_locname_length",
|
||||
nullptr);
|
||||
|
||||
prop = RNA_def_pointer(srna,
|
||||
"subitem_reference_id",
|
||||
"ID",
|
||||
"Subitem Reference ID",
|
||||
"Collection of IDs only, used to disambiguate between potential IDs with "
|
||||
"same name from different libraries");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
|
||||
prop = RNA_def_pointer(srna,
|
||||
"subitem_local_id",
|
||||
"ID",
|
||||
"Subitem Local ID",
|
||||
"Collection of IDs only, used to disambiguate between potential IDs with "
|
||||
"same name from different libraries");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
|
||||
prop = RNA_def_int(srna,
|
||||
"subitem_reference_index",
|
||||
-1,
|
||||
-1,
|
||||
INT_MAX,
|
||||
"Subitem Reference Index",
|
||||
"Used to handle insertions into collection",
|
||||
"Used to handle changes into collection",
|
||||
-1,
|
||||
INT_MAX);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
@@ -1794,7 +1821,7 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna)
|
||||
-1,
|
||||
INT_MAX,
|
||||
"Subitem Local Index",
|
||||
"Used to handle insertions into collection",
|
||||
"Used to handle changes into collection",
|
||||
-1,
|
||||
INT_MAX);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
|
||||
@@ -1822,25 +1849,41 @@ static void rna_def_ID_override_library_property_operations(BlenderRNA *brna, Pr
|
||||
"Operation",
|
||||
"What override operation is performed");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
parm = RNA_def_boolean(
|
||||
func,
|
||||
"use_id",
|
||||
false,
|
||||
"Use ID Pointer Subitem",
|
||||
"Whether the found or created liboverride operation should use ID pointers or not");
|
||||
parm = RNA_def_string(func,
|
||||
"subitem_reference_name",
|
||||
nullptr,
|
||||
INT_MAX,
|
||||
"Subitem Reference Name",
|
||||
"Used to handle insertions into collection");
|
||||
"Used to handle insertions or ID replacements into collection");
|
||||
parm = RNA_def_string(func,
|
||||
"subitem_local_name",
|
||||
nullptr,
|
||||
INT_MAX,
|
||||
"Subitem Local Name",
|
||||
"Used to handle insertions into collection");
|
||||
"Used to handle insertions or ID replacements into collection");
|
||||
parm = RNA_def_pointer(func,
|
||||
"subitem_reference_id",
|
||||
"ID",
|
||||
"Subitem Reference ID",
|
||||
"Used to handle ID replacements into collection");
|
||||
parm = RNA_def_pointer(func,
|
||||
"subitem_local_id",
|
||||
"ID",
|
||||
"Subitem Local ID",
|
||||
"Used to handle ID replacements into collection");
|
||||
parm = RNA_def_int(func,
|
||||
"subitem_reference_index",
|
||||
-1,
|
||||
-1,
|
||||
INT_MAX,
|
||||
"Subitem Reference Index",
|
||||
"Used to handle insertions into collection",
|
||||
"Used to handle insertions or ID replacements into collection",
|
||||
-1,
|
||||
INT_MAX);
|
||||
parm = RNA_def_int(func,
|
||||
@@ -1849,7 +1892,7 @@ static void rna_def_ID_override_library_property_operations(BlenderRNA *brna, Pr
|
||||
-1,
|
||||
INT_MAX,
|
||||
"Subitem Local Index",
|
||||
"Used to handle insertions into collection",
|
||||
"Used to handle insertions or ID replacements into collection",
|
||||
-1,
|
||||
INT_MAX);
|
||||
parm = RNA_def_pointer(func,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#include <CLG_log.h>
|
||||
|
||||
@@ -874,6 +875,8 @@ bool RNA_struct_override_matches(Main *bmain,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
false,
|
||||
@@ -1000,10 +1003,91 @@ bool RNA_struct_override_store(Main *bmain,
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool rna_property_override_collection_subitem_name_id_match(
|
||||
const char *item_name,
|
||||
const int item_name_len,
|
||||
const bool do_id_pointer,
|
||||
const std::optional<ID *> &item_id,
|
||||
PointerRNA *ptr_item_name)
|
||||
{
|
||||
BLI_assert(!do_id_pointer || RNA_struct_is_ID(ptr_item_name->type));
|
||||
|
||||
bool is_match = false;
|
||||
|
||||
if (do_id_pointer) {
|
||||
if (*item_id != static_cast<ID *>(ptr_item_name->data)) {
|
||||
/* If the ID pointer does not match, then there is no match, no need to check the
|
||||
* name iteself. */
|
||||
return is_match;
|
||||
}
|
||||
}
|
||||
|
||||
PropertyRNA *nameprop = ptr_item_name->type->nameproperty;
|
||||
char name[256];
|
||||
char *nameptr;
|
||||
int namelen;
|
||||
|
||||
nameptr = RNA_property_string_get_alloc(ptr_item_name, nameprop, name, sizeof(name), &namelen);
|
||||
|
||||
is_match = ((item_name_len == namelen) && STREQ(item_name, nameptr));
|
||||
|
||||
if (UNLIKELY(name != nameptr)) {
|
||||
MEM_freeN(nameptr);
|
||||
}
|
||||
|
||||
return is_match;
|
||||
}
|
||||
|
||||
static bool rna_property_override_collection_subitem_name_id_lookup(
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
const char *item_name,
|
||||
const int item_name_len,
|
||||
const bool do_id_pointer,
|
||||
const std::optional<ID *> &item_id,
|
||||
PointerRNA *r_ptr_item_name)
|
||||
{
|
||||
/* NOTE: This code is very similar to the one from #RNA_property_collection_lookup_string_index,
|
||||
* but it adds an extra early check on matching ID pointer.
|
||||
*
|
||||
* This custom code is needed because otherwise, it is only possible to check the first
|
||||
* name-matched item found by #RNA_property_collection_lookup_string, and not potential other
|
||||
* items having the same name. */
|
||||
if (do_id_pointer) {
|
||||
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
|
||||
|
||||
/* We cannot use a potential `CollectionPropertyRNA->lookupstring` here. */
|
||||
CollectionPropertyIterator iter;
|
||||
|
||||
RNA_property_collection_begin(ptr, prop, &iter);
|
||||
for (; iter.valid; RNA_property_collection_next(&iter)) {
|
||||
if (iter.ptr.data && iter.ptr.type->nameproperty) {
|
||||
if (rna_property_override_collection_subitem_name_id_match(
|
||||
item_name, item_name_len, do_id_pointer, item_id, &iter.ptr))
|
||||
{
|
||||
*r_ptr_item_name = iter.ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RNA_property_collection_end(&iter);
|
||||
|
||||
if (!iter.valid) {
|
||||
memset(r_ptr_item_name, 0, sizeof(*r_ptr_item_name));
|
||||
}
|
||||
|
||||
return bool(iter.valid);
|
||||
}
|
||||
else {
|
||||
return bool(RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_property_override_collection_subitem_name_index_lookup(
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
const char *item_name,
|
||||
const std::optional<ID *> &item_id,
|
||||
const int item_index,
|
||||
PointerRNA *r_ptr_item_name,
|
||||
PointerRNA *r_ptr_item_index)
|
||||
@@ -1011,21 +1095,23 @@ static void rna_property_override_collection_subitem_name_index_lookup(
|
||||
RNA_POINTER_INVALIDATE(r_ptr_item_name);
|
||||
RNA_POINTER_INVALIDATE(r_ptr_item_index);
|
||||
|
||||
PointerRNA collection_ptr_type;
|
||||
RNA_property_collection_type_get(ptr, prop, &collection_ptr_type);
|
||||
const bool do_id_pointer = item_id && RNA_struct_is_ID(collection_ptr_type.type);
|
||||
|
||||
const int item_name_len = item_name ? int(strlen(item_name)) : 0;
|
||||
|
||||
/* First, lookup by index, but only validate if name also matches (or if there is no given name).
|
||||
*
|
||||
* Note that this is also beneficial on performances (when looking up in big collections), since
|
||||
* typically index lookup will be faster than name lookup.
|
||||
*/
|
||||
if (item_index != -1) {
|
||||
if (RNA_property_collection_lookup_int(ptr, prop, item_index, r_ptr_item_index)) {
|
||||
if (item_name != nullptr) {
|
||||
PropertyRNA *nameprop = r_ptr_item_index->type->nameproperty;
|
||||
char name[256], *nameptr;
|
||||
int keylen = int(strlen(item_name));
|
||||
int namelen;
|
||||
|
||||
nameptr = RNA_property_string_get_alloc(
|
||||
r_ptr_item_index, nameprop, name, sizeof(name), &namelen);
|
||||
|
||||
if (keylen == namelen && STREQ(nameptr, item_name)) {
|
||||
/* Index and name both match. */
|
||||
if (item_name) {
|
||||
if (rna_property_override_collection_subitem_name_id_match(
|
||||
item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_index))
|
||||
{
|
||||
*r_ptr_item_name = *r_ptr_item_index;
|
||||
return;
|
||||
}
|
||||
@@ -1033,18 +1119,20 @@ static void rna_property_override_collection_subitem_name_index_lookup(
|
||||
}
|
||||
}
|
||||
|
||||
if (item_name == nullptr) {
|
||||
if (!item_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Then, lookup by name only. */
|
||||
if (RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name)) {
|
||||
/* Then, lookup by name (+ id) only. */
|
||||
if (rna_property_override_collection_subitem_name_id_lookup(
|
||||
ptr, prop, item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_name))
|
||||
{
|
||||
RNA_POINTER_INVALIDATE(r_ptr_item_index);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If name lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was successful it
|
||||
* will be the only valid return value. */
|
||||
/* If name (+ id) lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was
|
||||
* successful it will be the only valid return value. */
|
||||
}
|
||||
|
||||
static void rna_property_override_collection_subitem_lookup(
|
||||
@@ -1071,6 +1159,13 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
return;
|
||||
}
|
||||
|
||||
const bool use_id_pointer = (opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID) != 0;
|
||||
std::optional<ID *> subitem_local_id = use_id_pointer ? std::optional(opop->subitem_local_id) :
|
||||
std::nullopt;
|
||||
std::optional<ID *> subitem_reference_id = use_id_pointer ?
|
||||
std::optional(opop->subitem_reference_id) :
|
||||
std::nullopt;
|
||||
|
||||
RNA_POINTER_INVALIDATE(ptr_item_dst);
|
||||
RNA_POINTER_INVALIDATE(ptr_item_src);
|
||||
if (prop_storage != nullptr) {
|
||||
@@ -1083,12 +1178,14 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_src,
|
||||
prop_src,
|
||||
opop->subitem_local_name,
|
||||
subitem_local_id,
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_src_name,
|
||||
&ptr_item_src_index);
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_dst,
|
||||
prop_dst,
|
||||
opop->subitem_reference_name,
|
||||
subitem_reference_id,
|
||||
opop->subitem_reference_index,
|
||||
&ptr_item_dst_name,
|
||||
&ptr_item_dst_index);
|
||||
@@ -1108,6 +1205,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
ptr_dst,
|
||||
prop_dst,
|
||||
opop->subitem_local_name,
|
||||
{},
|
||||
opop->subitem_reference_index != -1 ? opop->subitem_reference_index :
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_dst_name,
|
||||
@@ -1121,6 +1219,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
ptr_dst,
|
||||
prop_dst,
|
||||
opop->subitem_local_name,
|
||||
{},
|
||||
opop->subitem_reference_index != -1 ? opop->subitem_reference_index :
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_dst_name,
|
||||
@@ -1130,6 +1229,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_src,
|
||||
prop_src,
|
||||
opop->subitem_reference_name,
|
||||
{},
|
||||
opop->subitem_local_index != -1 ?
|
||||
opop->subitem_local_index :
|
||||
opop->subitem_reference_index,
|
||||
@@ -1140,6 +1240,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_dst,
|
||||
prop_dst,
|
||||
nullptr,
|
||||
{},
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_dst_name,
|
||||
&ptr_item_dst_index);
|
||||
@@ -1148,6 +1249,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_src,
|
||||
prop_src,
|
||||
nullptr,
|
||||
{},
|
||||
opop->subitem_reference_index,
|
||||
&ptr_item_src_name,
|
||||
&ptr_item_src_index);
|
||||
@@ -1158,6 +1260,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_storage,
|
||||
prop_storage,
|
||||
opop->subitem_local_name,
|
||||
subitem_local_id,
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_storage_name,
|
||||
&ptr_item_storage_index);
|
||||
@@ -1165,6 +1268,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_storage,
|
||||
prop_storage,
|
||||
opop->subitem_reference_name,
|
||||
subitem_reference_id,
|
||||
opop->subitem_reference_index,
|
||||
&ptr_item_storage_name,
|
||||
&ptr_item_storage_index);
|
||||
@@ -1173,6 +1277,7 @@ static void rna_property_override_collection_subitem_lookup(
|
||||
rna_property_override_collection_subitem_name_index_lookup(ptr_storage,
|
||||
prop_storage,
|
||||
nullptr,
|
||||
{},
|
||||
opop->subitem_local_index,
|
||||
&ptr_item_storage_name,
|
||||
&ptr_item_storage_index);
|
||||
@@ -1593,7 +1698,7 @@ IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_fin
|
||||
}
|
||||
|
||||
return BKE_lib_override_library_property_operation_find(
|
||||
op, nullptr, nullptr, index, index, strict, r_strict);
|
||||
op, nullptr, nullptr, {}, {}, index, index, strict, r_strict);
|
||||
}
|
||||
|
||||
IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get(
|
||||
@@ -1617,7 +1722,7 @@ IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get
|
||||
}
|
||||
|
||||
return BKE_lib_override_library_property_operation_get(
|
||||
op, operation, nullptr, nullptr, index, index, strict, r_strict, r_created);
|
||||
op, operation, nullptr, nullptr, {}, {}, index, index, strict, r_strict, r_created);
|
||||
}
|
||||
|
||||
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain,
|
||||
|
||||
@@ -1265,13 +1265,17 @@ struct RNACompareOverrideDiffPropPtrContext {
|
||||
/** RNA collection items: forcefully get an item property name, even if one of the items is
|
||||
* null/doesn't have one. Mutually exclusive with `no_prop_name`. */
|
||||
bool do_force_name = false;
|
||||
/** RNA collection ID items: also check and store item's ID pointers. */
|
||||
bool use_id_pointer = false;
|
||||
|
||||
/** Information specific to RNA collections. */
|
||||
/* NOTE: names are typically set by a call to
|
||||
* #rna_property_override_diff_propptr_validate_diffing. Indices are typically set directly from
|
||||
* the loop over all RNA collections items in #rna_property_override_diff_default. */
|
||||
/* NOTE: names (and ID pointers, in case items are ID pointers) are typically set by a call
|
||||
* to #rna_property_override_diff_propptr_validate_diffing. Indices are typically set directly
|
||||
* from the loop over all RNA collections items in #rna_property_override_diff_default. */
|
||||
std::optional<std::string> rna_itemname_a;
|
||||
std::optional<std::string> rna_itemname_b;
|
||||
std::optional<ID *> rna_itemid_a;
|
||||
std::optional<ID *> rna_itemid_b;
|
||||
int rna_itemindex_a = -1;
|
||||
int rna_itemindex_b = -1;
|
||||
|
||||
@@ -1306,7 +1310,7 @@ static void rna_property_override_diff_propptr_validate_diffing(
|
||||
|
||||
BLI_assert(propptr_a != nullptr);
|
||||
|
||||
if (do_force_name) {
|
||||
if (do_force_name || ptrdiff_ctx.use_id_pointer) {
|
||||
BLI_assert(!no_prop_name);
|
||||
}
|
||||
|
||||
@@ -1341,6 +1345,7 @@ static void rna_property_override_diff_propptr_validate_diffing(
|
||||
PropertyRNA *nameprop_b = (propptr_b != nullptr && propptr_b->type != nullptr) ?
|
||||
RNA_struct_name_property(propptr_b->type) :
|
||||
nullptr;
|
||||
const bool do_id_pointer = ptrdiff_ctx.use_id_pointer && ptrdiff_ctx.is_id;
|
||||
|
||||
/* NOTE: Until we have a `std::string` version of `RNA_property_string_get`, these C string
|
||||
* pointers and buffers are needed here. Otherwise, in case of C string allocation, if the
|
||||
@@ -1363,9 +1368,22 @@ static void rna_property_override_diff_propptr_validate_diffing(
|
||||
propptr_b, nameprop_b, buff_b, sizeof(buff_b), &rna_itemname_b_len);
|
||||
ptrdiff_ctx.rna_itemname_b = rna_itemname_b;
|
||||
}
|
||||
|
||||
/* Note: This will always assign nullptr to these libpointers in case `do_id_lib` is false,
|
||||
* which ensures that they will not affect the result of `ptrdiff_ctx.is_valid_for_diffing` in
|
||||
* the last check below. */
|
||||
ID *rna_itemid_a = (do_id_pointer && propptr_a->data) ? static_cast<ID *>(propptr_a->data) :
|
||||
nullptr;
|
||||
ID *rna_itemid_b = (do_id_pointer && propptr_b->data) ? static_cast<ID *>(propptr_b->data) :
|
||||
nullptr;
|
||||
if (do_id_pointer) {
|
||||
ptrdiff_ctx.rna_itemid_a = rna_itemid_a;
|
||||
ptrdiff_ctx.rna_itemid_b = rna_itemid_b;
|
||||
}
|
||||
|
||||
if (rna_itemname_a != nullptr && rna_itemname_b != nullptr) {
|
||||
if (rna_itemname_a_len != rna_itemname_b_len || rna_itemname_a[0] != rna_itemname_b[0] ||
|
||||
!STREQ(rna_itemname_a, rna_itemname_b))
|
||||
if (rna_itemid_a != rna_itemid_b || rna_itemname_a_len != rna_itemname_b_len ||
|
||||
rna_itemname_a[0] != rna_itemname_b[0] || !STREQ(rna_itemname_a, rna_itemname_b))
|
||||
{
|
||||
ptrdiff_ctx.is_valid_for_diffing = false;
|
||||
// printf("%s: different names\n", rna_path ? rna_path : "<UNKNOWN>");
|
||||
@@ -1469,6 +1487,8 @@ static void rna_property_override_diff_propptr(Main *bmain,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
subitem_refname,
|
||||
subitem_locname,
|
||||
ptrdiff_ctx.rna_itemid_b,
|
||||
ptrdiff_ctx.rna_itemid_a,
|
||||
rna_itemindex_b,
|
||||
rna_itemindex_a,
|
||||
true,
|
||||
@@ -1493,6 +1513,8 @@ static void rna_property_override_diff_propptr(Main *bmain,
|
||||
opop = BKE_lib_override_library_property_operation_find(op,
|
||||
subitem_refname,
|
||||
subitem_locname,
|
||||
ptrdiff_ctx.rna_itemid_b,
|
||||
ptrdiff_ctx.rna_itemid_a,
|
||||
rna_itemindex_b,
|
||||
rna_itemindex_a,
|
||||
true,
|
||||
@@ -1721,8 +1743,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) {
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
else {
|
||||
@@ -1746,8 +1777,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) { /* If not yet overridden... */
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
}
|
||||
@@ -1777,8 +1817,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) {
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (created) {
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
@@ -1804,8 +1853,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) { /* If not yet overridden... */
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
}
|
||||
@@ -1835,8 +1893,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) {
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
else {
|
||||
@@ -1860,8 +1927,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) { /* If not yet overridden... */
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
}
|
||||
@@ -1878,8 +1954,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) { /* If not yet overridden... */
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
}
|
||||
@@ -1907,8 +1992,17 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
op = BKE_lib_override_library_property_get(liboverride, rna_path, &created);
|
||||
|
||||
if (op != nullptr && created) { /* If not yet overridden... */
|
||||
BKE_lib_override_library_property_operation_get(
|
||||
op, LIBOVERRIDE_OP_REPLACE, nullptr, nullptr, -1, -1, true, nullptr, nullptr);
|
||||
BKE_lib_override_library_property_operation_get(op,
|
||||
LIBOVERRIDE_OP_REPLACE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
-1,
|
||||
-1,
|
||||
true,
|
||||
nullptr,
|
||||
nullptr);
|
||||
rnadiff_ctx.report_flag |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
|
||||
}
|
||||
}
|
||||
@@ -1953,6 +2047,7 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
int idx_a = 0;
|
||||
int idx_b = 0;
|
||||
std::optional<std::string> prev_rna_itemname_a;
|
||||
std::optional<ID *> prev_rna_itemid_a;
|
||||
|
||||
CollectionPropertyIterator iter_a, iter_b;
|
||||
RNA_property_collection_begin(ptr_a, rawprop_a, &iter_a);
|
||||
@@ -1985,6 +2080,7 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
}
|
||||
ptrdiff_ctx.no_prop_name = no_prop_name;
|
||||
ptrdiff_ctx.do_force_name = !no_prop_name;
|
||||
ptrdiff_ctx.use_id_pointer = !no_prop_name;
|
||||
ptrdiff_ctx.no_ownership = no_ownership;
|
||||
ptrdiff_ctx.property_type = PROP_COLLECTION;
|
||||
|
||||
@@ -1994,6 +2090,7 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
* when calling #rna_property_override_diff_propptr. */
|
||||
ptrdiff_ctx.no_prop_name = true;
|
||||
ptrdiff_ctx.do_force_name = false;
|
||||
ptrdiff_ctx.use_id_pointer = false;
|
||||
}
|
||||
|
||||
const bool is_valid_for_diffing = ptrdiff_ctx.is_valid_for_diffing;
|
||||
@@ -2047,6 +2144,8 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
(no_prop_name || !ptrdiff_ctx.rna_itemname_a) ?
|
||||
nullptr :
|
||||
ptrdiff_ctx.rna_itemname_a->c_str(),
|
||||
prev_rna_itemid_a,
|
||||
ptrdiff_ctx.rna_itemid_a,
|
||||
idx_a - 1,
|
||||
idx_a,
|
||||
true,
|
||||
@@ -2077,6 +2176,7 @@ void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffCont
|
||||
else {
|
||||
prev_rna_itemname_a.reset();
|
||||
}
|
||||
prev_rna_itemid_a = ptrdiff_ctx.rna_itemid_a;
|
||||
|
||||
if (!do_create && !equals) {
|
||||
abort = true; /* Early out in case we do not want to loop over whole collection. */
|
||||
|
||||
@@ -323,6 +323,19 @@ class TestLibraryOverridesComplex(TestHelper, unittest.TestCase):
|
||||
|
||||
for coll_ in root_collection.children_recursive:
|
||||
liboverride_systemoverrideonly_hierarchy_validate(coll_, root_collection)
|
||||
if coll_.override_library:
|
||||
for op in coll_.override_library.properties:
|
||||
for opop in op.operations:
|
||||
assert 'IDPOINTER_ITEM_USE_ID' in opop.flag
|
||||
print(
|
||||
coll_,
|
||||
opop.flag,
|
||||
opop.subitem_reference_name,
|
||||
opop.subitem_reference_id,
|
||||
opop.subitem_local_name,
|
||||
opop.subitem_local_id)
|
||||
assert opop.subitem_reference_id.library is not None
|
||||
assert opop.subitem_local_id.library is None if coll_.library is None else opop.subitem_local_id.library is not None
|
||||
for ob_ in root_collection.all_objects:
|
||||
liboverride_systemoverrideonly_hierarchy_validate(ob_, root_collection)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user