diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.hh b/source/blender/blenkernel/BKE_blendfile_link_append.hh index b56d17b77d2..2538a907af4 100644 --- a/source/blender/blenkernel/BKE_blendfile_link_append.hh +++ b/source/blender/blenkernel/BKE_blendfile_link_append.hh @@ -7,16 +7,169 @@ * \ingroup bke */ +#include +#include + +#include "BLI_bit_vector.hh" #include "BLI_function_ref.hh" +#include "BLI_map.hh" + +#include "BLO_readfile.hh" struct BlendHandle; struct ID; struct Library; struct LibraryLink_Params; +struct MainLibraryWeakReferenceMap; struct ReportList; +/* TODO: Rename file to `BKE_blendfile_import.hh`. */ +/* TODO: Replace `BlendfileLinkAppend` prefix by `blender::bke::blendfile::import` namespace. */ +/* TODO: Move these enums to scoped enum classes. */ + +/** Actions to apply to an item (i.e. linked ID). */ +enum { + LINK_APPEND_ACT_UNSET = 0, + LINK_APPEND_ACT_KEEP_LINKED, + LINK_APPEND_ACT_REUSE_LOCAL, + LINK_APPEND_ACT_MAKE_LOCAL, + LINK_APPEND_ACT_COPY_LOCAL, +}; + +/** Various status info about an item (i.e. linked ID). */ +enum { + /** An indirectly linked ID. */ + LINK_APPEND_TAG_INDIRECT = 1 << 0, + /** + * An ID also used as liboverride dependency (either directly, as a liboverride reference, or + * indirectly, as data used by a liboverride reference). It should never be directly made local. + * + * Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY. + */ + LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY = 1 << 1, + /** + * An ID only used as liboverride dependency (either directly or indirectly, see + * #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY for precisions). It should not be considered during + * the 'make local' process, and remain purely linked data. + * + * Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY. + */ + LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY = 1 << 2, +}; + +/* NOTE: These three structs are currently exposed in header to allow for their usage in RNA. + * Regualr C++ code should not access their content directly. + * + * TODO: Refactor these three structs into classes, and integrated the whole API into them. */ struct BlendfileLinkAppendContext; -struct BlendfileLinkAppendContextItem; + +/** A data-block (ID) entry in the `items` list from #BlendfileLinkAppendContext. */ +struct BlendfileLinkAppendContextItem { + /** + * Link/Append context owner of this item. Used in RNA API, could be removed once RNA paths are + * functional. + */ + BlendfileLinkAppendContext *lapp_context; + + /** Name of the ID (without the heading two-chars IDcode). */ + std::string name; + /** All libraries (from #BlendfileLinkAppendContext.libraries) to try to load this ID from. */ + blender::BitVector<> libraries; + /** ID type. */ + short idcode; + + /** Type of action to perform on this item, and general status tag information. + * NOTE: Mostly used by append post-linking processing. */ + char action; + char tag; + + /** Newly linked ID (nullptr until it has been successfully linked). */ + ID *new_id; + /** Library ID from which the #new_id has been linked (nullptr until it has been successfully + * linked). */ + Library *source_library; + /** Liboverride of the linked ID (nullptr until it has been successfully created or an existing + * one has been found). */ + ID *liboverride_id; + /** + * Whether the item has a matching local ID that was already appended from the same source + * before, and has not been modified. In 'Append & Reuse' case, this local ID _may_ be reused + * instead of making linked data local again. + */ + ID *reusable_local_id; + + /** Opaque user data pointer. */ + void *userdata; +}; + +/** A blendfile library entry in the `libraries` vector from #BlendfileLinkAppendContext. */ +struct BlendfileLinkAppendContextLibrary { + std::string path; /* Absolute .blend file path. */ + BlendHandle *blo_handle; /* Blend file handle, if any. */ + bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */ + /* The blendfile report associated with the `blo_handle`, if owned. */ + BlendFileReadReport bf_reports; +}; + +/** + * General container for all relevant data for a library/linked-data related operation (linking, + * appending, library relocating, etc.). + */ +struct BlendfileLinkAppendContext { + /** List of library paths to search IDs in. */ + blender::Vector libraries; + /** + * List of all ID to try to link from #libraries. This is a linked list because iterators must + * not be invalidated when adding more items. + */ + std::list items; + using items_iterator_t = std::list::iterator; + /** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */ + LibraryLink_Params *params = nullptr; + + /** + * What is the current stage of the link/append process. Used mainly by the RNA wrappers for the + * pre/post handlers currently. + */ + enum class ProcessStage { + /** + * The context data is being filled with data (Libraries and IDs) to process. Nothing has been + * linked yet. + */ + Init = 0, + /** The context data is being used to linked IDs. */ + Linking, + /** + * The context data is being used to append IDs (i.e. make local linked ones, or re-use already + * existing local ones). + */ + Appending, + /** + * The context data is being used to instantiate (loose) IDs (i.e. ensure that Collections, + * Objects and/or ObjectData IDs are added to the current scene). + */ + Instantiating, + /** + * All data has been linked or appended. The context state represents the final result of the + * process. + */ + Done, + + /* NOTE: For the time being, liboverride step is not considered here (#BKE_blendfile_override). + * Mainly because it is only available through the BPY API currently. */ + }; + ProcessStage process_stage; + + /** Allows to easily find an existing items from an ID pointer. */ + blender::Map new_id_to_item; + + /** Runtime info used by append code to manage re-use of already appended matching IDs. */ + MainLibraryWeakReferenceMap *library_weak_reference_mapping = nullptr; + + /** Embedded blendfile and its size, if needed. */ + const void *blendfile_mem = nullptr; + size_t blendfile_memsize = 0; +}; /** * Allocate and initialize a new context to link/append data-blocks. @@ -158,6 +311,18 @@ void BKE_blendfile_link_append_context_item_foreach( BlendfileLinkAppendContextItem *item)> callback_function, eBlendfileLinkAppendForeachItemFlag flag); +/** + * Called once the link/append process has been fully initialized (all of its data has been set). + * + * NOTE: Currently only used to call the matching handler. + */ +void BKE_blendfile_link_append_context_init_done(BlendfileLinkAppendContext *lapp_context); + +/** + * Perform linking operation on all items added to given `lapp_context`. + */ +void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports); + /** * Perform append operation, using modern ID usage looper to detect which ID should be kept * linked, made local, duplicated as local, re-used from local etc. @@ -166,10 +331,6 @@ void BKE_blendfile_link_append_context_item_foreach( * #BKE_blendfile_link on the same `lapp_context`. */ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports); -/** - * Perform linking operation on all items added to given `lapp_context`. - */ -void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports); /** * Instantiate loose data in the scene (e.g. add object to the active collection). @@ -177,6 +338,13 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lapp_context, ReportList *reports); +/** + * Finalize the link/append process. + * + * NOTE: Currently only used to call the matching handler.. + */ +void BKE_blendfile_link_append_context_finalize(BlendfileLinkAppendContext *lapp_context); + /** * Options controlling the behavior of liboverrides creation. */ diff --git a/source/blender/blenkernel/BKE_callbacks.hh b/source/blender/blenkernel/BKE_callbacks.hh index 002c2d332fe..42e46619885 100644 --- a/source/blender/blenkernel/BKE_callbacks.hh +++ b/source/blender/blenkernel/BKE_callbacks.hh @@ -110,6 +110,8 @@ enum eCbEvent { BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST, BKE_CB_EVT_EXTENSION_REPOS_SYNC, BKE_CB_EVT_EXTENSION_REPOS_FILES_CLEAR, + BKE_CB_EVT_BLENDIMPORT_PRE, + BKE_CB_EVT_BLENDIMPORT_POST, BKE_CB_EVT_TOT, }; diff --git a/source/blender/blenkernel/intern/asset_edit.cc b/source/blender/blenkernel/intern/asset_edit.cc index 2409a74dc10..7c0214e0ace 100644 --- a/source/blender/blenkernel/intern/asset_edit.cc +++ b/source/blender/blenkernel/intern/asset_edit.cc @@ -61,8 +61,12 @@ static ID *asset_link_id(Main &global_main, lapp_context, asset_name, id_type, nullptr); BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0); + BKE_blendfile_link_append_context_init_done(lapp_context); + BKE_blendfile_link(lapp_context, nullptr); + BKE_blendfile_link_append_context_finalize(lapp_context); + ID *local_asset = BKE_blendfile_link_append_context_item_newid_get(lapp_context, lapp_item); BKE_blendfile_link_append_context_free(lapp_context); diff --git a/source/blender/blenkernel/intern/blender_copybuffer.cc b/source/blender/blenkernel/intern/blender_copybuffer.cc index 3bf95f0e657..799dce2be65 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.cc +++ b/source/blender/blenkernel/intern/blender_copybuffer.cc @@ -41,6 +41,8 @@ static void copybuffer_append(BlendfileLinkAppendContext *lapp_context, /* Tag existing IDs in given `bmain_dst` as already existing. */ BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, true); + BKE_blendfile_link_append_context_init_done(lapp_context); + BKE_blendfile_link(lapp_context, reports); /* Mark all library linked objects to be updated. */ @@ -53,6 +55,8 @@ static void copybuffer_append(BlendfileLinkAppendContext *lapp_context, /* Instantiate loose data in the scene (e.g. add object to the active collection). */ BKE_blendfile_link_append_instantiate_loose(lapp_context, reports); + BKE_blendfile_link_append_context_finalize(lapp_context); + /* This must be unset, otherwise these object won't link into other scenes from this blend * file. */ BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, false); diff --git a/source/blender/blenkernel/intern/blendfile_link_append.cc b/source/blender/blenkernel/intern/blendfile_link_append.cc index 3ae49e38bd4..54d5a2ae240 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.cc +++ b/source/blender/blenkernel/intern/blendfile_link_append.cc @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include "CLG_log.h" @@ -28,11 +26,9 @@ #include "DNA_scene_types.h" #include "DNA_space_types.h" -#include "BLI_bit_vector.hh" #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_linklist.h" -#include "BLI_map.hh" #include "BLI_math_vector.h" #include "BLI_string_ref.hh" #include "BLI_utildefines.h" @@ -40,6 +36,10 @@ #include "BLT_translation.hh" +#include "RNA_access.hh" +#include "RNA_prototypes.hh" + +#include "BKE_callbacks.hh" #include "BKE_grease_pencil_legacy_convert.hh" #include "BKE_idtype.hh" #include "BKE_key.hh" @@ -60,7 +60,6 @@ #include "BKE_blendfile_link_append.hh" -#include "BLO_readfile.hh" #include "BLO_writefile.hh" static CLG_LogRef LOG = {"bke.blendfile_link_append"}; @@ -69,69 +68,6 @@ static CLG_LogRef LOG = {"bke.blendfile_link_append"}; /** \name Link/append context implementation and public management API. * \{ */ -struct BlendfileLinkAppendContextItem { - /** Name of the ID (without the heading two-chars IDcode). */ - std::string name; - /** All libraries (from #BlendfileLinkAppendContext.libraries) to try to load this ID from. */ - blender::BitVector<> libraries; - /** ID type. */ - short idcode; - - /** Type of action to perform on this item, and general status tag information. - * NOTE: Mostly used by append post-linking processing. */ - char action; - char tag; - - /** Newly linked ID (nullptr until it has been successfully linked). */ - ID *new_id; - /** Library ID from which the #new_id has been linked (nullptr until it has been successfully - * linked). */ - Library *source_library; - /** Liboverride of the linked ID (nullptr until it has been successfully created or an existing - * one has been found). */ - ID *liboverride_id; - /** - * Whether the item has a matching local ID that was already appended from the same source - * before, and has not been modified. In 'Append & Reuse' case, this local ID _may_ be reused - * instead of making linked data local again. - */ - ID *reusable_local_id; - - /** Opaque user data pointer. */ - void *userdata; -}; - -/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */ -struct BlendfileLinkAppendContextLibrary { - std::string path; /* Absolute .blend file path. */ - BlendHandle *blo_handle; /* Blend file handle, if any. */ - bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */ - /* The blendfile report associated with the `blo_handle`, if owned. */ - BlendFileReadReport bf_reports; -}; - -struct BlendfileLinkAppendContext { - /** List of library paths to search IDs in. */ - blender::Vector libraries; - /** - * List of all ID to try to link from #libraries. This is a linked list because iterators must - * not be invalidated when adding more items. - */ - std::list items; - /** Linking/appending parameters. Including `bmain`, `scene`, `viewlayer` and `view3d`. */ - LibraryLink_Params *params = nullptr; - - /** Allows to easily find an existing items from an ID pointer. */ - blender::Map new_id_to_item; - - /** Runtime info used by append code to manage re-use of already appended matching IDs. */ - MainLibraryWeakReferenceMap *library_weak_reference_mapping = nullptr; - - /** Embedded blendfile and its size, if needed. */ - const void *blendfile_mem = nullptr; - size_t blendfile_memsize = 0; -}; - struct BlendfileLinkAppendContextCallBack { BlendfileLinkAppendContext *lapp_context; BlendfileLinkAppendContextItem *item; @@ -155,36 +91,6 @@ struct BlendfileLinkAppendContextCallBack { bool is_liboverride_dependency_only; }; -/** Actions to apply to an item (i.e. linked ID). */ -enum { - LINK_APPEND_ACT_UNSET = 0, - LINK_APPEND_ACT_KEEP_LINKED, - LINK_APPEND_ACT_REUSE_LOCAL, - LINK_APPEND_ACT_MAKE_LOCAL, - LINK_APPEND_ACT_COPY_LOCAL, -}; - -/** Various status info about an item (i.e. linked ID). */ -enum { - /** An indirectly linked ID. */ - LINK_APPEND_TAG_INDIRECT = 1 << 0, - /** - * An ID also used as liboverride dependency (either directly, as a liboverride reference, or - * indirectly, as data used by a liboverride reference). It should never be directly made local. - * - * Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY. - */ - LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY = 1 << 1, - /** - * An ID only used as liboverride dependency (either directly or indirectly, see - * #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY for precisions). It should not be considered during - * the 'make local' process, and remain purely linked data. - * - * Mutually exclusive with #LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY. - */ - LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY = 1 << 2, -}; - static BlendHandle *link_append_context_library_blohandle_ensure( BlendfileLinkAppendContext &lapp_context, BlendfileLinkAppendContextLibrary &lib_context, @@ -225,6 +131,7 @@ BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Pa { BlendfileLinkAppendContext *lapp_context = MEM_new(__func__); lapp_context->params = params; + lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Init; return lapp_context; } @@ -273,6 +180,7 @@ void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *l BlendHandle *blo_handle) { BLI_assert(lapp_context->items.empty()); + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init); BlendfileLinkAppendContextLibrary lib_context = {}; @@ -293,6 +201,8 @@ BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( { BlendfileLinkAppendContextItem item = {}; + item.lapp_context = lapp_context; + item.name = idname; item.idcode = idcode; item.libraries = blender::BitVector<>(lapp_context->libraries.size(), false); @@ -312,6 +222,8 @@ int BKE_blendfile_link_append_context_item_idtypes_from_library_add( const uint64_t id_types_filter, const int library_index) { + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init); + int id_num = 0; int id_code_iter = 0; short id_code; @@ -357,10 +269,12 @@ int BKE_blendfile_link_append_context_item_idtypes_from_library_add( } void BKE_blendfile_link_append_context_item_library_index_enable( - BlendfileLinkAppendContext * /*lapp_context*/, + BlendfileLinkAppendContext *lapp_context, BlendfileLinkAppendContextItem *item, const int library_index) { + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init); + UNUSED_VARS_NDEBUG(lapp_context); item->libraries[library_index].set(); } @@ -375,9 +289,11 @@ void *BKE_blendfile_link_append_context_item_userdata_get( return item->userdata; } -ID *BKE_blendfile_link_append_context_item_newid_get(BlendfileLinkAppendContext * /*lapp_context*/, +ID *BKE_blendfile_link_append_context_item_newid_get(BlendfileLinkAppendContext *lapp_context, BlendfileLinkAppendContextItem *item) { + BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init); + UNUSED_VARS_NDEBUG(lapp_context); return item->new_id; } @@ -385,6 +301,7 @@ void BKE_blendfile_link_append_context_item_newid_set(BlendfileLinkAppendContext BlendfileLinkAppendContextItem *item, ID *new_id) { + BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init); BLI_assert(item->new_id); BLI_assert(!item->liboverride_id); BLI_assert(new_id->lib == item->new_id->lib); @@ -396,8 +313,10 @@ void BKE_blendfile_link_append_context_item_newid_set(BlendfileLinkAppendContext } ID *BKE_blendfile_link_append_context_item_liboverrideid_get( - BlendfileLinkAppendContext * /*lapp_context*/, BlendfileLinkAppendContextItem *item) + BlendfileLinkAppendContext *lapp_context, BlendfileLinkAppendContextItem *item) { + BLI_assert(lapp_context->process_stage != BlendfileLinkAppendContext::ProcessStage::Init); + UNUSED_VARS_NDEBUG(lapp_context); return item->liboverride_id; } @@ -431,6 +350,28 @@ void BKE_blendfile_link_append_context_item_foreach( } } +void BKE_blendfile_link_append_context_init_done(BlendfileLinkAppendContext *lapp_context) +{ + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init); + + PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_BlendImportContext, lapp_context); + PointerRNA *pointers[1] = {&ctx_ptr}; + BKE_callback_exec(lapp_context->params->bmain, pointers, 1, BKE_CB_EVT_BLENDIMPORT_PRE); +} + +void BKE_blendfile_link_append_context_finalize(BlendfileLinkAppendContext *lapp_context) +{ + BLI_assert(ELEM(lapp_context->process_stage, + BlendfileLinkAppendContext::ProcessStage::Linking, + BlendfileLinkAppendContext::ProcessStage::Appending, + BlendfileLinkAppendContext::ProcessStage::Instantiating)); + lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Done; + + PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_BlendImportContext, lapp_context); + PointerRNA *pointers[1] = {&ctx_ptr}; + BKE_callback_exec(lapp_context->params->bmain, pointers, 1, BKE_CB_EVT_BLENDIMPORT_POST); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1334,6 +1275,9 @@ static void blendfile_append_define_actions(BlendfileLinkAppendContext &lapp_con void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) { + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Linking); + lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Appending; + if (lapp_context->items.empty()) { /* Nothing to append. */ return; @@ -1537,6 +1481,11 @@ static int foreach_libblock_link_finalize_cb(LibraryIDLinkCallbackData *cb_data) void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lapp_context, ReportList *reports) { + BLI_assert(ELEM(lapp_context->process_stage, + BlendfileLinkAppendContext::ProcessStage::Linking, + BlendfileLinkAppendContext::ProcessStage::Appending)); + lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Instantiating; + if (!lapp_context->params->context.scene) { return; } @@ -1574,6 +1523,9 @@ void BKE_blendfile_link_append_instantiate_loose(BlendfileLinkAppendContext *lap void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) { + BLI_assert(lapp_context->process_stage == BlendfileLinkAppendContext::ProcessStage::Init); + lapp_context->process_stage = BlendfileLinkAppendContext::ProcessStage::Linking; + if (lapp_context->items.empty()) { /* Nothing to be linked. */ return; @@ -1869,6 +1821,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, BKE_main_id_tag_all(bmain, ID_TAG_PRE_EXISTING, true); + BKE_blendfile_link_append_context_init_done(lapp_context); + /* We do not want any instantiation here! */ BKE_blendfile_link(lapp_context, reports); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index c53fa919db8..13104e92b91 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -55,6 +55,7 @@ set(DEFSRC rna_light.cc rna_lightprobe.cc rna_linestyle.cc + rna_blendfile_import.cc rna_main.cc rna_mask.cc rna_material.cc diff --git a/source/blender/makesrna/intern/makesrna.cc b/source/blender/makesrna/intern/makesrna.cc index 53b0fbb5638..8ef63571993 100644 --- a/source/blender/makesrna/intern/makesrna.cc +++ b/source/blender/makesrna/intern/makesrna.cc @@ -4827,6 +4827,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_lattice.cc", "rna_lattice_api.cc", RNA_def_lattice}, {"rna_layer.cc", nullptr, RNA_def_view_layer}, {"rna_linestyle.cc", nullptr, RNA_def_linestyle}, + {"rna_blendfile_import.cc", nullptr, RNA_def_blendfile_import}, {"rna_main.cc", "rna_main_api.cc", RNA_def_main}, {"rna_fluid.cc", nullptr, RNA_def_fluid}, {"rna_material.cc", "rna_material_api.cc", RNA_def_material}, diff --git a/source/blender/makesrna/intern/rna_blendfile_import.cc b/source/blender/makesrna/intern/rna_blendfile_import.cc new file mode 100644 index 00000000000..81bb5a5aec9 --- /dev/null +++ b/source/blender/makesrna/intern/rna_blendfile_import.cc @@ -0,0 +1,556 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup RNA + */ + +#include + +#include "BLO_readfile.hh" + +#include "DNA_space_types.h" + +#include "BKE_blendfile_link_append.hh" + +#include "RNA_access.hh" +#include "RNA_define.hh" +#include "RNA_enum_types.hh" + +#include "rna_internal.hh" + +#ifdef RNA_RUNTIME + +# include "BLI_bit_span.hh" +# include "BLI_string_utils.hh" + +void rna_BlendImportContextLibrary_filepath_get(PointerRNA *ptr, char *value) +{ + BlendfileLinkAppendContextLibrary *ctx_lib = static_cast( + ptr->data); + const size_t str_len = ctx_lib->path.length(); + BLI_strncpy(value, ctx_lib->path.c_str(), str_len + 1); +} + +int rna_BlendImportContextLibrary_filepath_len(PointerRNA *ptr) +{ + BlendfileLinkAppendContextLibrary *ctx_lib = static_cast( + ptr->data); + return int(ctx_lib->path.length()); +} + +void rna_BlendImportContextItem_name_get(PointerRNA *ptr, char *value) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + const size_t str_len = ctx_item->name.length(); + BLI_strncpy(value, ctx_item->name.c_str(), str_len + 1); +} + +int rna_BlendImportContextItem_name_len(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return int(ctx_item->name.length()); +} + +int rna_BlendImportContextItem_id_type_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return int(ctx_item->idcode); +} + +struct RNABlendImportContextItemLibrariesIterator { + BlendfileLinkAppendContextItem *ctx_item; + blender::bits::BitIterator iter; + int iter_index; +}; + +void rna_BlendImportContextItem_libraries_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + + const blender::BitVector<> &libraries = ctx_item->libraries; + RNABlendImportContextItemLibrariesIterator *libs_iter = + MEM_new( + __func__, RNABlendImportContextItemLibrariesIterator{ctx_item, libraries.begin(), 0}); + iter->internal.custom = libs_iter; + while (!(*libs_iter->iter) && libs_iter->iter != libs_iter->ctx_item->libraries.end()) { + libs_iter->iter.operator++(); + libs_iter->iter_index++; + } + iter->valid = (libs_iter->iter != libs_iter->ctx_item->libraries.end()); +} + +void rna_BlendImportContextItem_libraries_next(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemLibrariesIterator *libs_iter = + static_cast(iter->internal.custom); + do { + libs_iter->iter.operator++(); + libs_iter->iter_index++; + } while (!(*libs_iter->iter) && libs_iter->iter != libs_iter->ctx_item->libraries.end()); + iter->valid = (libs_iter->iter != libs_iter->ctx_item->libraries.end()); +} + +void rna_BlendImportContextItem_libraries_end(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemLibrariesIterator *libs_iter = + static_cast(iter->internal.custom); + + iter->valid = false; + iter->internal.custom = nullptr; + MEM_delete(libs_iter); +} + +PointerRNA rna_BlendImportContextItem_libraries_get(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemLibrariesIterator *libs_iter = + static_cast(iter->internal.custom); + + BlendfileLinkAppendContextLibrary &ctx_lib = + libs_iter->ctx_item->lapp_context->libraries[libs_iter->iter_index]; + return rna_pointer_inherit_refine(&iter->parent, &RNA_BlendImportContextLibrary, &ctx_lib); +} + +int rna_BlendImportContextItem_libraries_len(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + + /* Count amount of enabled libraries in the item's bitmask. */ + int count = 0; + for (const blender::BitRef &bit : ctx_item->libraries) { + if (bit) { + count++; + } + } + return count; +} + +int rna_BlendImportContextItem_append_action_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return int(ctx_item->action); +} + +int rna_BlendImportContextItem_import_info_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return int(ctx_item->tag); +} + +PointerRNA rna_BlendImportContextItem_id_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->new_id); +} + +PointerRNA rna_BlendImportContextItem_source_library_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_Library, ctx_item->source_library); +} + +PointerRNA rna_BlendImportContextItem_library_override_id_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->liboverride_id); +} + +PointerRNA rna_BlendImportContextItem_reusable_local_id_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContextItem *ctx_item = static_cast( + ptr->data); + return rna_pointer_inherit_refine(&PointerRNA_NULL, &RNA_ID, ctx_item->reusable_local_id); +} + +struct RNABlendImportContextItemsIterator { + BlendfileLinkAppendContext *ctx; + BlendfileLinkAppendContext::items_iterator_t iter; +}; + +void rna_BlendImportContext_import_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + BlendfileLinkAppendContext *ctx = static_cast(ptr->data); + + RNABlendImportContextItemsIterator *items_iter = MEM_new( + __func__, RNABlendImportContextItemsIterator{ctx, ctx->items.begin()}); + iter->internal.custom = items_iter; + iter->valid = (items_iter->iter != items_iter->ctx->items.end()); +} + +void rna_BlendImportContext_import_items_next(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemsIterator *items_iter = + static_cast(iter->internal.custom); + items_iter->iter++; + iter->valid = (items_iter->iter != items_iter->ctx->items.end()); +} + +void rna_BlendImportContext_import_items_end(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemsIterator *items_iter = + static_cast(iter->internal.custom); + + iter->valid = false; + iter->internal.custom = nullptr; + MEM_delete(items_iter); +} + +PointerRNA rna_BlendImportContext_import_items_get(CollectionPropertyIterator *iter) +{ + RNABlendImportContextItemsIterator *items_iter = + static_cast(iter->internal.custom); + + BlendfileLinkAppendContextItem &ctx_item = *items_iter->iter; + return rna_pointer_inherit_refine(&iter->parent, &RNA_BlendImportContextItem, &ctx_item); +} + +int rna_BlendImportContext_import_items_len(PointerRNA *ptr) +{ + BlendfileLinkAppendContext *ctx = static_cast(ptr->data); + return int(ctx->items.size()); +} + +int rna_BlendImportContext_options_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContext *ctx = static_cast(ptr->data); + return int(ctx->params->flag); +} + +int rna_BlendImportContext_process_stage_get(PointerRNA *ptr) +{ + BlendfileLinkAppendContext *ctx = static_cast(ptr->data); + return int(ctx->process_stage); +} + +#else /* RNA_RUNTIME */ + +static void rna_def_blendfile_import_library(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "BlendImportContextLibrary", nullptr); + RNA_def_struct_ui_text( + srna, + "Blendfile Import Context Library", + "Library (blendfile) reference in a BlendImportContext data. Currently only " + "exposed as read-only data for the pre/post blendimport handlers"); + + RNA_define_verify_sdna(false); /* not in sdna */ + + prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_funcs(prop, + "rna_BlendImportContextLibrary_filepath_get", + "rna_BlendImportContextLibrary_filepath_len", + nullptr); + + RNA_define_verify_sdna(true); /* not in sdna */ +} + +static void RNA_def_blendfile_import_libraries(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + RNA_def_property_srna(cprop, "BlendImportContextLibraries"); + srna = RNA_def_struct(brna, "BlendImportContextLibraries", nullptr); + RNA_def_struct_ui_text(srna, + "Blendfile Import Context Libraries", + "Collection of source libraries, i.e. blendfile paths"); +} + +static void rna_def_blendfile_import_item(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "BlendImportContextItem", nullptr); + RNA_def_struct_ui_text( + srna, + "Blendfile Import Context Item", + "An item (representing a data-block) in a BlendImportContext data. Currently only " + "exposed as read-only data for the pre/post linking handlers"); + + RNA_define_verify_sdna(false); /* not in sdna */ + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "ID Name", "ID name of the item"); + RNA_def_property_string_funcs( + prop, "rna_BlendImportContextItem_name_get", "rna_BlendImportContextItem_name_len", nullptr); + + prop = RNA_def_property(srna, "id_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_id_type_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "ID Type", "ID type of the item"); + RNA_def_property_enum_funcs(prop, "rna_BlendImportContextItem_id_type_get", nullptr, nullptr); + + prop = RNA_def_property(srna, "source_libraries", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "BlendImportContextLibrary"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Source Libraries", + "List of libraries to search and import that ID from. The ID will be " + "imported from the first file in that list that contains it"); + RNA_def_property_collection_funcs(prop, + "rna_BlendImportContextItem_libraries_begin", + "rna_BlendImportContextItem_libraries_next", + "rna_BlendImportContextItem_libraries_end", + "rna_BlendImportContextItem_libraries_get", + "rna_BlendImportContextItem_libraries_len", + nullptr, + nullptr, + nullptr); + RNA_def_blendfile_import_libraries(brna, prop); + + static const EnumPropertyItem blend_import_item_append_action_items[] = { + {LINK_APPEND_ACT_UNSET, "UNSET", 0, "", "Not yet defined"}, + {LINK_APPEND_ACT_KEEP_LINKED, "KEEP_LINKED", 0, "", "ID has been kept linked"}, + {LINK_APPEND_ACT_REUSE_LOCAL, + "REUSE_LOCAL", + 0, + "", + "An existing matching local ID has been re-used"}, + {LINK_APPEND_ACT_MAKE_LOCAL, "MAKE_LOCAL", 0, "", "The newly linked ID has been made local"}, + {LINK_APPEND_ACT_COPY_LOCAL, + "COPY_LOCAL", + 0, + "", + "The linked ID had other unrelated usages, so it has been duplicated into a local copy"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + prop = RNA_def_property(srna, "append_action", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, blend_import_item_append_action_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Append Action", + "How this item has been handled by the append operation. Only set if " + "the data has been appended"); + RNA_def_property_enum_funcs( + prop, "rna_BlendImportContextItem_append_action_get", nullptr, nullptr); + + static const EnumPropertyItem blend_import_item_import_info_items[] = { + {LINK_APPEND_TAG_INDIRECT, + "INDIRECT_USAGE", + 0, + "", + "That item was added for an indirectly imported ID, as a dependency of another data-block"}, + {LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY, + "LIBOVERRIDE_DEPENDENCY", + 0, + "", + "That item represents an ID also used as liboverride dependency (either directly, as a " + "liboverride reference, or indirectly, as data used by a liboverride reference). It should " + "never be directly made local. Mutually exclusive with `LIBOVERRIDE_DEPENDENCY_ONLY`"}, + {LINK_APPEND_TAG_LIBOVERRIDE_DEPENDENCY_ONLY, + "LIBOVERRIDE_DEPENDENCY_ONLY", + 0, + "", + "That item represents an ID only used as liboverride dependency (either directly or " + "indirectly, see `LIBOVERRIDE_DEPENDENCY` for precisions). It should not be considered " + "during the 'make local' (append) process, and remain purely linked data. Mutually " + "exclusive with `LIBOVERRIDE_DEPENDENCY`"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + prop = RNA_def_property(srna, "import_info", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, blend_import_item_import_info_items); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Import Info", "Various status info about an item after it has been imported"); + RNA_def_property_enum_funcs( + prop, "rna_BlendImportContextItem_import_info_get", nullptr, nullptr); + + prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ID"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Imported ID", + "The imported ID. None until it has been linked or appended. May be " + "the same as `reusable_local_id` when appended"); + RNA_def_property_pointer_funcs( + prop, "rna_BlendImportContextItem_id_get", nullptr, nullptr, nullptr); + + prop = RNA_def_property(srna, "source_library", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Library"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Source Library", + "Library ID representing the blendfile from which the ID was imported. " + "None until the ID has been linked or appended"); + RNA_def_property_pointer_funcs( + prop, "rna_BlendImportContextItem_source_library_get", nullptr, nullptr, nullptr); + + prop = RNA_def_property(srna, "library_override_id", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ID"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, + "Library Overridden ID", + "The library override of the linked ID. None until it has been created"); + RNA_def_property_pointer_funcs( + prop, "rna_BlendImportContextItem_library_override_id_get", nullptr, nullptr, nullptr); + + prop = RNA_def_property(srna, "reusable_local_id", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ID"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Reusable Local ID", + "The already existing local ID that may be reused in append & reuse " + "case. None until it has been found"); + RNA_def_property_pointer_funcs( + prop, "rna_BlendImportContextItem_reusable_local_id_get", nullptr, nullptr, nullptr); + + RNA_define_verify_sdna(true); /* not in sdna */ +} + +static void rna_def_blendfile_import_items(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + RNA_def_property_srna(cprop, "BlendImportContextItems"); + srna = RNA_def_struct(brna, "BlendImportContextItems", nullptr); + RNA_def_struct_ui_text( + srna, "Blendfile Import Context Items", "Collection of blendfile import context items"); + + /* TODO: Add/Remove items _before_ doing link/append (i.e. for 'pre' handlers). */ +} + +static void rna_def_blendfile_import_context(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "BlendImportContext", nullptr); + RNA_def_struct_ui_text( + srna, + "Blendfile Import Context", + "Contextual data for a blendfile library/linked-data related operation. Currently " + "only exposed as read-only data for the pre/post blendimport handlers"); + + RNA_define_verify_sdna(false); /* not in sdna */ + + /* NOTE: Cannot use just `items` here as this is a reserved Python dict method name. */ + prop = RNA_def_property(srna, "import_items", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "BlendImportContextItem"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_collection_funcs(prop, + "rna_BlendImportContext_import_items_begin", + "rna_BlendImportContext_import_items_next", + "rna_BlendImportContext_import_items_end", + "rna_BlendImportContext_import_items_get", + "rna_BlendImportContext_import_items_len", + nullptr, + nullptr, + nullptr); + rna_def_blendfile_import_items(brna, prop); + + static const EnumPropertyItem blend_import_options_items[] = { + {FILE_LINK, "LINK", 0, "", "Only link data, instead of appending it"}, + {FILE_RELPATH, + "MAKE_PATHS_RELATIVE", + 0, + "", + "Make paths of used library blendfiles relative to current blendfile"}, + {BLO_LIBLINK_USE_PLACEHOLDERS, + "USE_PLACEHOLDERS", + 0, + "", + "Generate a placeholder (empty ID) if not found in any library files"}, + {BLO_LIBLINK_FORCE_INDIRECT, + "FORCE_INDIRECT", + 0, + "", + "Force loaded ID to be tagged as indirectly linked (used in reload context only)"}, + {BLO_LIBLINK_APPEND_SET_FAKEUSER, + "APPEND_SET_FAKEUSER", + 0, + "", + "Set fake user on appended IDs"}, + {BLO_LIBLINK_APPEND_RECURSIVE, + "APPEND_RECURSIVE", + 0, + "", + "Append (make local) also indirect dependencies of appended IDs coming from other " + "libraries. NOTE: All IDs (including indirectly linked ones) coming from the same initial " + "library are always made local"}, + {BLO_LIBLINK_APPEND_LOCAL_ID_REUSE, + "APPEND_LOCAL_ID_REUSE", + 0, + "", + "Try to re-use previously appended matching IDs when appending them again, instead of " + "creating local duplicates"}, + {BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR, + "APPEND_ASSET_DATA_CLEAR", + 0, + "", + "Clear the asset data on append (it is always kept for linked data)"}, + {FILE_AUTOSELECT, "SELECT_OBJECTS", 0, "", "Automatically select imported objects"}, + {FILE_ACTIVE_COLLECTION, + "USE_ACTIVE_COLLECTION", + 0, + "", + "Use the active Collection of the current View Layer to instantiate imported " + "collections and objects"}, + {BLO_LIBLINK_OBDATA_INSTANCE, + "OBDATA_INSTANCE", + 0, + "", + "Instantiate object data IDs (i.e. create objects for them if needed)"}, + {BLO_LIBLINK_COLLECTION_INSTANCE, + "COLLECTION_INSTANCE", + 0, + "", + "Instantiate collections as empties, instead of linking them into the current view layer"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + prop = RNA_def_property(srna, "options", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, blend_import_options_items); + RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "", "Options for this blendfile import operation"); + RNA_def_property_enum_funcs(prop, "rna_BlendImportContext_options_get", nullptr, nullptr); + + /* NOTE: Only stages currently exposed to handlers are listed here. */ + static const EnumPropertyItem blend_import_process_stage_items[] = { + {int(BlendfileLinkAppendContext::ProcessStage::Init), + "INIT", + 0, + "", + "Blendfile import context has been initialized and filled with a list of items to import, " + "no data has been linked or appended yet"}, + {int(BlendfileLinkAppendContext::ProcessStage::Done), + "DONE", + 0, + "", + "All data has been imported and is available in the list of `import_items`"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + prop = RNA_def_property(srna, "process_stage", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, blend_import_process_stage_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "", "Current stage of the import process"); + RNA_def_property_enum_funcs(prop, "rna_BlendImportContext_process_stage_get", nullptr, nullptr); + + RNA_define_verify_sdna(true); /* not in sdna */ +} + +void RNA_def_blendfile_import(BlenderRNA *brna) +{ + rna_def_blendfile_import_library(brna); + rna_def_blendfile_import_item(brna); + rna_def_blendfile_import_context(brna); +} + +#endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_internal.hh b/source/blender/makesrna/intern/rna_internal.hh index 130c4b848f1..9763b8290a4 100644 --- a/source/blender/makesrna/intern/rna_internal.hh +++ b/source/blender/makesrna/intern/rna_internal.hh @@ -166,6 +166,7 @@ void RNA_def_key(BlenderRNA *brna); void RNA_def_light(BlenderRNA *brna); void RNA_def_lattice(BlenderRNA *brna); void RNA_def_linestyle(BlenderRNA *brna); +void RNA_def_blendfile_import(BlenderRNA *brna); void RNA_def_main(BlenderRNA *brna); void RNA_def_material(BlenderRNA *brna); void RNA_def_mesh(BlenderRNA *brna); diff --git a/source/blender/python/intern/bpy_app_handlers.cc b/source/blender/python/intern/bpy_app_handlers.cc index a8ce57b7690..3500dff2879 100644 --- a/source/blender/python/intern/bpy_app_handlers.cc +++ b/source/blender/python/intern/bpy_app_handlers.cc @@ -99,6 +99,10 @@ static PyStructSequence_Field app_cb_info_fields[] = { {"_extension_repos_sync", "on creating or synchronizing the active repository"}, {"_extension_repos_files_clear", "remove files from the repository directory (uses as a string argument)"}, + {"blend_import_pre", + "on linking or appending data (before), get a single `BlendImportContext` parameter"}, + {"blend_import_post", + "on linking or appending data (after), get a single `BlendImportContext` parameter"}, /* sets the permanent tag */ #define APP_CB_OTHER_FIELDS 1 diff --git a/source/blender/python/intern/bpy_library_load.cc b/source/blender/python/intern/bpy_library_load.cc index fdd1b525672..1590ba3465e 100644 --- a/source/blender/python/intern/bpy_library_load.cc +++ b/source/blender/python/intern/bpy_library_load.cc @@ -527,6 +527,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject * /*args*/) } } + BKE_blendfile_link_append_context_init_done(lapp_context); + BKE_blendfile_link(lapp_context, nullptr); if (do_append) { BKE_blendfile_append(lapp_context, nullptr); @@ -535,6 +537,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject * /*args*/) BKE_blendfile_override(lapp_context, self->liboverride_flags, nullptr); } + BKE_blendfile_link_append_context_finalize(lapp_context); + /* If enabled, replace named items in given lists by the final matching new ID pointer. */ #ifdef USE_RNA_DATABLOCKS idcode_step = 0; diff --git a/source/blender/windowmanager/intern/wm_files_link.cc b/source/blender/windowmanager/intern/wm_files_link.cc index 1f557c1a8a9..d309b5a2c4f 100644 --- a/source/blender/windowmanager/intern/wm_files_link.cc +++ b/source/blender/windowmanager/intern/wm_files_link.cc @@ -350,6 +350,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + BKE_blendfile_link_append_context_init_done(lapp_context); + /* XXX We'd need re-entrant locking on Main for this to work... */ // BKE_main_lock(bmain); @@ -369,6 +371,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* Instantiate loose data in the scene (e.g. add object to the active collection). */ BKE_blendfile_link_append_instantiate_loose(lapp_context, op->reports); + BKE_blendfile_link_append_context_finalize(lapp_context); + BKE_blendfile_link_append_context_free(lapp_context); /* Important we unset, otherwise these object won't @@ -543,6 +547,8 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, lapp_context, id_name, id_code, nullptr); BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); + BKE_blendfile_link_append_context_init_done(lapp_context); + /* Link datablock. */ BKE_blendfile_link(lapp_context, nullptr); @@ -552,6 +558,8 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, BKE_blendfile_link_append_instantiate_loose(lapp_context, nullptr); + BKE_blendfile_link_append_context_finalize(lapp_context); + /* Get linked datablock and free working data. */ ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item);