Blender V5.0
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 if (RNA_pointer_is_null(ptr_a)) {
271 if (RNA_pointer_is_null(ptr_b)) {
272 return true;
273 }
274 return false;
275 }
276
277 iterprop = RNA_struct_iterator_property(ptr_a->type);
278
279 RNA_property_collection_begin(ptr_a, iterprop, &iter);
280 for (; iter.valid; RNA_property_collection_next(&iter)) {
281 PropertyRNA *prop = static_cast<PropertyRNA *>(iter.ptr.data);
282
283 if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
284 equals = false;
285 break;
286 }
287 }
289
290 return equals;
291}
292
293/* Low-level functions, also used by non-override RNA API like copy or equality check. */
294
305 PropertyRNAOrID *prop_a,
306 PropertyRNAOrID *prop_b,
307 const char *rna_path,
308 const size_t rna_path_len,
309 eRNACompareMode mode,
310 IDOverrideLibrary *liboverride,
311 const eRNAOverrideMatch flags,
312 eRNAOverrideMatchResult *r_report_flags)
313{
314 BLI_assert(!ELEM(nullptr, prop_a, prop_b));
315
318 {
319 return 0;
320 }
321
322 if (mode == RNA_EQ_UNSET_MATCH_ANY) {
323 /* Unset properties are assumed to match anything. */
324 if (!prop_a->is_set || !prop_b->is_set) {
325 return 0;
326 }
327 }
328 else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
329 /* Unset properties never match set properties. */
330 if (prop_a->is_set != prop_b->is_set) {
331 return 1;
332 }
333 }
334
335 if (prop_a->is_idprop && ELEM(nullptr, prop_a->idprop, prop_b->idprop)) {
336 return (prop_a->idprop == prop_b->idprop) ? 0 : 1;
337 }
338
339 /* Check if we are working with arrays. */
340 const bool is_array_a = prop_a->is_array;
341 const bool is_array_b = prop_b->is_array;
342
343 if (is_array_a != is_array_b) {
344 /* Should probably never happen actually... */
346 return is_array_a ? 1 : -1;
347 }
348
349 /* Get the length of the array to work with. */
350 const uint len_a = prop_a->array_len;
351 const uint len_b = prop_b->array_len;
352
353 if (len_a != len_b) {
354 /* Do not handle override in that case,
355 * we do not support insertion/deletion from arrays for now. */
356 return len_a > len_b ? 1 : -1;
357 }
358
359 if (is_array_a && len_a == 0) {
360 /* Empty arrays, will happen in some case with dynamic ones. */
361 return 0;
362 }
363
364 RNAPropOverrideDiff override_diff = nullptr;
365 /* Special case for IDProps, we use default callback then. */
366 if (prop_a->is_idprop) {
368 if (!prop_b->is_idprop && prop_b->rnaprop->override_diff != override_diff) {
369 override_diff = nullptr;
370 }
371 }
372 else if (prop_b->is_idprop) {
374 if (prop_a->rnaprop->override_diff != override_diff) {
375 override_diff = nullptr;
376 }
377 }
378 else if (prop_a->rnaprop->override_diff == prop_b->rnaprop->override_diff) {
379 override_diff = prop_a->rnaprop->override_diff;
380 if (override_diff == nullptr) {
382 }
383 }
384
385 if (override_diff == nullptr) {
387 &LOG,
388 "'%s' gives unmatching or nullptr RNA diff callbacks, should not happen (%d vs. %d)",
389 rna_path ? rna_path : prop_a->identifier,
390 !prop_a->is_idprop,
391 !prop_b->is_idprop);
393 return 1;
394 }
395
396 eRNAOverrideMatch diff_flags = flags;
397 if (!RNA_property_overridable_get(prop_a->ptr, prop_a->rawprop) ||
399 !RNA_property_editable_flag(prop_a->ptr, prop_a->rawprop)))
400 {
401 diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
402 }
403
405 rnadiff_ctx.prop_a = prop_a;
406 rnadiff_ctx.prop_b = prop_b;
407 rnadiff_ctx.mode = mode;
408
409 rnadiff_ctx.liboverride = liboverride;
410 rnadiff_ctx.rna_path = rna_path;
411 rnadiff_ctx.rna_path_len = rna_path_len;
412 rnadiff_ctx.liboverride_flags = diff_flags;
413 override_diff(bmain, rnadiff_ctx);
414
415 if (r_report_flags) {
416 *r_report_flags = rnadiff_ctx.report_flag;
417 }
418 return rnadiff_ctx.comparison;
419}
420
421/* Modify local data-block to make it ready for override application
422 * (only needed for diff operations, where we use
423 * the local data-block's data as second operand). */
425 PointerRNA *ptr_local,
426 PointerRNA *ptr_reference,
427 PointerRNA *ptr_storage,
428 PropertyRNA *prop_local,
429 PropertyRNA *prop_reference,
430 PropertyRNA *prop_storage,
432{
433 int len_local, len_reference, len_storage = 0;
434 bool changed = false;
435
436 if (ptr_storage == nullptr) {
437 return changed;
438 }
439
440 /* get the length of the array to work with */
441 len_local = RNA_property_array_length(ptr_local, prop_local);
442 len_reference = RNA_property_array_length(ptr_reference, prop_reference);
443 if (prop_storage) {
444 len_storage = RNA_property_array_length(ptr_storage, prop_storage);
445 }
446
447 if (len_local != len_reference || len_local != len_storage) {
448 /* Do not handle override in that case,
449 * we do not support insertion/deletion from arrays for now. */
450 return changed;
451 }
452
453 RNAPropOverrideStore override_store = nullptr;
454 /* Special case for IDProps, we use default callback then. */
455 if (prop_local->magic != RNA_MAGIC) {
457 if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) {
458 override_store = nullptr;
459 }
460 }
461 else if (prop_reference->magic != RNA_MAGIC) {
463 if (prop_local->override_store != override_store) {
464 override_store = nullptr;
465 }
466 }
467 else if (prop_local->override_store == prop_reference->override_store) {
468 override_store = prop_local->override_store;
469 if (override_store == nullptr) {
471 }
472 }
473
474 if ((prop_storage->magic == RNA_MAGIC) &&
475 !ELEM(prop_storage->override_store, nullptr, override_store))
476 {
477 override_store = nullptr;
478 }
479
480 if (override_store == nullptr) {
482 &LOG,
483 "'%s' gives unmatching or nullptr RNA store callbacks, should not happen (%d vs. %d)",
484 op->rna_path,
485 prop_local->magic == RNA_MAGIC,
486 prop_reference->magic == RNA_MAGIC);
488 return changed;
489 }
490
492 /* Only needed for diff operations. */
493 if (!ELEM(
495 {
496 continue;
497 }
498
499 if (override_store(bmain,
500 ptr_local,
501 ptr_reference,
502 ptr_storage,
503 prop_local,
504 prop_reference,
505 prop_storage,
506 len_local,
507 len_reference,
508 len_storage,
509 opop))
510 {
511 changed = true;
512 }
513 }
514
515 return changed;
516}
517
520{
521 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
522 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
523 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
524 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
525 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
526 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
528
529 const short override_op = opop->operation;
530
532 opop, ptr_dst, ptr_src, ptr_storage, prop_dst, prop_src, prop_storage))
533 {
534 return false;
535 }
536
537 if (override_op == LIBOVERRIDE_OP_NOOP) {
538 return true;
539 }
540
541 RNAPropOverrideApply override_apply = nullptr;
542 /* Special case for IDProps, we use default callback then. */
543 if (prop_dst->magic != RNA_MAGIC) {
545 if (prop_src->magic == RNA_MAGIC && !ELEM(prop_src->override_apply, nullptr, override_apply)) {
546 override_apply = nullptr;
547 }
548 }
549 else if (prop_src->magic != RNA_MAGIC) {
551 if (!ELEM(prop_dst->override_apply, nullptr, override_apply)) {
552 override_apply = nullptr;
553 }
554 }
555 else if (prop_dst->override_apply == prop_src->override_apply) {
556 override_apply = prop_dst->override_apply;
557 if (override_apply == nullptr) {
559 }
560 }
561
562 if (prop_storage && prop_storage->magic == RNA_MAGIC &&
563 !ELEM(prop_storage->override_apply, nullptr, override_apply))
564 {
565 override_apply = nullptr;
566 }
567
568 if (override_apply == nullptr) {
570 &LOG,
571 "'%s' gives unmatching or nullptr RNA apply callbacks, should not happen (%d vs. %d)",
572 prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
573 prop_dst->magic == RNA_MAGIC,
574 prop_src->magic == RNA_MAGIC);
576 return false;
577 }
578
579 /* get the length of the array to work with */
580 rnaapply_ctx.len_dst = RNA_property_array_length(ptr_dst, prop_dst);
581 rnaapply_ctx.len_src = RNA_property_array_length(ptr_src, prop_src);
582 if (prop_storage) {
583 rnaapply_ctx.len_storage = RNA_property_array_length(ptr_storage, prop_storage);
584 }
585
586 if (rnaapply_ctx.len_dst != rnaapply_ctx.len_src ||
587 (prop_storage && rnaapply_ctx.len_dst != rnaapply_ctx.len_storage))
588 {
589 /* Do not handle override in that case,
590 * we do not support insertion/deletion from arrays for now. */
591 return false;
592 }
593
594 /* get and set the default values as appropriate for the various types */
595 const bool success = override_apply(bmain, rnaapply_ctx);
596 return success;
597}
598
600 PointerRNA *ptr_local,
601 PointerRNA *ptr_reference,
602 const char *root_path,
603 const size_t root_path_len,
604 IDOverrideLibrary *liboverride,
605 const eRNAOverrideMatch flags,
606 eRNAOverrideMatchResult *r_report_flags)
607{
609 PropertyRNA *iterprop;
610 bool matching = true;
611
612 BLI_assert(ptr_local->type == ptr_reference->type);
613 BLI_assert(ptr_local->owner_id && ptr_reference->owner_id);
614
615 const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
616 const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
617 const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
618 const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
619 const bool do_tag_for_restore = (flags & RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE) != 0;
620
621#ifdef DEBUG_OVERRIDE_TIMEIT
622 static float _sum_time_global = 0.0f;
623 static float _num_time_global = 0.0f;
624 double _timeit_time_global;
625 static float _sum_time_diffing = 0.0f;
626 static float _delta_time_diffing = 0.0f;
627 static int _num_delta_time_diffing = 0.0f;
628 static float _num_time_diffing = 0.0f;
629 double _timeit_time_diffing;
630
631 if (!root_path) {
632 _delta_time_diffing = 0.0f;
633 _num_delta_time_diffing = 0;
634 _timeit_time_global = BLI_time_now_seconds();
635 }
636#endif
637
638 if (ptr_local->owner_id == ptr_local->data && GS(ptr_local->owner_id->name) == ID_OB) {
639 /* Our beloved pose's bone cross-data pointers. Usually, depsgraph evaluation would
640 * ensure this is valid, but in some situations (like hidden collections etc.) this won't
641 * be the case, so we need to take care of this ourselves.
642 *
643 * NOTE: Typically callers of this function (from BKE_lib_override area) will already have
644 * ensured this. However, studio is still reporting sporadic, unreproducible crashes due to
645 * invalid pose data, so think there are still some cases where some armatures are somehow
646 * missing updates (possibly due to dependencies?). Since calling this function on same ID
647 * several time is almost free, and safe even in a threaded context as long as it has been done
648 * at least once first outside of threaded processing, we do it another time here. */
649 Object *ob_local = (Object *)ptr_local->owner_id;
650 if (ob_local->type == OB_ARMATURE) {
651 Object *ob_reference = (Object *)ptr_local->owner_id->override_library->reference;
652 BLI_assert(ob_local->data != nullptr);
653 BLI_assert(ob_reference->data != nullptr);
654 BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
655 BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
656 }
657 }
658
659 iterprop = RNA_struct_iterator_property(ptr_local->type);
660
661 for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
663 {
664 PropertyRNA *rawprop = static_cast<PropertyRNA *>(iter.ptr.data);
665
666 PropertyRNAOrID prop_local;
667 PropertyRNAOrID prop_reference;
668
669 rna_property_rna_or_id_get(rawprop, ptr_local, &prop_local);
670 rna_property_rna_or_id_get(rawprop, ptr_reference, &prop_reference);
671
672 BLI_assert(prop_local.rnaprop != nullptr);
673 BLI_assert(prop_local.rnaprop == prop_reference.rnaprop);
674 BLI_assert(prop_local.is_idprop == prop_reference.is_idprop);
675
676 if ((prop_local.is_idprop && prop_local.idprop == nullptr) ||
677 (prop_reference.is_idprop && prop_reference.idprop == nullptr))
678 {
679 continue;
680 }
681
682 if (ignore_non_overridable && !RNA_property_overridable_get(prop_local.ptr, rawprop)) {
683 continue;
684 }
685
686 if (!prop_local.is_idprop &&
688 {
689 continue;
690 }
691
692#if 0
693 /* This actually makes things slower, since it has to check for animation paths etc! */
694 if (RNA_property_animated(ptr_local, prop_local)) {
695 /* We cannot do anything here really, animation is some kind of dynamic overrides that has
696 * precedence over static one... */
697 continue;
698 }
699#endif
700
701#define RNA_PATH_BUFFSIZE 8192
702
703 std::optional<std::string> rna_path;
704 size_t rna_path_len = 0;
705
706 /* XXX TODO: this will have to be refined to handle collections insertions, and array items. */
707 if (root_path) {
708 BLI_assert(strlen(root_path) == root_path_len);
709
710 const char *prop_name = prop_local.identifier;
711 const size_t prop_name_len = strlen(prop_name);
712
713 char rna_path_buffer[RNA_PATH_BUFFSIZE];
714 char *rna_path_c = rna_path_buffer;
715
716 /* Inlined building (significantly more efficient). */
717 if (!prop_local.is_idprop) {
718 rna_path_len = root_path_len + 1 + prop_name_len;
719 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
720 rna_path = MEM_malloc_arrayN<char>(rna_path_len + 1, __func__);
721 }
722
723 memcpy(rna_path_c, root_path, root_path_len);
724 rna_path_c[root_path_len] = '.';
725 memcpy(rna_path_c + root_path_len + 1, prop_name, prop_name_len);
726 rna_path_c[rna_path_len] = '\0';
727 }
728 else {
729 rna_path_len = root_path_len + 2 + prop_name_len + 2;
730 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
731 rna_path_c = MEM_malloc_arrayN<char>(rna_path_len + 1, __func__);
732 }
733
734 memcpy(rna_path_c, root_path, root_path_len);
735 rna_path_c[root_path_len] = '[';
736 rna_path_c[root_path_len + 1] = '"';
737 memcpy(rna_path_c + root_path_len + 2, prop_name, prop_name_len);
738 rna_path_c[root_path_len + 2 + prop_name_len] = '"';
739 rna_path_c[root_path_len + 2 + prop_name_len + 1] = ']';
740 rna_path_c[rna_path_len] = '\0';
741 }
742
743 rna_path.emplace(rna_path_c);
744 }
745 else {
746 /* This is rather slow, but is not much called, so not really worth optimizing. */
747 rna_path = RNA_path_from_ID_to_property(ptr_local, rawprop);
748 if (rna_path) {
749 rna_path_len = rna_path->size();
750 }
751 }
752 if (!rna_path) {
753 continue;
754 }
755
756 CLOG_DEBUG(&LOG, "Override Checking %s", rna_path->c_str());
757
758 if (ignore_overridden) {
760 rna_path->c_str());
761 if (op != nullptr) {
763 continue;
764 }
765 }
766
767#ifdef DEBUG_OVERRIDE_TIMEIT
768 if (!root_path) {
769 _timeit_time_diffing = BLI_time_now_seconds();
770 }
771#endif
772
774 const int diff = rna_property_override_diff(bmain,
775 &prop_local,
776 &prop_reference,
777 rna_path->c_str(),
778 rna_path_len,
780 liboverride,
781 flags,
782 &report_flags);
783
784#ifdef DEBUG_OVERRIDE_TIMEIT
785 if (!root_path) {
786 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_diffing);
787 _delta_time_diffing += _delta_time;
788 _num_delta_time_diffing++;
789 }
790#endif
791
792 matching = matching && diff == 0;
793 if (r_report_flags) {
794 *r_report_flags = (*r_report_flags | report_flags);
795 }
796
797 if (diff != 0) {
798 /* XXX TODO: refine this for per-item overriding of arrays... */
800 rna_path->c_str());
802 op ? op->operations.first : nullptr);
803
804 if (op != nullptr) {
805 /* Only set all operations from this property as used (via
806 * #BKE_lib_override_library_operations_tag) if the property itself is still tagged as
807 * unused.
808 *
809 * In case the property itself is already tagged as used, in means lower-level diffing code
810 * took care of this property (e.g. as is needed collections of items, since then some
811 * operations may be valid, while others may need to be purged). */
814 }
815 }
816
817 if ((do_restore || do_tag_for_restore) &&
818 (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0)
819 {
820 /* We are allowed to restore to reference's values. */
821 if (ELEM(nullptr, op, opop) || opop->operation == LIBOVERRIDE_OP_NOOP) {
822 if (RNA_property_editable(ptr_local, rawprop)) {
823 /* This property should be restored to its reference value. This should not be done
824 * here, since this code may be called from non-main thread (modifying data through RNA
825 * is not thread safe). */
826 if (do_restore) {
829 opop_tmp.subitem_reference_index = -1;
830 opop_tmp.subitem_local_index = -1;
831
833 rnaapply_ctx.ptr_dst = *ptr_local;
834 rnaapply_ctx.ptr_src = *ptr_reference;
835 rnaapply_ctx.prop_dst = rawprop;
836 rnaapply_ctx.prop_src = rawprop;
837 rnaapply_ctx.liboverride_operation = &opop_tmp;
838
839 const bool is_restored = rna_property_override_operation_apply(bmain, rnaapply_ctx);
840
841 if (is_restored) {
843 "Restoreed forbidden liboverride `%s` for override data '%s'",
844 rna_path->c_str(),
845 ptr_local->owner_id->name);
846 if (r_report_flags) {
847 *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
848 }
849 }
850 else {
852 "Failed to restore forbidden liboverride `%s` for override data '%s'",
853 rna_path->c_str(),
854 ptr_local->owner_id->name);
855 }
856 }
857 else {
858 if (op == nullptr) {
859 /* An override property is needed, create a temp one if necessary. */
861 liboverride, rna_path->c_str(), nullptr);
863 }
867 nullptr,
868 nullptr,
869 {},
870 {},
871 -1,
872 -1,
873 false,
874 nullptr,
875 nullptr);
876 /* Do not use `BKE_lib_override_library_operations_tag` here, as the property may be
877 * a valid one that has other operations that needs to remain (e.g. from a template,
878 * a NOOP operation to enforce no change on that property, etc.). */
880 opop_restore->tag |= LIBOVERRIDE_PROP_TAG_NEEDS_RETORE;
882
884 &LOG,
885 "Tagging for restoration forbidden liboverride `%s` for override data '%s'",
886 rna_path->c_str(),
887 ptr_local->owner_id->name);
888 if (r_report_flags) {
890 }
891 }
892 }
893 else {
894 /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
895#if 0
897 "We have differences between reference and "
898 "overriding data on non-editable property.");
899#endif
900 matching = false;
901 }
902 }
903 }
904 else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(nullptr, op, opop))
905 {
906 /* This property is not overridden, and differs from reference, so we have no match. */
907 matching = false;
908 if (!(do_create || do_restore || do_tag_for_restore)) {
909
910 break;
911 }
912 }
913 }
914#undef RNA_PATH_BUFFSIZE
915 }
917
918#ifdef DEBUG_OVERRIDE_TIMEIT
919 if (!root_path) {
920 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_global);
921 _sum_time_global += _delta_time;
922 _num_time_global++;
923 _sum_time_diffing += _delta_time_diffing;
924 _num_time_diffing++;
925 printf("ID: %s\n", ((ID *)ptr_local->owner_id)->name);
926 printf("time end (%s): %.6f\n", __func__, _delta_time);
927 printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
928 __func__,
929 (_sum_time_global / _num_time_global),
930 _sum_time_global,
931 int(_num_time_global));
932 printf("diffing time end (%s): %.6f (in %d runs)\n",
933 __func__,
934 _delta_time_diffing,
935 _num_delta_time_diffing);
936 printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
937 __func__,
938 (_sum_time_diffing / _num_time_diffing),
939 _sum_time_diffing,
940 int(_num_time_diffing));
941 }
942#endif
943
944 return matching;
945}
946
948 PointerRNA *ptr_local,
949 PointerRNA *ptr_reference,
950 PointerRNA *ptr_storage,
951 IDOverrideLibrary *liboverride)
952{
953 bool changed = false;
954
955#ifdef DEBUG_OVERRIDE_TIMEIT
957#endif
959 /* Simplified for now! */
960 PointerRNA data_reference, data_local;
961 PropertyRNA *prop_reference, *prop_local;
962
963 if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
964 RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
965 {
966 PointerRNA data_storage;
967 PropertyRNA *prop_storage = nullptr;
968
969 /* It is totally OK if this does not success,
970 * only a subset of override operations actually need storage. */
971 if (ptr_storage && (ptr_storage->owner_id != nullptr)) {
972 RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
973 }
974
976 &data_local,
977 &data_reference,
978 &data_storage,
979 prop_reference,
980 prop_local,
981 prop_storage,
982 op))
983 {
984 changed = true;
985 }
986 }
987 }
988#ifdef DEBUG_OVERRIDE_TIMEIT
990#endif
991
992 return changed;
993}
994
996 const char *item_name,
997 const int item_name_len,
998 const bool do_id_pointer,
999 const std::optional<ID *> &item_id,
1000 PointerRNA *ptr_item_name)
1001{
1002 BLI_assert(!do_id_pointer || RNA_struct_is_ID(ptr_item_name->type));
1003
1004 bool is_match = false;
1005
1006 if (do_id_pointer) {
1007 if (*item_id != static_cast<ID *>(ptr_item_name->data)) {
1008 /* If the ID pointer does not match, then there is no match, no need to check the
1009 * name itself. */
1010 return is_match;
1011 }
1012 }
1013
1014 PropertyRNA *nameprop = ptr_item_name->type->nameproperty;
1015 char name_buf[256];
1016 char *name;
1017 int namelen;
1018
1020 ptr_item_name, nameprop, name_buf, sizeof(name_buf), &namelen);
1021
1022 is_match = ((item_name_len == namelen) && STREQ(item_name, name));
1023
1024 if (UNLIKELY(name != name_buf)) {
1025 MEM_freeN(name);
1026 }
1027
1028 return is_match;
1029}
1030
1032 PointerRNA *ptr,
1033 PropertyRNA *prop,
1034 const char *item_name,
1035 const int item_name_len,
1036 const bool do_id_pointer,
1037 const std::optional<ID *> &item_id,
1038 PointerRNA *r_ptr_item_name)
1039{
1040 /* NOTE: This code is very similar to the one from #RNA_property_collection_lookup_string_index,
1041 * but it adds an extra early check on matching ID pointer.
1042 *
1043 * This custom code is needed because otherwise, it is only possible to check the first
1044 * name-matched item found by #RNA_property_collection_lookup_string, and not potential other
1045 * items having the same name. */
1046 if (do_id_pointer) {
1048
1049 /* We cannot use a potential `CollectionPropertyRNA->lookupstring` here. */
1051
1052 RNA_property_collection_begin(ptr, prop, &iter);
1053 for (; iter.valid; RNA_property_collection_next(&iter)) {
1054 if (iter.ptr.data && iter.ptr.type->nameproperty) {
1056 item_name, item_name_len, do_id_pointer, item_id, &iter.ptr))
1057 {
1058 *r_ptr_item_name = iter.ptr;
1059 break;
1060 }
1061 }
1062 }
1064
1065 if (!iter.valid) {
1066 *r_ptr_item_name = {};
1067 }
1068
1069 return iter.valid;
1070 }
1071
1072 return RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name);
1073}
1074
1076 PointerRNA *ptr,
1077 PropertyRNA *prop,
1078 const char *item_name,
1079 const std::optional<ID *> &item_id,
1080 const int item_index,
1081 /* Never use index-only lookup to validate a match (unless no item name (+ id) was given). */
1082 const bool ignore_index_only_lookup,
1083 PointerRNA *r_ptr_item_name,
1084 PointerRNA *r_ptr_item_index)
1085{
1086 r_ptr_item_name->invalidate();
1087 r_ptr_item_index->invalidate();
1088
1089 const bool do_id_pointer = item_id && RNA_struct_is_ID(RNA_property_pointer_type(ptr, prop));
1090
1091 const int item_name_len = item_name ? int(strlen(item_name)) : 0;
1092
1093 /* First, lookup by index, but only validate if name also matches (or if there is no given name).
1094 *
1095 * Note that this is also beneficial on performances (when looking up in big collections), since
1096 * typically index lookup will be faster than name lookup.
1097 */
1098 if (item_index != -1) {
1099 if (RNA_property_collection_lookup_int(ptr, prop, item_index, r_ptr_item_index)) {
1100 if (item_name && r_ptr_item_index->type) {
1102 item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_index))
1103 {
1104 *r_ptr_item_name = *r_ptr_item_index;
1105 return;
1106 }
1107 }
1108 }
1109 }
1110
1111 if (!item_name) {
1112 return;
1113 }
1114
1115 /* If index + name (+ id) lookup failed, do not keep result of index-only lookup. That means that
1116 * if the name (+ id) only lookup fails, no matching item was found, even if index-only would
1117 * have matched. */
1118 if (ignore_index_only_lookup) {
1119 r_ptr_item_index->invalidate();
1120 }
1121
1122 /* Then, lookup by name (+ id) only. */
1124 ptr, prop, item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_name))
1125 {
1126 r_ptr_item_index->invalidate();
1127 return;
1128 }
1129
1130 /* If name (+ id) lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was
1131 * successful it will be the only valid return value. */
1132}
1133
1135 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1136{
1137 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
1138 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
1139 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
1140 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
1141 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
1142 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
1143 PointerRNA *ptr_item_dst = &rnaapply_ctx.ptr_item_dst;
1144 PointerRNA *ptr_item_src = &rnaapply_ctx.ptr_item_src;
1145 PointerRNA *ptr_item_storage = &rnaapply_ctx.ptr_item_storage;
1148
1149 if ((RNA_property_type(prop_dst) != PROP_COLLECTION ||
1150 RNA_property_type(prop_src) != PROP_COLLECTION ||
1151 (prop_storage != nullptr && RNA_property_type(prop_storage) != PROP_COLLECTION)) ||
1152 (opop->subitem_local_name == nullptr && opop->subitem_reference_name == nullptr &&
1153 opop->subitem_local_index == -1 && opop->subitem_reference_index == -1))
1154 {
1155 return;
1156 }
1157
1158 const bool use_id_pointer = (opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID) != 0;
1159 std::optional<ID *> subitem_local_id = use_id_pointer ? std::optional(opop->subitem_local_id) :
1160 std::nullopt;
1161 std::optional<ID *> subitem_reference_id = use_id_pointer ?
1162 std::optional(opop->subitem_reference_id) :
1163 std::nullopt;
1164
1165 ptr_item_dst->invalidate();
1166 ptr_item_src->invalidate();
1167 if (prop_storage != nullptr) {
1168 ptr_item_storage->invalidate();
1169 }
1170
1171 /* If there is an item ID, there should _always_ be a valid item name too. */
1172 BLI_assert(opop->subitem_local_name || !subitem_local_id);
1173 BLI_assert(opop->subitem_reference_name || !subitem_reference_id);
1174 /* Do not match by index only, if there are valid item names and ID.
1175 *
1176 * Otherwise, it can end up 'matching by index' e.g. collection childrens, re-assigning
1177 * completely wrong collections only based on indices. This is especially bad when some
1178 * collections are _removed_ from the reference collection's children. */
1179 const bool ignore_index_only_lookup = (subitem_local_id || subitem_reference_id);
1180
1181 PointerRNA ptr_item_dst_name, ptr_item_dst_index;
1182 PointerRNA ptr_item_src_name, ptr_item_src_index;
1183 PointerRNA ptr_item_storage_name, ptr_item_storage_index;
1185 prop_src,
1186 opop->subitem_local_name,
1187 subitem_local_id,
1188 opop->subitem_local_index,
1189 ignore_index_only_lookup,
1190 &ptr_item_src_name,
1191 &ptr_item_src_index);
1193 prop_dst,
1195 subitem_reference_id,
1197 ignore_index_only_lookup,
1198 &ptr_item_dst_name,
1199 &ptr_item_dst_index);
1200 /* This is rather fragile, but the fact that local override IDs may have a different name
1201 * than their linked reference makes it necessary.
1202 * Basically, here we are considering that if we cannot find the original linked ID in
1203 * the local override we are (re-)applying the operations, then it may be because some of
1204 * those operations have already been applied, and we may already have the local ID
1205 * pointer we want to set.
1206 * This happens e.g. during re-sync of an override, since we have already remapped all ID
1207 * pointers to their expected values.
1208 * In that case we simply try to get the property from the local expected name. */
1209 if (opop->subitem_reference_name != nullptr && opop->subitem_local_name != nullptr &&
1210 ptr_item_dst_name.type == nullptr)
1211 {
1213 ptr_dst,
1214 prop_dst,
1215 opop->subitem_local_name,
1216 {},
1218 opop->subitem_local_index,
1219 ignore_index_only_lookup,
1220 &ptr_item_dst_name,
1221 &ptr_item_dst_index);
1222 }
1223
1224 /* For historical compatibility reasons, we fallback to reference if no local item info is given,
1225 * and vice-versa. */
1226 if (opop->subitem_reference_name == nullptr && opop->subitem_local_name != nullptr) {
1228 ptr_dst,
1229 prop_dst,
1230 opop->subitem_local_name,
1231 {},
1233 opop->subitem_local_index,
1234 ignore_index_only_lookup,
1235 &ptr_item_dst_name,
1236 &ptr_item_dst_index);
1237 }
1238 else if (opop->subitem_reference_name != nullptr && opop->subitem_local_name == nullptr) {
1240 prop_src,
1242 {},
1243 opop->subitem_local_index != -1 ?
1244 opop->subitem_local_index :
1246 ignore_index_only_lookup,
1247 &ptr_item_src_name,
1248 &ptr_item_src_index);
1249 }
1250 if (opop->subitem_reference_index == -1 && opop->subitem_local_index != -1) {
1252 prop_dst,
1253 nullptr,
1254 {},
1255 opop->subitem_local_index,
1256 ignore_index_only_lookup,
1257 &ptr_item_dst_name,
1258 &ptr_item_dst_index);
1259 }
1260 else if (opop->subitem_reference_index != -1 && opop->subitem_local_index == -1) {
1262 prop_src,
1263 nullptr,
1264 {},
1266 ignore_index_only_lookup,
1267 &ptr_item_src_name,
1268 &ptr_item_src_index);
1269 }
1270
1271 /* For storage, simply lookup by name first, and fallback to indices. */
1272 if (prop_storage != nullptr) {
1274 prop_storage,
1275 opop->subitem_local_name,
1276 subitem_local_id,
1277 opop->subitem_local_index,
1278 ignore_index_only_lookup,
1279 &ptr_item_storage_name,
1280 &ptr_item_storage_index);
1281 if (ptr_item_storage_name.data == nullptr) {
1283 prop_storage,
1285 subitem_reference_id,
1287 ignore_index_only_lookup,
1288 &ptr_item_storage_name,
1289 &ptr_item_storage_index);
1290 }
1291 if (ptr_item_storage_name.data == nullptr && ptr_item_storage_index.data == nullptr) {
1293 prop_storage,
1294 nullptr,
1295 {},
1296 opop->subitem_local_index,
1297 ignore_index_only_lookup,
1298 &ptr_item_storage_name,
1299 &ptr_item_storage_index);
1300 }
1301 }
1302
1303 /* Final selection. Both matches have to be based on names, or indices, but not a mix of both.
1304 * If we are missing either source or destination data based on names, and based on indices, then
1305 * use partial data from names (allows to handle 'need resync' detection cases). */
1306 if ((ptr_item_src_name.type || ptr_item_dst_name.type) &&
1307 !(ptr_item_src_index.type && ptr_item_dst_index.type))
1308 {
1309 *ptr_item_src = ptr_item_src_name;
1310 *ptr_item_dst = ptr_item_dst_name;
1311 if (prop_storage != nullptr) {
1312 *ptr_item_storage = ptr_item_storage_name;
1313 }
1314 }
1315 else if (ptr_item_src_index.type != nullptr || ptr_item_dst_index.type != nullptr) {
1316 *ptr_item_src = ptr_item_src_index;
1317 *ptr_item_dst = ptr_item_dst_index;
1318 if (prop_storage != nullptr) {
1319 *ptr_item_storage = ptr_item_storage_index;
1320 }
1321 }
1322
1323 /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
1324 * and index are invalid. This can often happen when inserting new items (constraint,
1325 * modifier...) in a collection that supports it. */
1326 if (ptr_item_dst->type == nullptr &&
1327 ((opop->subitem_reference_name != nullptr && opop->subitem_reference_name[0] != '\0') ||
1328 opop->subitem_reference_index != -1))
1329 {
1330 CLOG_DEBUG(&LOG,
1331 "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
1332 opop->subitem_reference_name != nullptr ? opop->subitem_reference_name : "",
1334 op->rna_path,
1335 ptr_dst->owner_id->name);
1336 }
1337 if (ptr_item_src->type == nullptr &&
1338 ((opop->subitem_local_name != nullptr && opop->subitem_local_name[0] != '\0') ||
1339 opop->subitem_local_index != -1))
1340 {
1341 CLOG_DEBUG(&LOG,
1342 "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
1343 opop->subitem_local_name != nullptr ? opop->subitem_local_name : "",
1344 opop->subitem_local_index,
1345 op->rna_path,
1346 ptr_src->owner_id->name);
1347 }
1348}
1349
1351 PointerRNA *ptr_dst,
1352 PointerRNA *ptr_src,
1353 PointerRNA *ptr_item_dst,
1354 PointerRNA *ptr_item_src)
1355{
1357 bmain, ptr_src, nullptr, nullptr);
1359 bmain, ptr_dst, nullptr, nullptr);
1360 ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, nullptr, nullptr);
1361 ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, nullptr, nullptr);
1362
1364
1365 /* If the owner ID is not part of an override hierarchy, there is no possible resync. */
1367 return;
1368 }
1369
1370 /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
1371 * here. */
1372 if (id_src != nullptr && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
1373 return;
1374 }
1375
1376 if (/* We might be in a case where id_dst has already been processed and its usages
1377 * remapped to its new local override. In that case overrides and linked data
1378 * are always properly matching. */
1379 id_src != id_dst &&
1380 /* If one of the pointers is nullptr and not the other, we are in a non-matching case. */
1381 (ELEM(nullptr, id_src, id_dst) ||
1382 /* If `id_dst` is not from same lib as id_src, and linked reference ID of `id_src` is not
1383 * `id_dst`, we are in a non-matching case. */
1384 (id_dst->lib != id_src->lib && id_src->override_library->reference != id_dst) ||
1385 /* If `id_dst` is from same lib as id_src, and is not same as `id_owner`, we are in a
1386 * non-matching case.
1387 *
1388 * NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new
1389 * override copy generated by `BKE_lib_override_library_update` will already have its
1390 * self-references updated to itself, instead of still pointing to its linked source. */
1391 (id_dst->lib == id_src->lib && id_dst != id_owner_dst)))
1392 {
1393 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1394 if (ID_IS_LINKED(id_owner_src)) {
1395 id_owner_src->lib->runtime->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1396 }
1397 CLOG_DEBUG(&LOG,
1398 "Local override %s detected as needing resync due to mismatch in its used IDs",
1399 id_owner_dst->name);
1400 }
1401 if ((id_owner_src->override_library->reference->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) != 0) {
1402 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1403 if (ID_IS_LINKED(id_owner_src)) {
1404 id_owner_src->lib->runtime->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1405 }
1406 CLOG_DEBUG(&LOG,
1407 "Local override %s detected as needing resync as its liboverride reference is "
1408 "already tagged for resync",
1409 id_owner_dst->name);
1410 }
1411}
1412
1414 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1415{
1417 const bool do_insert = rnaapply_ctx.do_insert;
1418
1420 if (opop->operation == LIBOVERRIDE_OP_NOOP) {
1421 continue;
1422 }
1423
1424 if (!do_insert !=
1426 {
1427 if (!do_insert) {
1428 CLOG_DEBUG(&LOG, "Skipping insert override operations in first pass (%s)", op->rna_path);
1429 }
1430 continue;
1431 }
1432
1433 rnaapply_ctx.liboverride_operation = opop;
1434
1436
1437 if (!rna_property_override_operation_apply(bmain, rnaapply_ctx)) {
1438 CLOG_DEBUG(&LOG,
1439 "Failed to apply '%s' override operation on %s\n",
1440 op->rna_path,
1441 rnaapply_ctx.ptr_src.owner_id->name);
1442 }
1443 }
1444
1445 rnaapply_ctx.liboverride_operation = nullptr;
1446}
1447
1453 PointerRNA *id_ptr_dst,
1454 PointerRNA *id_ptr_src,
1455 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1456{
1457 UNUSED_VARS_NDEBUG(bmain, id_ptr_src);
1458
1459 if ((rnaapply_ctx.flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) == 0) {
1460 return false;
1461 }
1462
1463 if (!RNA_struct_is_ID(RNA_property_pointer_type(&rnaapply_ctx.ptr_dst, rnaapply_ctx.prop_dst))) {
1465 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1466 return false;
1467 }
1468
1470
1471 /* IDProperties case. */
1472 if (rnaapply_ctx.prop_dst->magic != RNA_MAGIC) {
1473 CLOG_DEBUG(&LOG,
1474 "%s: Ignoring local override on ID pointer custom property '%s', as requested by "
1475 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1476 id_ptr_dst->owner_id->name,
1477 op->rna_path);
1478 return true;
1479 }
1480
1481 switch (op->rna_prop_type) {
1482 case PROP_POINTER: {
1483 if ((static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1485 {
1487 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1489 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1490
1491 CLOG_DEBUG(&LOG,
1492 "%s: Ignoring local override on ID pointer property '%s', as requested by "
1493 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1494 id_ptr_dst->owner_id->name,
1495 op->rna_path);
1496 return true;
1497 }
1498 break;
1499 }
1500 case PROP_COLLECTION: {
1501 /* For collections of ID pointers just completely skip the override ops here... A tad brutal,
1502 * but this is a backup 'fix the mess' tool, and in practice this should never be an issue.
1503 * Can always be refined later if needed. */
1504 CLOG_DEBUG(&LOG,
1505 "%s: Ignoring all local override on ID pointer collection property '%s', as "
1506 "requested by RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1507 id_ptr_dst->owner_id->name,
1508 op->rna_path);
1509 return true;
1510 }
1511 default:
1512 break;
1513 }
1514
1515 return false;
1516}
1517
1519 PointerRNA *id_ptr_dst,
1520 PointerRNA *id_ptr_src,
1521 PointerRNA *id_ptr_storage,
1522 IDOverrideLibrary *liboverride,
1524{
1525#ifdef DEBUG_OVERRIDE_TIMEIT
1527#endif
1528 const bool do_restore_only = (flag & RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY) != 0;
1529 /* NOTE: Applying insert operations in a separate pass is mandatory.
1530 * We could optimize this later, but for now, as inefficient as it is,
1531 * don't think this is a critical point.
1532 */
1533 bool do_insert = false;
1534 for (int i = 0; i < (do_restore_only ? 1 : 2); i++, do_insert = true) {
1536 if (do_restore_only && (op->tag % LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0) {
1537 continue;
1538 }
1539 /* That tag should only exist for short lifespan when restoring values from reference linked
1540 * data. */
1541 BLI_assert((op->tag & LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0 || do_restore_only);
1542
1544 rnaapply_ctx.flag = flag;
1545 rnaapply_ctx.do_insert = do_insert;
1546
1547 rnaapply_ctx.liboverride = liboverride;
1548 rnaapply_ctx.liboverride_property = op;
1549
1551 op->rna_path,
1552 &rnaapply_ctx.ptr_dst,
1553 &rnaapply_ctx.prop_dst,
1554 &rnaapply_ctx.ptr_item_dst) &&
1556 op->rna_path,
1557 &rnaapply_ctx.ptr_src,
1558 &rnaapply_ctx.prop_src,
1559 &rnaapply_ctx.ptr_item_src)))
1560 {
1561 CLOG_DEBUG(&LOG,
1562 "Failed to apply library override operation to '%s.%s' "
1563 "(could not resolve some properties, local: %d, override: %d)",
1564 static_cast<ID *>(id_ptr_src->owner_id)->name,
1565 op->rna_path,
1567 id_ptr_dst, op->rna_path, &rnaapply_ctx.ptr_dst, &rnaapply_ctx.prop_dst),
1569 id_ptr_src, op->rna_path, &rnaapply_ctx.ptr_src, &rnaapply_ctx.prop_src));
1570 continue;
1571 }
1572
1573 /* It is totally OK if this does not success,
1574 * only a subset of override operations actually need storage. */
1575 if (id_ptr_storage && (id_ptr_storage->owner_id != nullptr)) {
1577 op->rna_path,
1578 &rnaapply_ctx.ptr_storage,
1579 &rnaapply_ctx.prop_storage,
1580 &rnaapply_ctx.ptr_item_storage);
1581 }
1582
1583 /* Check if an overridden ID pointer supposed to be in sync with linked data gets out of
1584 * sync. */
1586 (id_ptr_dst->owner_id->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) == 0)
1587 {
1588 if (op->rna_prop_type == PROP_POINTER && op->operations.first != nullptr &&
1589 (static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1591 {
1593 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1595 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1597 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1598
1599 PointerRNA prop_ptr_src = RNA_property_pointer_get(&rnaapply_ctx.ptr_src,
1600 rnaapply_ctx.prop_src);
1601 PointerRNA prop_ptr_dst = RNA_property_pointer_get(&rnaapply_ctx.ptr_dst,
1602 rnaapply_ctx.prop_dst);
1604 bmain, id_ptr_dst, id_ptr_src, &prop_ptr_dst, &prop_ptr_src);
1605 }
1606 else if (op->rna_prop_type == PROP_COLLECTION) {
1607 if (RNA_struct_is_ID(
1608 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)))
1609 {
1610 BLI_assert(id_ptr_src->owner_id ==
1612 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1613 BLI_assert(id_ptr_dst->owner_id ==
1615 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1616
1617 LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
1618 if ((opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
1619 continue;
1620 }
1621 rnaapply_ctx.liboverride_operation = opop;
1622
1624
1626 id_ptr_dst,
1627 id_ptr_src,
1628 &rnaapply_ctx.ptr_item_dst,
1629 &rnaapply_ctx.ptr_item_src);
1630 }
1631 rnaapply_ctx.liboverride_operation = nullptr;
1632 }
1633 }
1634 }
1635
1636 if (override_apply_property_check_skip(bmain, id_ptr_dst, id_ptr_src, rnaapply_ctx)) {
1637 continue;
1638 }
1639
1640 rna_property_override_apply_ex(bmain, rnaapply_ctx);
1641 }
1642 }
1643
1644 /* Some cases (like point caches) may require additional post-processing. */
1645 if (RNA_struct_is_a(id_ptr_dst->type, &RNA_ID)) {
1646 ID *id_dst = static_cast<ID *>(id_ptr_dst->data);
1647 ID *id_src = static_cast<ID *>(id_ptr_src->data);
1648 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id_dst);
1649 if (id_type->lib_override_apply_post != nullptr) {
1650 id_type->lib_override_apply_post(id_dst, id_src);
1651 }
1652 }
1653
1654#ifdef DEBUG_OVERRIDE_TIMEIT
1656#endif
1657}
1658
1660 PointerRNA *ptr,
1661 PropertyRNA *prop,
1662 ID **r_owner_id)
1663{
1664 std::optional<std::string> rna_path;
1665
1666 *r_owner_id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1667 if (rna_path) {
1669 (*r_owner_id)->override_library, rna_path->c_str());
1670 return op;
1671 }
1672 return nullptr;
1673}
1674
1676 PointerRNA *ptr,
1677 PropertyRNA *prop,
1678 bool *r_created)
1679{
1680 std::optional<std::string> rna_path;
1681
1682 if (r_created != nullptr) {
1683 *r_created = false;
1684 }
1685
1686 ID *id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1687 if (rna_path) {
1689 id->override_library, rna_path->c_str(), r_created);
1690 return op;
1691 }
1692 return nullptr;
1693}
1694
1696 Main *bmain,
1697 PointerRNA *ptr,
1698 PropertyRNA *prop,
1699 const int index,
1700 const bool strict,
1701 bool *r_strict)
1702{
1703 ID *owner_id;
1705
1706 if (!op) {
1707 return nullptr;
1708 }
1709
1711 op, nullptr, nullptr, {}, {}, index, index, strict, r_strict);
1712}
1713
1715 Main *bmain,
1716 PointerRNA *ptr,
1717 PropertyRNA *prop,
1718 const short operation,
1719 const int index,
1720 const bool strict,
1721 bool *r_strict,
1722 bool *r_created)
1723{
1724 if (r_created != nullptr) {
1725 *r_created = false;
1726 }
1727
1729
1730 if (!op) {
1731 return nullptr;
1732 }
1733
1735 op, operation, nullptr, nullptr, {}, {}, index, index, strict, r_strict, r_created);
1736}
1737
1739 PointerRNA *ptr,
1740 PropertyRNA *prop,
1741 const int index)
1742{
1743 eRNAOverrideStatus override_status = eRNAOverrideStatus(0);
1744
1745 if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) {
1746 return override_status;
1747 }
1748
1750 override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
1751 }
1752
1754 bmain, ptr, prop, index, false, nullptr);
1755 if (opop != nullptr) {
1756 override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
1757 if (opop->flag & LIBOVERRIDE_OP_FLAG_MANDATORY) {
1758 override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
1759 }
1760 if (opop->flag & LIBOVERRIDE_OP_FLAG_LOCKED) {
1761 override_status |= RNA_OVERRIDE_STATUS_LOCKED;
1762 }
1763 }
1764
1765 return override_status;
1766}
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:146
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:113
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:188
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
ID and Library types, which are fundamental for SDNA.
@ ID_TAG_LIBOVERRIDE_NEED_RESYNC
Definition DNA_ID.h:906
@ LIBOVERRIDE_TAG_NEEDS_RESTORE
Definition DNA_ID.h:316
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
@ LIBOVERRIDE_OP_FLAG_MANDATORY
Definition DNA_ID.h:248
@ LIBOVERRIDE_OP_FLAG_LOCKED
Definition DNA_ID.h:250
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID
Definition DNA_ID.h:262
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE
Definition DNA_ID.h:256
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ LIBOVERRIDE_PROP_TAG_NEEDS_RETORE
Definition DNA_ID.h:297
@ LIBOVERRIDE_PROP_OP_TAG_UNUSED
Definition DNA_ID.h:294
@ LIBOVERRIDE_OP_NOOP
Definition DNA_ID.h:228
@ LIBOVERRIDE_OP_ADD
Definition DNA_ID.h:233
@ LIBOVERRIDE_OP_SUBTRACT
Definition DNA_ID.h:235
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:230
@ LIBOVERRIDE_OP_MULTIPLY
Definition DNA_ID.h:237
@ LIBOVERRIDE_OP_INSERT_BEFORE
Definition DNA_ID.h:241
@ LIBOVERRIDE_OP_INSERT_AFTER
Definition DNA_ID.h:240
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:358
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:785
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:774
@ 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:167
@ PROP_COLLECTION
Definition RNA_types.hh:168
@ PROPOVERRIDE_OVERRIDABLE_LIBRARY
Definition RNA_types.hh:503
@ PROPOVERRIDE_NO_COMPARISON
Definition RNA_types.hh:511
@ PROPOVERRIDE_IGNORE
Definition RNA_types.hh:523
nullptr float
#define GS(x)
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
#define printf(...)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
#define LOG(level)
Definition log.h:97
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
const char * name
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)
bool RNA_pointer_is_null(const PointerRNA *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 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)
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, const bool ignore_index_only_lookup, PointerRNA *r_ptr_item_name, PointerRNA *r_ptr_item_index)
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:288
ListBase properties
Definition DNA_ID.h:336
unsigned int flag
Definition DNA_ID.h:348
struct ID * reference
Definition DNA_ID.h:334
IDOverrideLibraryRuntime * runtime
Definition DNA_ID.h:346
short flag
Definition DNA_ID.h:163
IDTypeLibOverrideApplyPost lib_override_apply_post
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
short flag
Definition DNA_ID.h:438
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:579
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:4238
uint8_t flag
Definition wm_window.cc:145