The method Node.copy is supposed to be called when a node is copied. In particular, this should allow developers of ShaderNodeCustomGroup to recreate internal node_tree if it depends on node options/properties.
However, this does not happen when node is copied into another material with operator ops.material.new. This results in that all node trees are shared between materials and adjusting trees according to options/properties affect all materials.
The condition when the method shold be called is determined by this line at source/blender/rendkernel/intern/node.c, in function BKE_node_copy_ex:
The flags are described as /** Create datablock outside of any main database - similar to 'localize' functions of materials etc. */ and /** Generate a local copy, outside of bmain, to work on (used by COW e.g.). */
When copying material node_tree, the flags to copy nodes are set
at source/blender/rendkernel/intern/node.c, in function BKE_node_tree_copy_data
:
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
The flag LIB_ID_CREATE_NO_USER_REFCOUNT is /** Do not affect user refcount of datablocks used by new one (which also gets zero usercount then). */ and it’s included into LIB_ID_COPY_LOCALIZE.
Altough, refcounts of node_trees of copied ShaderNodeCustomGroups are effectively affected by such copying.
Could someone or @mont29 please explain the logic behind this, and hint if the behaviour of not calling copy can be ever fixed?
From quick overview the do_copy_api check is obviously wrong, you cannot use a simple boolean value to check a multiple-bits ‘flag’ like LIB_ID_COPY_LOCALIZE, you need a proper full comparison of the result of the AND operation here to ensure all expected bits are actually set…
Will fix that now, am kind of wary though that some ID may create other random IDs in their duplication code… we do that in a few specific cases (like actions from animdata, or shapekeys for meshes and co), but those are fairly well contained scope, and were already rather hairy to get working properly…
Well.
Setting property node_tree updates user counts for old and new values.
The reason why it fails is that it is called from various BKE_*_copy_data while a node is inconsistent state in the middle of copying/linking/parenting.
I suppose that the call should be moved from the BKE_node_copy_ex to upper contexts such as operator implementations.