Blender V4.5
rna_access_compare_override.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10#include <fmt/format.h>
11#include <optional>
12
13#include <CLG_log.h>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_ID.h"
18#include "DNA_anim_types.h"
19#include "DNA_camera_types.h"
21#include "DNA_key_types.h"
22#include "DNA_modifier_types.h"
23#include "DNA_object_types.h"
24
25#include "BLI_listbase.h"
26#include "BLI_utildefines.h"
27
28// #define DEBUG_OVERRIDE_TIMEIT
29
30#ifdef DEBUG_OVERRIDE_TIMEIT
31# include "BLI_time_utildefines.h"
32# include <stdio.h>
33#endif
34
35#include "BKE_armature.hh"
36#include "BKE_idprop.hh"
37#include "BKE_idtype.hh"
38#include "BKE_lib_override.hh"
39#include "BKE_library.hh"
40#include "BKE_main.hh"
41
42#include "RNA_access.hh"
43#include "RNA_enum_types.hh"
44#include "RNA_path.hh"
45#include "RNA_prototypes.hh"
46
48#include "rna_internal.hh"
49
50static CLG_LogRef LOG = {"rna.access_compare_override"};
51
62 PropertyRNA *prop,
63 std::optional<std::string> *r_rna_path)
64{
65 ID *id = ptr->owner_id;
66 ID *owner_id = id;
67 const char *rna_path_prefix = nullptr;
68
69 if (r_rna_path != nullptr) {
70 *r_rna_path = std::nullopt;
71 }
72
73 if (id == nullptr) {
74 return nullptr;
75 }
76
78 /* XXX this is very bad band-aid code, but for now it will do.
79 * We should at least use a #define for those prop names.
80 * Ideally RNA as a whole should be aware of those PITA of embedded IDs, and have a way to
81 * retrieve their owner IDs and generate paths from those.
82 */
83
84 switch (GS(id->name)) {
85 case ID_KE:
86 owner_id = ((Key *)id)->from;
87 rna_path_prefix = "shape_keys.";
88 break;
89 case ID_GR:
90 case ID_NT:
91 /* Master collections, Root node trees. */
92 owner_id = RNA_find_real_ID_and_path(id, &rna_path_prefix);
93 break;
94 default:
96 }
97 }
98
99 if (r_rna_path == nullptr) {
100 return owner_id;
101 }
102
103 if (std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop)) {
104 if (rna_path_prefix) {
105 r_rna_path->emplace(fmt::format("{}{}", rna_path_prefix, *rna_path));
106 }
107 else {
108 r_rna_path->emplace(std::move(*rna_path));
109 }
110
111 return owner_id;
112 }
113 return nullptr;
114}
115
120
122{
123 if (prop->magic == RNA_MAGIC) {
124 /* Special handling for insertions of constraints or modifiers... */
125 /* TODO: Note We may want to add a more generic system to RNA
126 * (like a special property in struct of items)
127 * if we get more overridable collections,
128 * for now we can live with those special-cases handling I think. */
129 if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
130 bConstraint *con = static_cast<bConstraint *>(ptr->data);
132 return true;
133 }
134 }
135 else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
136 ModifierData *mod = static_cast<ModifierData *>(ptr->data);
138 return true;
139 }
140 }
141 else if (RNA_struct_is_a(ptr->type, &RNA_NlaTrack)) {
142 NlaTrack *nla_track = static_cast<NlaTrack *>(ptr->data);
143 if (nla_track->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) {
144 return true;
145 }
146 }
147 else if (RNA_struct_is_a(ptr->type, &RNA_CameraBackgroundImage)) {
148 CameraBGImage *bgpic = static_cast<CameraBGImage *>(ptr->data);
150 return true;
151 }
152 }
153 else if (RNA_struct_is_a(ptr->type, &RNA_BoneCollection)) {
154 BoneCollection *bcoll = static_cast<BoneCollection *>(ptr->data);
156 return true;
157 }
158 }
159 /* If this is a RNA-defined property (real or 'virtual' IDProp),
160 * we want to use RNA prop flag. */
161 return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
163 }
164 /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
165 IDProperty *idprop = (IDProperty *)prop;
166 return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
167}
168
170 PropertyRNA *prop,
171 const bool is_overridable)
172{
173 /* Only works for pure custom properties IDProps. */
174 if (prop->magic != RNA_MAGIC) {
175 IDProperty *idprop = (IDProperty *)prop;
176 constexpr short flags = (IDP_FLAG_OVERRIDABLE_LIBRARY | IDP_FLAG_STATIC_TYPE);
177 idprop->flag = is_overridable ? (idprop->flag | flags) : (idprop->flag & ~flags);
178 return true;
179 }
180
181 return false;
182}
183
185{
186 const std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop);
187 ID *id = ptr->owner_id;
188
189 if (!rna_path || id == nullptr || !ID_IS_OVERRIDE_LIBRARY(id)) {
190 return false;
191 }
192
193 return (BKE_lib_override_library_property_find(id->override_library, rna_path->c_str()) !=
194 nullptr);
195}
196
198{
199 prop = rna_ensure_property(prop);
200
202}
203
205 RNAPropertyOverrideApplyContext &rnaapply_ctx);
206
208 Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
209{
210 if (!RNA_property_editable(ptr, prop)) {
211 return false;
212 }
213
216 opop.subitem_reference_index = index;
217 opop.subitem_local_index = index;
218
220 rnaapply_ctx.ptr_dst = *ptr;
221 rnaapply_ctx.ptr_src = *fromptr;
222 rnaapply_ctx.prop_dst = prop;
223 rnaapply_ctx.prop_src = prop;
224 rnaapply_ctx.liboverride_operation = &opop;
225
226 return rna_property_override_operation_apply(bmain, rnaapply_ctx);
227}
228
229static int rna_property_override_diff(Main *bmain,
230 PropertyRNAOrID *prop_a,
231 PropertyRNAOrID *prop_b,
232 const char *rna_path,
233 const size_t rna_path_len,
234 eRNACompareMode mode,
235 IDOverrideLibrary *liboverride,
236 const eRNAOverrideMatch flags,
237 eRNAOverrideMatchResult *r_report_flags);
238
240 Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
241{
243
244 PropertyRNAOrID prop_a, prop_b;
245
246 rna_property_rna_or_id_get(prop, ptr_a, &prop_a);
247 rna_property_rna_or_id_get(prop, ptr_b, &prop_b);
248
250 bmain, &prop_a, &prop_b, nullptr, 0, mode, nullptr, eRNAOverrideMatch(0), nullptr) ==
251 0);
252}
253
255{
257 PropertyRNA *iterprop;
258 bool equals = true;
259
260 if (ptr_a == nullptr && ptr_b == nullptr) {
261 return true;
262 }
263 if (ptr_a == nullptr || ptr_b == nullptr) {
264 return false;
265 }
266 if (ptr_a->type != ptr_b->type) {
267 return false;
268 }
269
270 iterprop = RNA_struct_iterator_property(ptr_a->type);
271
272 RNA_property_collection_begin(ptr_a, iterprop, &iter);
273 for (; iter.valid; RNA_property_collection_next(&iter)) {
274 PropertyRNA *prop = static_cast<PropertyRNA *>(iter.ptr.data);
275
276 if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
277 equals = false;
278 break;
279 }
280 }
282
283 return equals;
284}
285
286/* Low-level functions, also used by non-override RNA API like copy or equality check. */
287
298 PropertyRNAOrID *prop_a,
299 PropertyRNAOrID *prop_b,
300 const char *rna_path,
301 const size_t rna_path_len,
302 eRNACompareMode mode,
303 IDOverrideLibrary *liboverride,
304 const eRNAOverrideMatch flags,
305 eRNAOverrideMatchResult *r_report_flags)
306{
307 BLI_assert(!ELEM(nullptr, prop_a, prop_b));
308
311 {
312 return 0;
313 }
314
315 if (mode == RNA_EQ_UNSET_MATCH_ANY) {
316 /* Unset properties are assumed to match anything. */
317 if (!prop_a->is_set || !prop_b->is_set) {
318 return 0;
319 }
320 }
321 else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
322 /* Unset properties never match set properties. */
323 if (prop_a->is_set != prop_b->is_set) {
324 return 1;
325 }
326 }
327
328 if (prop_a->is_idprop && ELEM(nullptr, prop_a->idprop, prop_b->idprop)) {
329 return (prop_a->idprop == prop_b->idprop) ? 0 : 1;
330 }
331
332 /* Check if we are working with arrays. */
333 const bool is_array_a = prop_a->is_array;
334 const bool is_array_b = prop_b->is_array;
335
336 if (is_array_a != is_array_b) {
337 /* Should probably never happen actually... */
339 return is_array_a ? 1 : -1;
340 }
341
342 /* Get the length of the array to work with. */
343 const uint len_a = prop_a->array_len;
344 const uint len_b = prop_b->array_len;
345
346 if (len_a != len_b) {
347 /* Do not handle override in that case,
348 * we do not support insertion/deletion from arrays for now. */
349 return len_a > len_b ? 1 : -1;
350 }
351
352 if (is_array_a && len_a == 0) {
353 /* Empty arrays, will happen in some case with dynamic ones. */
354 return 0;
355 }
356
357 RNAPropOverrideDiff override_diff = nullptr;
358 /* Special case for IDProps, we use default callback then. */
359 if (prop_a->is_idprop) {
361 if (!prop_b->is_idprop && prop_b->rnaprop->override_diff != override_diff) {
362 override_diff = nullptr;
363 }
364 }
365 else if (prop_b->is_idprop) {
367 if (prop_a->rnaprop->override_diff != override_diff) {
368 override_diff = nullptr;
369 }
370 }
371 else if (prop_a->rnaprop->override_diff == prop_b->rnaprop->override_diff) {
372 override_diff = prop_a->rnaprop->override_diff;
373 if (override_diff == nullptr) {
375 }
376 }
377
378 if (override_diff == nullptr) {
380 &LOG,
381 "'%s' gives unmatching or nullptr RNA diff callbacks, should not happen (%d vs. %d)",
382 rna_path ? rna_path : prop_a->identifier,
383 !prop_a->is_idprop,
384 !prop_b->is_idprop);
386 return 1;
387 }
388
389 eRNAOverrideMatch diff_flags = flags;
390 if (!RNA_property_overridable_get(prop_a->ptr, prop_a->rawprop) ||
392 !RNA_property_editable_flag(prop_a->ptr, prop_a->rawprop)))
393 {
394 diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
395 }
396
398 rnadiff_ctx.prop_a = prop_a;
399 rnadiff_ctx.prop_b = prop_b;
400 rnadiff_ctx.mode = mode;
401
402 rnadiff_ctx.liboverride = liboverride;
403 rnadiff_ctx.rna_path = rna_path;
404 rnadiff_ctx.rna_path_len = rna_path_len;
405 rnadiff_ctx.liboverride_flags = diff_flags;
406 override_diff(bmain, rnadiff_ctx);
407
408 if (r_report_flags) {
409 *r_report_flags = rnadiff_ctx.report_flag;
410 }
411 return rnadiff_ctx.comparison;
412}
413
414/* Modify local data-block to make it ready for override application
415 * (only needed for diff operations, where we use
416 * the local data-block's data as second operand). */
418 PointerRNA *ptr_local,
419 PointerRNA *ptr_reference,
420 PointerRNA *ptr_storage,
421 PropertyRNA *prop_local,
422 PropertyRNA *prop_reference,
423 PropertyRNA *prop_storage,
425{
426 int len_local, len_reference, len_storage = 0;
427 bool changed = false;
428
429 if (ptr_storage == nullptr) {
430 return changed;
431 }
432
433 /* get the length of the array to work with */
434 len_local = RNA_property_array_length(ptr_local, prop_local);
435 len_reference = RNA_property_array_length(ptr_reference, prop_reference);
436 if (prop_storage) {
437 len_storage = RNA_property_array_length(ptr_storage, prop_storage);
438 }
439
440 if (len_local != len_reference || len_local != len_storage) {
441 /* Do not handle override in that case,
442 * we do not support insertion/deletion from arrays for now. */
443 return changed;
444 }
445
446 RNAPropOverrideStore override_store = nullptr;
447 /* Special case for IDProps, we use default callback then. */
448 if (prop_local->magic != RNA_MAGIC) {
450 if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) {
451 override_store = nullptr;
452 }
453 }
454 else if (prop_reference->magic != RNA_MAGIC) {
456 if (prop_local->override_store != override_store) {
457 override_store = nullptr;
458 }
459 }
460 else if (prop_local->override_store == prop_reference->override_store) {
461 override_store = prop_local->override_store;
462 if (override_store == nullptr) {
464 }
465 }
466
467 if ((prop_storage->magic == RNA_MAGIC) &&
468 !ELEM(prop_storage->override_store, nullptr, override_store))
469 {
470 override_store = nullptr;
471 }
472
473 if (override_store == nullptr) {
475 &LOG,
476 "'%s' gives unmatching or nullptr RNA store callbacks, should not happen (%d vs. %d)",
477 op->rna_path,
478 prop_local->magic == RNA_MAGIC,
479 prop_reference->magic == RNA_MAGIC);
481 return changed;
482 }
483
485 /* Only needed for diff operations. */
486 if (!ELEM(
488 {
489 continue;
490 }
491
492 if (override_store(bmain,
493 ptr_local,
494 ptr_reference,
495 ptr_storage,
496 prop_local,
497 prop_reference,
498 prop_storage,
499 len_local,
500 len_reference,
501 len_storage,
502 opop))
503 {
504 changed = true;
505 }
506 }
507
508 return changed;
509}
510
513{
514 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
515 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
516 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
517 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
518 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
519 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
521
522 const short override_op = opop->operation;
523
525 opop, ptr_dst, ptr_src, ptr_storage, prop_dst, prop_src, prop_storage))
526 {
527 return false;
528 }
529
530 if (override_op == LIBOVERRIDE_OP_NOOP) {
531 return true;
532 }
533
534 RNAPropOverrideApply override_apply = nullptr;
535 /* Special case for IDProps, we use default callback then. */
536 if (prop_dst->magic != RNA_MAGIC) {
538 if (prop_src->magic == RNA_MAGIC && !ELEM(prop_src->override_apply, nullptr, override_apply)) {
539 override_apply = nullptr;
540 }
541 }
542 else if (prop_src->magic != RNA_MAGIC) {
544 if (!ELEM(prop_dst->override_apply, nullptr, override_apply)) {
545 override_apply = nullptr;
546 }
547 }
548 else if (prop_dst->override_apply == prop_src->override_apply) {
549 override_apply = prop_dst->override_apply;
550 if (override_apply == nullptr) {
552 }
553 }
554
555 if (prop_storage && prop_storage->magic == RNA_MAGIC &&
556 !ELEM(prop_storage->override_apply, nullptr, override_apply))
557 {
558 override_apply = nullptr;
559 }
560
561 if (override_apply == nullptr) {
563 &LOG,
564 "'%s' gives unmatching or nullptr RNA apply callbacks, should not happen (%d vs. %d)",
565 prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
566 prop_dst->magic == RNA_MAGIC,
567 prop_src->magic == RNA_MAGIC);
569 return false;
570 }
571
572 /* get the length of the array to work with */
573 rnaapply_ctx.len_dst = RNA_property_array_length(ptr_dst, prop_dst);
574 rnaapply_ctx.len_src = RNA_property_array_length(ptr_src, prop_src);
575 if (prop_storage) {
576 rnaapply_ctx.len_storage = RNA_property_array_length(ptr_storage, prop_storage);
577 }
578
579 if (rnaapply_ctx.len_dst != rnaapply_ctx.len_src ||
580 (prop_storage && rnaapply_ctx.len_dst != rnaapply_ctx.len_storage))
581 {
582 /* Do not handle override in that case,
583 * we do not support insertion/deletion from arrays for now. */
584 return false;
585 }
586
587 /* get and set the default values as appropriate for the various types */
588 const bool success = override_apply(bmain, rnaapply_ctx);
589 return success;
590}
591
593 PointerRNA *ptr_local,
594 PointerRNA *ptr_reference,
595 const char *root_path,
596 const size_t root_path_len,
597 IDOverrideLibrary *liboverride,
598 const eRNAOverrideMatch flags,
599 eRNAOverrideMatchResult *r_report_flags)
600{
602 PropertyRNA *iterprop;
603 bool matching = true;
604
605 BLI_assert(ptr_local->type == ptr_reference->type);
606 BLI_assert(ptr_local->owner_id && ptr_reference->owner_id);
607
608 const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
609 const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
610 const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
611 const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
612 const bool do_tag_for_restore = (flags & RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE) != 0;
613
614#ifdef DEBUG_OVERRIDE_TIMEIT
615 static float _sum_time_global = 0.0f;
616 static float _num_time_global = 0.0f;
617 double _timeit_time_global;
618 static float _sum_time_diffing = 0.0f;
619 static float _delta_time_diffing = 0.0f;
620 static int _num_delta_time_diffing = 0.0f;
621 static float _num_time_diffing = 0.0f;
622 double _timeit_time_diffing;
623
624 if (!root_path) {
625 _delta_time_diffing = 0.0f;
626 _num_delta_time_diffing = 0;
627 _timeit_time_global = BLI_time_now_seconds();
628 }
629#endif
630
631 if (ptr_local->owner_id == ptr_local->data && GS(ptr_local->owner_id->name) == ID_OB) {
632 /* Our beloved pose's bone cross-data pointers. Usually, depsgraph evaluation would
633 * ensure this is valid, but in some situations (like hidden collections etc.) this won't
634 * be the case, so we need to take care of this ourselves.
635 *
636 * NOTE: Typically callers of this function (from BKE_lib_override area) will already have
637 * ensured this. However, studio is still reporting sporadic, unreproducible crashes due to
638 * invalid pose data, so think there are still some cases where some armatures are somehow
639 * missing updates (possibly due to dependencies?). Since calling this function on same ID
640 * several time is almost free, and safe even in a threaded context as long as it has been done
641 * at least once first outside of threaded processing, we do it another time here. */
642 Object *ob_local = (Object *)ptr_local->owner_id;
643 if (ob_local->type == OB_ARMATURE) {
644 Object *ob_reference = (Object *)ptr_local->owner_id->override_library->reference;
645 BLI_assert(ob_local->data != nullptr);
646 BLI_assert(ob_reference->data != nullptr);
647 BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
648 BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
649 }
650 }
651
652 iterprop = RNA_struct_iterator_property(ptr_local->type);
653
654 for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
656 {
657 PropertyRNA *rawprop = static_cast<PropertyRNA *>(iter.ptr.data);
658
659 PropertyRNAOrID prop_local;
660 PropertyRNAOrID prop_reference;
661
662 rna_property_rna_or_id_get(rawprop, ptr_local, &prop_local);
663 rna_property_rna_or_id_get(rawprop, ptr_reference, &prop_reference);
664
665 BLI_assert(prop_local.rnaprop != nullptr);
666 BLI_assert(prop_local.rnaprop == prop_reference.rnaprop);
667 BLI_assert(prop_local.is_idprop == prop_reference.is_idprop);
668
669 if ((prop_local.is_idprop && prop_local.idprop == nullptr) ||
670 (prop_reference.is_idprop && prop_reference.idprop == nullptr))
671 {
672 continue;
673 }
674
675 if (ignore_non_overridable && !RNA_property_overridable_get(prop_local.ptr, rawprop)) {
676 continue;
677 }
678
679 if (!prop_local.is_idprop &&
681 {
682 continue;
683 }
684
685#if 0
686 /* This actually makes things slower, since it has to check for animation paths etc! */
687 if (RNA_property_animated(ptr_local, prop_local)) {
688 /* We cannot do anything here really, animation is some kind of dynamic overrides that has
689 * precedence over static one... */
690 continue;
691 }
692#endif
693
694#define RNA_PATH_BUFFSIZE 8192
695
696 std::optional<std::string> rna_path;
697 size_t rna_path_len = 0;
698
699 /* XXX TODO: this will have to be refined to handle collections insertions, and array items. */
700 if (root_path) {
701 BLI_assert(strlen(root_path) == root_path_len);
702
703 const char *prop_name = prop_local.identifier;
704 const size_t prop_name_len = strlen(prop_name);
705
706 char rna_path_buffer[RNA_PATH_BUFFSIZE];
707 char *rna_path_c = rna_path_buffer;
708
709 /* Inlined building (significantly more efficient). */
710 if (!prop_local.is_idprop) {
711 rna_path_len = root_path_len + 1 + prop_name_len;
712 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
713 rna_path = MEM_malloc_arrayN<char>(rna_path_len + 1, __func__);
714 }
715
716 memcpy(rna_path_c, root_path, root_path_len);
717 rna_path_c[root_path_len] = '.';
718 memcpy(rna_path_c + root_path_len + 1, prop_name, prop_name_len);
719 rna_path_c[rna_path_len] = '\0';
720 }
721 else {
722 rna_path_len = root_path_len + 2 + prop_name_len + 2;
723 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
724 rna_path_c = MEM_malloc_arrayN<char>(rna_path_len + 1, __func__);
725 }
726
727 memcpy(rna_path_c, root_path, root_path_len);
728 rna_path_c[root_path_len] = '[';
729 rna_path_c[root_path_len + 1] = '"';
730 memcpy(rna_path_c + root_path_len + 2, prop_name, prop_name_len);
731 rna_path_c[root_path_len + 2 + prop_name_len] = '"';
732 rna_path_c[root_path_len + 2 + prop_name_len + 1] = ']';
733 rna_path_c[rna_path_len] = '\0';
734 }
735
736 rna_path.emplace(rna_path_c);
737 }
738 else {
739 /* This is rather slow, but is not much called, so not really worth optimizing. */
740 rna_path = RNA_path_from_ID_to_property(ptr_local, rawprop);
741 if (rna_path) {
742 rna_path_len = rna_path->size();
743 }
744 }
745 if (!rna_path) {
746 continue;
747 }
748
749 CLOG_INFO(&LOG, 5, "Override Checking %s", rna_path->c_str());
750
751 if (ignore_overridden) {
753 rna_path->c_str());
754 if (op != nullptr) {
756 continue;
757 }
758 }
759
760#ifdef DEBUG_OVERRIDE_TIMEIT
761 if (!root_path) {
762 _timeit_time_diffing = BLI_time_now_seconds();
763 }
764#endif
765
767 const int diff = rna_property_override_diff(bmain,
768 &prop_local,
769 &prop_reference,
770 rna_path->c_str(),
771 rna_path_len,
773 liboverride,
774 flags,
775 &report_flags);
776
777#ifdef DEBUG_OVERRIDE_TIMEIT
778 if (!root_path) {
779 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_diffing);
780 _delta_time_diffing += _delta_time;
781 _num_delta_time_diffing++;
782 }
783#endif
784
785 matching = matching && diff == 0;
786 if (r_report_flags) {
787 *r_report_flags = (*r_report_flags | report_flags);
788 }
789
790 if (diff != 0) {
791 /* XXX TODO: refine this for per-item overriding of arrays... */
793 rna_path->c_str());
795 op ? op->operations.first : nullptr);
796
797 if (op != nullptr) {
798 /* Only set all operations from this property as used (via
799 * #BKE_lib_override_library_operations_tag) if the property itself is still tagged as
800 * unused.
801 *
802 * In case the property itself is already tagged as used, in means lower-level diffing code
803 * took care of this property (e.g. as is needed collections of items, since then some
804 * operations may be valid, while others may need to be purged). */
807 }
808 }
809
810 if ((do_restore || do_tag_for_restore) &&
811 (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0)
812 {
813 /* We are allowed to restore to reference's values. */
814 if (ELEM(nullptr, op, opop) || opop->operation == LIBOVERRIDE_OP_NOOP) {
815 if (RNA_property_editable(ptr_local, rawprop)) {
816 /* This property should be restored to its reference value. This should not be done
817 * here, since this code may be called from non-main thread (modifying data through RNA
818 * is not thread safe). */
819 if (do_restore) {
822 opop_tmp.subitem_reference_index = -1;
823 opop_tmp.subitem_local_index = -1;
824
826 rnaapply_ctx.ptr_dst = *ptr_local;
827 rnaapply_ctx.ptr_src = *ptr_reference;
828 rnaapply_ctx.prop_dst = rawprop;
829 rnaapply_ctx.prop_src = rawprop;
830 rnaapply_ctx.liboverride_operation = &opop_tmp;
831
832 const bool is_restored = rna_property_override_operation_apply(bmain, rnaapply_ctx);
833
834 if (is_restored) {
835 CLOG_INFO(&LOG,
836 5,
837 "Restoreed forbidden liboverride `%s` for override data '%s'",
838 rna_path->c_str(),
839 ptr_local->owner_id->name);
840 if (r_report_flags) {
841 *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
842 }
843 }
844 else {
845 CLOG_INFO(&LOG,
846 2,
847 "Failed to restore forbidden liboverride `%s` for override data '%s'",
848 rna_path->c_str(),
849 ptr_local->owner_id->name);
850 }
851 }
852 else {
853 if (op == nullptr) {
854 /* An override property is needed, create a temp one if necessary. */
856 liboverride, rna_path->c_str(), nullptr);
858 }
862 nullptr,
863 nullptr,
864 {},
865 {},
866 -1,
867 -1,
868 false,
869 nullptr,
870 nullptr);
871 /* Do not use `BKE_lib_override_library_operations_tag` here, as the property may be
872 * a valid one that has other operations that needs to remain (e.g. from a template,
873 * a NOOP operation to enforce no change on that property, etc.). */
875 opop_restore->tag |= LIBOVERRIDE_PROP_TAG_NEEDS_RETORE;
877
878 CLOG_INFO(
879 &LOG,
880 5,
881 "Tagging for restoration forbidden liboverride `%s` for override data '%s'",
882 rna_path->c_str(),
883 ptr_local->owner_id->name);
884 if (r_report_flags) {
886 }
887 }
888 }
889 else {
890 /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
891#if 0
893 "We have differences between reference and "
894 "overriding data on non-editable property.");
895#endif
896 matching = false;
897 }
898 }
899 }
900 else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(nullptr, op, opop))
901 {
902 /* This property is not overridden, and differs from reference, so we have no match. */
903 matching = false;
904 if (!(do_create || do_restore || do_tag_for_restore)) {
905
906 break;
907 }
908 }
909 }
910#undef RNA_PATH_BUFFSIZE
911 }
913
914#ifdef DEBUG_OVERRIDE_TIMEIT
915 if (!root_path) {
916 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_global);
917 _sum_time_global += _delta_time;
918 _num_time_global++;
919 _sum_time_diffing += _delta_time_diffing;
920 _num_time_diffing++;
921 printf("ID: %s\n", ((ID *)ptr_local->owner_id)->name);
922 printf("time end (%s): %.6f\n", __func__, _delta_time);
923 printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
924 __func__,
925 (_sum_time_global / _num_time_global),
926 _sum_time_global,
927 int(_num_time_global));
928 printf("diffing time end (%s): %.6f (in %d runs)\n",
929 __func__,
930 _delta_time_diffing,
931 _num_delta_time_diffing);
932 printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
933 __func__,
934 (_sum_time_diffing / _num_time_diffing),
935 _sum_time_diffing,
936 int(_num_time_diffing));
937 }
938#endif
939
940 return matching;
941}
942
944 PointerRNA *ptr_local,
945 PointerRNA *ptr_reference,
946 PointerRNA *ptr_storage,
947 IDOverrideLibrary *liboverride)
948{
949 bool changed = false;
950
951#ifdef DEBUG_OVERRIDE_TIMEIT
953#endif
955 /* Simplified for now! */
956 PointerRNA data_reference, data_local;
957 PropertyRNA *prop_reference, *prop_local;
958
959 if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
960 RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
961 {
962 PointerRNA data_storage;
963 PropertyRNA *prop_storage = nullptr;
964
965 /* It is totally OK if this does not success,
966 * only a subset of override operations actually need storage. */
967 if (ptr_storage && (ptr_storage->owner_id != nullptr)) {
968 RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
969 }
970
972 &data_local,
973 &data_reference,
974 &data_storage,
975 prop_reference,
976 prop_local,
977 prop_storage,
978 op))
979 {
980 changed = true;
981 }
982 }
983 }
984#ifdef DEBUG_OVERRIDE_TIMEIT
986#endif
987
988 return changed;
989}
990
992 const char *item_name,
993 const int item_name_len,
994 const bool do_id_pointer,
995 const std::optional<ID *> &item_id,
996 PointerRNA *ptr_item_name)
997{
998 BLI_assert(!do_id_pointer || RNA_struct_is_ID(ptr_item_name->type));
999
1000 bool is_match = false;
1001
1002 if (do_id_pointer) {
1003 if (*item_id != static_cast<ID *>(ptr_item_name->data)) {
1004 /* If the ID pointer does not match, then there is no match, no need to check the
1005 * name itself. */
1006 return is_match;
1007 }
1008 }
1009
1010 PropertyRNA *nameprop = ptr_item_name->type->nameproperty;
1011 char name_buf[256];
1012 char *name;
1013 int namelen;
1014
1016 ptr_item_name, nameprop, name_buf, sizeof(name_buf), &namelen);
1017
1018 is_match = ((item_name_len == namelen) && STREQ(item_name, name));
1019
1020 if (UNLIKELY(name != name_buf)) {
1021 MEM_freeN(name);
1022 }
1023
1024 return is_match;
1025}
1026
1028 PointerRNA *ptr,
1029 PropertyRNA *prop,
1030 const char *item_name,
1031 const int item_name_len,
1032 const bool do_id_pointer,
1033 const std::optional<ID *> &item_id,
1034 PointerRNA *r_ptr_item_name)
1035{
1036 /* NOTE: This code is very similar to the one from #RNA_property_collection_lookup_string_index,
1037 * but it adds an extra early check on matching ID pointer.
1038 *
1039 * This custom code is needed because otherwise, it is only possible to check the first
1040 * name-matched item found by #RNA_property_collection_lookup_string, and not potential other
1041 * items having the same name. */
1042 if (do_id_pointer) {
1044
1045 /* We cannot use a potential `CollectionPropertyRNA->lookupstring` here. */
1047
1048 RNA_property_collection_begin(ptr, prop, &iter);
1049 for (; iter.valid; RNA_property_collection_next(&iter)) {
1050 if (iter.ptr.data && iter.ptr.type->nameproperty) {
1052 item_name, item_name_len, do_id_pointer, item_id, &iter.ptr))
1053 {
1054 *r_ptr_item_name = iter.ptr;
1055 break;
1056 }
1057 }
1058 }
1060
1061 if (!iter.valid) {
1062 *r_ptr_item_name = {};
1063 }
1064
1065 return iter.valid;
1066 }
1067
1068 return RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name);
1069}
1070
1072 PointerRNA *ptr,
1073 PropertyRNA *prop,
1074 const char *item_name,
1075 const std::optional<ID *> &item_id,
1076 const int item_index,
1077 PointerRNA *r_ptr_item_name,
1078 PointerRNA *r_ptr_item_index)
1079{
1080 r_ptr_item_name->invalidate();
1081 r_ptr_item_index->invalidate();
1082
1083 const bool do_id_pointer = item_id && RNA_struct_is_ID(RNA_property_pointer_type(ptr, prop));
1084
1085 const int item_name_len = item_name ? int(strlen(item_name)) : 0;
1086
1087 /* First, lookup by index, but only validate if name also matches (or if there is no given name).
1088 *
1089 * Note that this is also beneficial on performances (when looking up in big collections), since
1090 * typically index lookup will be faster than name lookup.
1091 */
1092 if (item_index != -1) {
1093 if (RNA_property_collection_lookup_int(ptr, prop, item_index, r_ptr_item_index)) {
1094 if (item_name && r_ptr_item_index->type) {
1096 item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_index))
1097 {
1098 *r_ptr_item_name = *r_ptr_item_index;
1099 return;
1100 }
1101 }
1102 }
1103 }
1104
1105 if (!item_name) {
1106 return;
1107 }
1108
1109 /* Then, lookup by name (+ id) only. */
1111 ptr, prop, item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_name))
1112 {
1113 r_ptr_item_index->invalidate();
1114 return;
1115 }
1116
1117 /* If name (+ id) lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was
1118 * successful it will be the only valid return value. */
1119}
1120
1122 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1123{
1124 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
1125 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
1126 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
1127 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
1128 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
1129 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
1130 PointerRNA *ptr_item_dst = &rnaapply_ctx.ptr_item_dst;
1131 PointerRNA *ptr_item_src = &rnaapply_ctx.ptr_item_src;
1132 PointerRNA *ptr_item_storage = &rnaapply_ctx.ptr_item_storage;
1135
1136 if ((RNA_property_type(prop_dst) != PROP_COLLECTION ||
1137 RNA_property_type(prop_src) != PROP_COLLECTION ||
1138 (prop_storage != nullptr && RNA_property_type(prop_storage) != PROP_COLLECTION)) ||
1139 (opop->subitem_local_name == nullptr && opop->subitem_reference_name == nullptr &&
1140 opop->subitem_local_index == -1 && opop->subitem_reference_index == -1))
1141 {
1142 return;
1143 }
1144
1145 const bool use_id_pointer = (opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID) != 0;
1146 std::optional<ID *> subitem_local_id = use_id_pointer ? std::optional(opop->subitem_local_id) :
1147 std::nullopt;
1148 std::optional<ID *> subitem_reference_id = use_id_pointer ?
1149 std::optional(opop->subitem_reference_id) :
1150 std::nullopt;
1151
1152 ptr_item_dst->invalidate();
1153 ptr_item_src->invalidate();
1154 if (prop_storage != nullptr) {
1155 ptr_item_storage->invalidate();
1156 }
1157
1158 PointerRNA ptr_item_dst_name, ptr_item_dst_index;
1159 PointerRNA ptr_item_src_name, ptr_item_src_index;
1160 PointerRNA ptr_item_storage_name, ptr_item_storage_index;
1162 prop_src,
1163 opop->subitem_local_name,
1164 subitem_local_id,
1165 opop->subitem_local_index,
1166 &ptr_item_src_name,
1167 &ptr_item_src_index);
1169 prop_dst,
1171 subitem_reference_id,
1173 &ptr_item_dst_name,
1174 &ptr_item_dst_index);
1175 /* This is rather fragile, but the fact that local override IDs may have a different name
1176 * than their linked reference makes it necessary.
1177 * Basically, here we are considering that if we cannot find the original linked ID in
1178 * the local override we are (re-)applying the operations, then it may be because some of
1179 * those operations have already been applied, and we may already have the local ID
1180 * pointer we want to set.
1181 * This happens e.g. during re-sync of an override, since we have already remapped all ID
1182 * pointers to their expected values.
1183 * In that case we simply try to get the property from the local expected name. */
1184 if (opop->subitem_reference_name != nullptr && opop->subitem_local_name != nullptr &&
1185 ptr_item_dst_name.type == nullptr)
1186 {
1188 ptr_dst,
1189 prop_dst,
1190 opop->subitem_local_name,
1191 {},
1193 opop->subitem_local_index,
1194 &ptr_item_dst_name,
1195 &ptr_item_dst_index);
1196 }
1197
1198 /* For historical compatibility reasons, we fallback to reference if no local item info is given,
1199 * and vice-versa. */
1200 if (opop->subitem_reference_name == nullptr && opop->subitem_local_name != nullptr) {
1202 ptr_dst,
1203 prop_dst,
1204 opop->subitem_local_name,
1205 {},
1207 opop->subitem_local_index,
1208 &ptr_item_dst_name,
1209 &ptr_item_dst_index);
1210 }
1211 else if (opop->subitem_reference_name != nullptr && opop->subitem_local_name == nullptr) {
1213 prop_src,
1215 {},
1216 opop->subitem_local_index != -1 ?
1217 opop->subitem_local_index :
1219 &ptr_item_src_name,
1220 &ptr_item_src_index);
1221 }
1222 if (opop->subitem_reference_index == -1 && opop->subitem_local_index != -1) {
1224 prop_dst,
1225 nullptr,
1226 {},
1227 opop->subitem_local_index,
1228 &ptr_item_dst_name,
1229 &ptr_item_dst_index);
1230 }
1231 else if (opop->subitem_reference_index != -1 && opop->subitem_local_index == -1) {
1233 prop_src,
1234 nullptr,
1235 {},
1237 &ptr_item_src_name,
1238 &ptr_item_src_index);
1239 }
1240
1241 /* For storage, simply lookup by name first, and fallback to indices. */
1242 if (prop_storage != nullptr) {
1244 prop_storage,
1245 opop->subitem_local_name,
1246 subitem_local_id,
1247 opop->subitem_local_index,
1248 &ptr_item_storage_name,
1249 &ptr_item_storage_index);
1250 if (ptr_item_storage_name.data == nullptr) {
1252 prop_storage,
1254 subitem_reference_id,
1256 &ptr_item_storage_name,
1257 &ptr_item_storage_index);
1258 }
1259 if (ptr_item_storage_name.data == nullptr && ptr_item_storage_index.data == nullptr) {
1261 prop_storage,
1262 nullptr,
1263 {},
1264 opop->subitem_local_index,
1265 &ptr_item_storage_name,
1266 &ptr_item_storage_index);
1267 }
1268 }
1269
1270 /* Final selection. both matches have to be based on names, or indices, but not a mix of both. */
1271 if (ptr_item_src_name.type != nullptr && ptr_item_dst_name.type != nullptr) {
1272 *ptr_item_src = ptr_item_src_name;
1273 *ptr_item_dst = ptr_item_dst_name;
1274 if (prop_storage != nullptr) {
1275 *ptr_item_storage = ptr_item_storage_name;
1276 }
1277 }
1278 else if (ptr_item_src_index.type != nullptr && ptr_item_dst_index.type != nullptr) {
1279 *ptr_item_src = ptr_item_src_index;
1280 *ptr_item_dst = ptr_item_dst_index;
1281 if (prop_storage != nullptr) {
1282 *ptr_item_storage = ptr_item_storage_index;
1283 }
1284 }
1285
1286 /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
1287 * and index are invalid. This can often happen when inserting new items (constraint,
1288 * modifier...) in a collection that supports it. */
1289 if (ptr_item_dst->type == nullptr &&
1290 ((opop->subitem_reference_name != nullptr && opop->subitem_reference_name[0] != '\0') ||
1291 opop->subitem_reference_index != -1))
1292 {
1293 CLOG_INFO(&LOG,
1294 2,
1295 "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
1296 opop->subitem_reference_name != nullptr ? opop->subitem_reference_name : "",
1298 op->rna_path,
1299 ptr_dst->owner_id->name);
1300 }
1301 if (ptr_item_src->type == nullptr &&
1302 ((opop->subitem_local_name != nullptr && opop->subitem_local_name[0] != '\0') ||
1303 opop->subitem_local_index != -1))
1304 {
1305 CLOG_INFO(&LOG,
1306 2,
1307 "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
1308 opop->subitem_local_name != nullptr ? opop->subitem_local_name : "",
1309 opop->subitem_local_index,
1310 op->rna_path,
1311 ptr_src->owner_id->name);
1312 }
1313}
1314
1316 PointerRNA *ptr_dst,
1317 PointerRNA *ptr_src,
1318 PointerRNA *ptr_item_dst,
1319 PointerRNA *ptr_item_src)
1320{
1322 bmain, ptr_src, nullptr, nullptr);
1324 bmain, ptr_dst, nullptr, nullptr);
1325 ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, nullptr, nullptr);
1326 ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, nullptr, nullptr);
1327
1329
1330 /* If the owner ID is not part of an override hierarchy, there is no possible resync. */
1332 return;
1333 }
1334
1335 /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
1336 * here. */
1337 if (id_src != nullptr && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
1338 return;
1339 }
1340
1341 if (/* We might be in a case where id_dst has already been processed and its usages
1342 * remapped to its new local override. In that case overrides and linked data
1343 * are always properly matching. */
1344 id_src != id_dst &&
1345 /* If one of the pointers is nullptr and not the other, we are in a non-matching case. */
1346 (ELEM(nullptr, id_src, id_dst) ||
1347 /* If `id_dst` is not from same lib as id_src, and linked reference ID of `id_src` is not
1348 * `id_dst`, we are in a non-matching case. */
1349 (id_dst->lib != id_src->lib && id_src->override_library->reference != id_dst) ||
1350 /* If `id_dst` is from same lib as id_src, and is not same as `id_owner`, we are in a
1351 * non-matching case.
1352 *
1353 * NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new
1354 * override copy generated by `BKE_lib_override_library_update` will already have its
1355 * self-references updated to itself, instead of still pointing to its linked source. */
1356 (id_dst->lib == id_src->lib && id_dst != id_owner_dst)))
1357 {
1358 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1359 if (ID_IS_LINKED(id_owner_src)) {
1360 id_owner_src->lib->runtime->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1361 }
1362 CLOG_INFO(&LOG,
1363 3,
1364 "Local override %s detected as needing resync due to mismatch in its used IDs",
1365 id_owner_dst->name);
1366 }
1367 if ((id_owner_src->override_library->reference->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) != 0) {
1368 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1369 if (ID_IS_LINKED(id_owner_src)) {
1370 id_owner_src->lib->runtime->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1371 }
1372 CLOG_INFO(&LOG,
1373 3,
1374 "Local override %s detected as needing resync as its liboverride reference is "
1375 "already tagged for resync",
1376 id_owner_dst->name);
1377 }
1378}
1379
1381 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1382{
1384 const bool do_insert = rnaapply_ctx.do_insert;
1385
1387 if (opop->operation == LIBOVERRIDE_OP_NOOP) {
1388 continue;
1389 }
1390
1391 if (!do_insert !=
1393 {
1394 if (!do_insert) {
1395 CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path);
1396 }
1397 continue;
1398 }
1399
1400 rnaapply_ctx.liboverride_operation = opop;
1401
1403
1404 if (!rna_property_override_operation_apply(bmain, rnaapply_ctx)) {
1405 CLOG_INFO(&LOG,
1406 4,
1407 "Failed to apply '%s' override operation on %s\n",
1408 op->rna_path,
1409 rnaapply_ctx.ptr_src.owner_id->name);
1410 }
1411 }
1412
1413 rnaapply_ctx.liboverride_operation = nullptr;
1414}
1415
1421 PointerRNA *id_ptr_dst,
1422 PointerRNA *id_ptr_src,
1423 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1424{
1425 UNUSED_VARS_NDEBUG(bmain, id_ptr_src);
1426
1427 if ((rnaapply_ctx.flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) == 0) {
1428 return false;
1429 }
1430
1431 if (!RNA_struct_is_ID(RNA_property_pointer_type(&rnaapply_ctx.ptr_dst, rnaapply_ctx.prop_dst))) {
1433 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1434 return false;
1435 }
1436
1438
1439 /* IDProperties case. */
1440 if (rnaapply_ctx.prop_dst->magic != RNA_MAGIC) {
1441 CLOG_INFO(&LOG,
1442 2,
1443 "%s: Ignoring local override on ID pointer custom property '%s', as requested by "
1444 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1445 id_ptr_dst->owner_id->name,
1446 op->rna_path);
1447 return true;
1448 }
1449
1450 switch (op->rna_prop_type) {
1451 case PROP_POINTER: {
1452 if ((static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1454 {
1456 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1458 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1459
1460 CLOG_INFO(&LOG,
1461 2,
1462 "%s: Ignoring local override on ID pointer property '%s', as requested by "
1463 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1464 id_ptr_dst->owner_id->name,
1465 op->rna_path);
1466 return true;
1467 }
1468 break;
1469 }
1470 case PROP_COLLECTION: {
1471 /* For collections of ID pointers just completely skip the override ops here... A tad brutal,
1472 * but this is a backup 'fix the mess' tool, and in practice this should never be an issue.
1473 * Can always be refined later if needed. */
1474 CLOG_INFO(&LOG,
1475 2,
1476 "%s: Ignoring all local override on ID pointer collection property '%s', as "
1477 "requested by RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1478 id_ptr_dst->owner_id->name,
1479 op->rna_path);
1480 return true;
1481 }
1482 default:
1483 break;
1484 }
1485
1486 return false;
1487}
1488
1490 PointerRNA *id_ptr_dst,
1491 PointerRNA *id_ptr_src,
1492 PointerRNA *id_ptr_storage,
1493 IDOverrideLibrary *liboverride,
1495{
1496#ifdef DEBUG_OVERRIDE_TIMEIT
1498#endif
1499 const bool do_restore_only = (flag & RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY) != 0;
1500 /* NOTE: Applying insert operations in a separate pass is mandatory.
1501 * We could optimize this later, but for now, as inefficient as it is,
1502 * don't think this is a critical point.
1503 */
1504 bool do_insert = false;
1505 for (int i = 0; i < (do_restore_only ? 1 : 2); i++, do_insert = true) {
1507 if (do_restore_only && (op->tag % LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0) {
1508 continue;
1509 }
1510 /* That tag should only exist for short lifespan when restoring values from reference linked
1511 * data. */
1512 BLI_assert((op->tag & LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0 || do_restore_only);
1513
1515 rnaapply_ctx.flag = flag;
1516 rnaapply_ctx.do_insert = do_insert;
1517
1518 rnaapply_ctx.liboverride = liboverride;
1519 rnaapply_ctx.liboverride_property = op;
1520
1522 op->rna_path,
1523 &rnaapply_ctx.ptr_dst,
1524 &rnaapply_ctx.prop_dst,
1525 &rnaapply_ctx.ptr_item_dst) &&
1527 op->rna_path,
1528 &rnaapply_ctx.ptr_src,
1529 &rnaapply_ctx.prop_src,
1530 &rnaapply_ctx.ptr_item_src)))
1531 {
1532 CLOG_INFO(&LOG,
1533 4,
1534 "Failed to apply library override operation to '%s.%s' "
1535 "(could not resolve some properties, local: %d, override: %d)",
1536 static_cast<ID *>(id_ptr_src->owner_id)->name,
1537 op->rna_path,
1539 id_ptr_dst, op->rna_path, &rnaapply_ctx.ptr_dst, &rnaapply_ctx.prop_dst),
1541 id_ptr_src, op->rna_path, &rnaapply_ctx.ptr_src, &rnaapply_ctx.prop_src));
1542 continue;
1543 }
1544
1545 /* It is totally OK if this does not success,
1546 * only a subset of override operations actually need storage. */
1547 if (id_ptr_storage && (id_ptr_storage->owner_id != nullptr)) {
1549 op->rna_path,
1550 &rnaapply_ctx.ptr_storage,
1551 &rnaapply_ctx.prop_storage,
1552 &rnaapply_ctx.ptr_item_storage);
1553 }
1554
1555 /* Check if an overridden ID pointer supposed to be in sync with linked data gets out of
1556 * sync. */
1558 (id_ptr_dst->owner_id->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) == 0)
1559 {
1560 if (op->rna_prop_type == PROP_POINTER && op->operations.first != nullptr &&
1561 (static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1563 {
1565 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1567 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1569 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1570
1571 PointerRNA prop_ptr_src = RNA_property_pointer_get(&rnaapply_ctx.ptr_src,
1572 rnaapply_ctx.prop_src);
1573 PointerRNA prop_ptr_dst = RNA_property_pointer_get(&rnaapply_ctx.ptr_dst,
1574 rnaapply_ctx.prop_dst);
1576 bmain, id_ptr_dst, id_ptr_src, &prop_ptr_dst, &prop_ptr_src);
1577 }
1578 else if (op->rna_prop_type == PROP_COLLECTION) {
1579 if (RNA_struct_is_ID(
1580 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)))
1581 {
1582 BLI_assert(id_ptr_src->owner_id ==
1584 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1585 BLI_assert(id_ptr_dst->owner_id ==
1587 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1588
1589 LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
1590 if ((opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
1591 continue;
1592 }
1593 rnaapply_ctx.liboverride_operation = opop;
1594
1596
1598 id_ptr_dst,
1599 id_ptr_src,
1600 &rnaapply_ctx.ptr_item_dst,
1601 &rnaapply_ctx.ptr_item_src);
1602 }
1603 rnaapply_ctx.liboverride_operation = nullptr;
1604 }
1605 }
1606 }
1607
1608 if (override_apply_property_check_skip(bmain, id_ptr_dst, id_ptr_src, rnaapply_ctx)) {
1609 continue;
1610 }
1611
1612 rna_property_override_apply_ex(bmain, rnaapply_ctx);
1613 }
1614 }
1615
1616 /* Some cases (like point caches) may require additional post-processing. */
1617 if (RNA_struct_is_a(id_ptr_dst->type, &RNA_ID)) {
1618 ID *id_dst = static_cast<ID *>(id_ptr_dst->data);
1619 ID *id_src = static_cast<ID *>(id_ptr_src->data);
1620 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id_dst);
1621 if (id_type->lib_override_apply_post != nullptr) {
1622 id_type->lib_override_apply_post(id_dst, id_src);
1623 }
1624 }
1625
1626#ifdef DEBUG_OVERRIDE_TIMEIT
1628#endif
1629}
1630
1632 PointerRNA *ptr,
1633 PropertyRNA *prop,
1634 ID **r_owner_id)
1635{
1636 std::optional<std::string> rna_path;
1637
1638 *r_owner_id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1639 if (rna_path) {
1641 (*r_owner_id)->override_library, rna_path->c_str());
1642 return op;
1643 }
1644 return nullptr;
1645}
1646
1648 PointerRNA *ptr,
1649 PropertyRNA *prop,
1650 bool *r_created)
1651{
1652 std::optional<std::string> rna_path;
1653
1654 if (r_created != nullptr) {
1655 *r_created = false;
1656 }
1657
1658 ID *id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1659 if (rna_path) {
1661 id->override_library, rna_path->c_str(), r_created);
1662 return op;
1663 }
1664 return nullptr;
1665}
1666
1668 Main *bmain,
1669 PointerRNA *ptr,
1670 PropertyRNA *prop,
1671 const int index,
1672 const bool strict,
1673 bool *r_strict)
1674{
1675 ID *owner_id;
1677
1678 if (!op) {
1679 return nullptr;
1680 }
1681
1683 op, nullptr, nullptr, {}, {}, index, index, strict, r_strict);
1684}
1685
1687 Main *bmain,
1688 PointerRNA *ptr,
1689 PropertyRNA *prop,
1690 const short operation,
1691 const int index,
1692 const bool strict,
1693 bool *r_strict,
1694 bool *r_created)
1695{
1696 if (r_created != nullptr) {
1697 *r_created = false;
1698 }
1699
1701
1702 if (!op) {
1703 return nullptr;
1704 }
1705
1707 op, operation, nullptr, nullptr, {}, {}, index, index, strict, r_strict, r_created);
1708}
1709
1711 PointerRNA *ptr,
1712 PropertyRNA *prop,
1713 const int index)
1714{
1715 eRNAOverrideStatus override_status = eRNAOverrideStatus(0);
1716
1717 if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) {
1718 return override_status;
1719 }
1720
1722 override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
1723 }
1724
1726 bmain, ptr, prop, index, false, nullptr);
1727 if (opop != nullptr) {
1728 override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
1729 if (opop->flag & LIBOVERRIDE_OP_FLAG_MANDATORY) {
1730 override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
1731 }
1732 if (opop->flag & LIBOVERRIDE_OP_FLAG_LOCKED) {
1733 override_status |= RNA_OVERRIDE_STATUS_LOCKED;
1734 }
1735 }
1736
1737 return override_status;
1738}
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
Definition armature.cc:2932
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:147
void BKE_lib_override_library_operations_tag(IDOverrideLibraryProperty *liboverride_property, short tag, bool do_set)
IDOverrideLibraryProperty * BKE_lib_override_library_property_find(IDOverrideLibrary *liboverride, const char *rna_path)
IDOverrideLibraryProperty * BKE_lib_override_library_property_get(IDOverrideLibrary *liboverride, const char *rna_path, bool *r_created)
IDOverrideLibraryPropertyOperation * BKE_lib_override_library_property_operation_get(IDOverrideLibraryProperty *liboverride_property, 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, bool *r_strict, bool *r_created)
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, bool *r_strict)
bool BKE_lib_override_library_property_operation_operands_validate(IDOverrideLibraryPropertyOperation *liboverride_property_operation, PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage)
@ LIBRARY_TAG_RESYNC_REQUIRED
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
double BLI_time_now_seconds(void)
Definition time.cc:65
Utility defines for timing/benchmarks.
#define TIMEIT_START_AVERAGED(var)
#define TIMEIT_END_AVERAGED(var)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
ID and Library types, which are fundamental for SDNA.
@ LIBOVERRIDE_PROP_TAG_NEEDS_RETORE
Definition DNA_ID.h:287
@ LIBOVERRIDE_PROP_OP_TAG_UNUSED
Definition DNA_ID.h:284
@ LIBOVERRIDE_OP_FLAG_MANDATORY
Definition DNA_ID.h:238
@ LIBOVERRIDE_OP_FLAG_LOCKED
Definition DNA_ID.h:240
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID
Definition DNA_ID.h:252
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE
Definition DNA_ID.h:246
@ ID_TAG_LIBOVERRIDE_NEED_RESYNC
Definition DNA_ID.h:814
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:698
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:687
@ LIBOVERRIDE_OP_NOOP
Definition DNA_ID.h:218
@ LIBOVERRIDE_OP_ADD
Definition DNA_ID.h:223
@ LIBOVERRIDE_OP_SUBTRACT
Definition DNA_ID.h:225
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:220
@ LIBOVERRIDE_OP_MULTIPLY
Definition DNA_ID.h:227
@ LIBOVERRIDE_OP_INSERT_BEFORE
Definition DNA_ID.h:231
@ LIBOVERRIDE_OP_INSERT_AFTER
Definition DNA_ID.h:230
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:348
@ LIBOVERRIDE_TAG_NEEDS_RESTORE
Definition DNA_ID.h:306
@ ID_NT
@ ID_KE
@ ID_GR
@ ID_OB
@ IDP_FLAG_STATIC_TYPE
@ IDP_FLAG_OVERRIDABLE_LIBRARY
@ NLATRACK_OVERRIDELIBRARY_LOCAL
@ BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL
@ CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL
@ CONSTRAINT_OVERRIDE_LIBRARY_LOCAL
@ eModifierFlag_OverrideLibrary_Local
Object is a sort of wrapper for general info.
@ OB_ARMATURE
Read Guarded memory(de)allocation.
eRNAOverrideStatus
@ RNA_OVERRIDE_STATUS_OVERRIDABLE
@ RNA_OVERRIDE_STATUS_MANDATORY
@ RNA_OVERRIDE_STATUS_OVERRIDDEN
@ RNA_OVERRIDE_STATUS_LOCKED
eRNAOverrideApplyFlag
@ RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS
@ RNA_OVERRIDE_APPLY_FLAG_SKIP_RESYNC_CHECK
@ RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY
eRNAOverrideMatch
@ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN
@ RNA_OVERRIDE_COMPARE_CREATE
@ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE
@ RNA_OVERRIDE_COMPARE_RESTORE
@ RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE
eRNACompareMode
@ RNA_EQ_UNSET_MATCH_ANY
@ RNA_EQ_STRICT
@ RNA_EQ_UNSET_MATCH_NONE
eRNAOverrideMatchResult
@ RNA_OVERRIDE_MATCH_RESULT_RESTORED
@ RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED
@ RNA_OVERRIDE_MATCH_RESULT_CREATED
@ PROP_POINTER
Definition RNA_types.hh:155
@ PROP_COLLECTION
Definition RNA_types.hh:156
@ PROPOVERRIDE_OVERRIDABLE_LIBRARY
Definition RNA_types.hh:469
@ PROPOVERRIDE_NO_COMPARISON
Definition RNA_types.hh:477
@ PROPOVERRIDE_IGNORE
Definition RNA_types.hh:489
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
#define printf(...)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_IS_LINKED(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
#define LOG(severity)
Definition log.h:32
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
void rna_property_rna_or_id_get(PropertyRNA *prop, PointerRNA *ptr, PropertyRNAOrID *r_prop_rna_or_id)
bool RNA_struct_is_ID(const StructRNA *type)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, CollectionPropertyIterator *iter)
PropertyType RNA_property_type(PropertyRNA *prop)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_collection_next(CollectionPropertyIterator *iter)
bool RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, PointerRNA *r_ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr)
void RNA_property_collection_end(CollectionPropertyIterator *iter)
PropertyRNA * RNA_struct_iterator_property(StructRNA *type)
bool RNA_property_editable_flag(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * rna_ensure_property(PropertyRNA *prop)
IDOverrideLibraryPropertyOperation * RNA_property_override_property_operation_get(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, const bool strict, bool *r_strict, bool *r_created)
IDOverrideLibraryProperty * RNA_property_override_property_find(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, ID **r_owner_id)
IDOverrideLibraryProperty * RNA_property_override_property_get(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
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)
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)
static bool override_apply_property_check_skip(Main *bmain, PointerRNA *id_ptr_dst, PointerRNA *id_ptr_src, RNAPropertyOverrideApplyContext &rnaapply_ctx)
bool RNA_property_overridable_library_set(PointerRNA *, PropertyRNA *prop, const bool is_overridable)
IDOverrideLibraryPropertyOperation * RNA_property_override_property_operation_find(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
bool RNA_struct_override_store(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideLibrary *liboverride)
static void rna_property_override_apply_ex(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
static bool rna_property_override_operation_store(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideLibraryProperty *op)
static ID * rna_property_override_property_real_id_owner(Main *, PointerRNA *ptr, PropertyRNA *prop, std::optional< std::string > *r_rna_path)
int RNA_property_override_flag(PropertyRNA *prop)
static void rna_property_override_collection_subitem_lookup(RNAPropertyOverrideApplyContext &rnaapply_ctx)
bool RNA_property_comparable(PointerRNA *, PropertyRNA *prop)
static int rna_property_override_diff(Main *bmain, PropertyRNAOrID *prop_a, PropertyRNAOrID *prop_b, const char *rna_path, const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *liboverride, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags)
#define RNA_PATH_BUFFSIZE
static bool rna_property_override_operation_apply(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
void RNA_struct_override_apply(Main *bmain, PointerRNA *id_ptr_dst, PointerRNA *id_ptr_src, PointerRNA *id_ptr_storage, IDOverrideLibrary *liboverride, const eRNAOverrideApplyFlag flag)
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_overridable_get(const PointerRNA *ptr, PropertyRNA *prop)
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)
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index)
bool RNA_property_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
static void rna_property_override_check_resync(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_item_dst, PointerRNA *ptr_item_src)
bool RNA_struct_override_matches(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path, const size_t root_path_len, IDOverrideLibrary *liboverride, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags)
bool RNA_property_copy(Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
bool rna_property_override_apply_default(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffContext &rnadiff_ctx)
bool rna_property_override_store_default(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, int len_local, int len_reference, int len_storage, IDOverrideLibraryPropertyOperation *opop)
#define RNA_MAGIC
bool(*)(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx) RNAPropOverrideApply
void(*)(Main *bmain, RNAPropertyOverrideDiffContext &rnadiff_ctx) RNAPropOverrideDiff
bool(*)(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, int len_local, int len_reference, int len_storage, IDOverrideLibraryPropertyOperation *opop) RNAPropOverrideStore
ID * RNA_find_real_ID_and_path(ID *id, const char **r_path)
Definition rna_path.cc:954
bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, PointerRNA *r_item_ptr)
Definition rna_path.cc:582
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1173
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:560
unsigned int rna_prop_type
Definition DNA_ID.h:278
ListBase properties
Definition DNA_ID.h:326
unsigned int flag
Definition DNA_ID.h:338
struct ID * reference
Definition DNA_ID.h:324
IDOverrideLibraryRuntime * runtime
Definition DNA_ID.h:336
short flag
Definition DNA_ID.h:153
IDTypeLibOverrideApplyPost lib_override_apply_post
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct Library * lib
Definition DNA_ID.h:410
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
void * first
ID * owner_id
Definition RNA_types.hh:51
void invalidate()
Definition RNA_types.hh:110
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
RNAPropOverrideApply override_apply
RNAPropOverrideStore override_store
RNAPropOverrideDiff override_diff
IDOverrideLibraryProperty * liboverride_property
IDOverrideLibraryPropertyOperation * liboverride_operation
eRNAOverrideMatchResult report_flag
PropertyRNA * nameproperty
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4227
uint8_t flag
Definition wm_window.cc:139