Assets: Clear asset data by default on all "Make Local" actions

Fixes #107880.

When making a linked asset local, you typically wouldn't want this new
data-block to suddenly be part of the asset libraries this file is in. To the
user it seems like making such a data-block local also implicitly makes it an
asset.  Appending an asset already handles this, and clears the asset data by
default.

This patch modifies the `bpy.types.ID.make_local()` method, as well as all
internal calls to the make local functions, so that asset data is cleared by
default. The Python method has a new `clear_asset_data` parameter (optional,
true by default). Maybe this should not be optional.

Pull Request: https://projects.blender.org/blender/blender/pulls/110197
This commit is contained in:
Julian Eisel 2024-05-21 20:41:16 +02:00
parent 69e4aac784
commit 20df089341
7 changed files with 34 additions and 11 deletions

@ -712,9 +712,15 @@ char *BKE_id_to_unique_string_key(const ID *id);
* #LIB_TAG_PRE_EXISTING.
* \param set_fake: If true, set fake user on all localized data-blocks
* (except group and objects ones).
* \param clear_asset_data: If true, clear the asset metadata on all localized data-blocks, making
* them normal non-asset data-blocks.
*/
void BKE_library_make_local(
Main *bmain, const Library *lib, GHash *old_to_new_ids, bool untagged_only, bool set_fake);
void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
bool untagged_only,
bool set_fake,
bool clear_asset_data);
void BKE_id_tag_set_atomic(ID *id, int tag);
void BKE_id_tag_clear_atomic(ID *id, int tag);

@ -166,7 +166,7 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
* does not deal properly with it. */
/* NOTE: assert below ensures that the comment above is valid, and that exception is
* acceptable for the time being. */
BKE_lib_id_make_local(bmain, &brush->clone.image->id, 0);
BKE_lib_id_make_local(bmain, &brush->clone.image->id, LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR);
BLI_assert(!ID_IS_LINKED(brush->clone.image) && brush->clone.image->id.newid == nullptr);
}

@ -1946,7 +1946,8 @@ void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
const bool untagged_only,
const bool set_fake)
const bool set_fake,
const bool clear_asset_data)
{
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
@ -2061,6 +2062,8 @@ void BKE_library_make_local(Main *bmain,
TIMEIT_VALUE_PRINT(make_local);
#endif
const int make_local_flags = clear_asset_data ? LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : 0;
/* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
* which involves more complex checks and might instead
* create a local copy of original linked ID. */
@ -2073,7 +2076,7 @@ void BKE_library_make_local(Main *bmain,
* currently there are some indirect usages. So instead of making a copy that we'll likely
* get rid of later, directly make that data block local.
* Saves a tremendous amount of time with complex scenes... */
BKE_lib_id_clear_library_data(bmain, id, 0);
BKE_lib_id_clear_library_data(bmain, id, make_local_flags);
BKE_lib_id_expand_local(bmain, id, 0);
id->tag &= ~LIB_TAG_DOIT;
@ -2083,7 +2086,7 @@ void BKE_library_make_local(Main *bmain,
}
else {
/* In this specific case, we do want to make ID local even if it has no local usage yet... */
BKE_lib_id_make_local(bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY);
BKE_lib_id_make_local(bmain, id, make_local_flags | LIB_ID_MAKELOCAL_FULL_LIBRARY);
if (id->newid) {
if (GS(id->newid->name) == ID_OB) {

@ -1017,7 +1017,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
}
else {
if (BKE_lib_id_make_local(bmain, id, 0)) {
if (BKE_lib_id_make_local(bmain, id, LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR)) {
BKE_id_newptr_and_tag_clear(id);
/* Reassign to get proper updates/notifiers. */

@ -2262,7 +2262,8 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
BKE_library_make_local(bmain, nullptr, nullptr, true, false); /* nullptr is all libraries. */
BKE_library_make_local(
bmain, nullptr, nullptr, true, false, true); /* nullptr is all libraries. */
WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;

@ -978,7 +978,7 @@ static void id_local_fn(bContext *C,
{
if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
Main *bmain = CTX_data_main(C);
if (BKE_lib_id_make_local(bmain, tselem->id, 0)) {
if (BKE_lib_id_make_local(bmain, tselem->id, LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR)) {
BKE_id_newptr_and_tag_clear(tselem->id);
}
}

@ -1101,10 +1101,16 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
}
}
static ID *rna_ID_make_local(ID *self, Main *bmain, bool /*clear_proxy*/, bool clear_liboverride)
static ID *rna_ID_make_local(
ID *self, Main *bmain, bool /*clear_proxy*/, bool clear_liboverride, bool clear_asset_data)
{
if (ID_IS_LINKED(self)) {
BKE_lib_id_make_local(bmain, self, 0);
int flags = 0;
if (clear_asset_data) {
flags |= LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR;
}
BKE_lib_id_make_local(bmain, self, flags);
}
else if (ID_IS_OVERRIDE_LIBRARY_REAL(self)) {
BKE_lib_override_library_make_local(bmain, self);
@ -2458,6 +2464,13 @@ static void rna_def_ID(BlenderRNA *brna)
false,
"",
"Remove potential library override data from the newly made local data");
RNA_def_boolean(
func,
"clear_asset_data",
true,
"",
"Remove potential asset metadata so the newly local data-block is not treated as asset "
"data-block and won't show up in asset libraries");
parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied");
RNA_def_function_return(func, parm);