Call to user-defined copy method of NodeCustomGroup is broken. In addition, implementation of some related operators has pure logical bugs (confising true vs false), that happened to partially compensate each other.
The cause of broken copy is that the copyfunc_api is often called from within BKE_node_copy_ex <- BKE_node_tree_copy_data <- BKE_id_copy_ex when the data is in inconsistent state.
Initializing property node_tree within python copy updates counters of old/new trees. This makes source trees which are still in use to have 0 user counter, which may lead to NULL pointers or attempts to push counter below zero, destroying materials and crashing blender.
This patch adds new flag 'COPY_NO_API` and uses it to move the call to api to the very end of BKE_id_copy_ex after state of counters is settled.
Use cases adressed/affected/fixed/tested
- copying a tree with ID.copy -- FIXED // D6420/test_api_trees_copy
- duplicating node -- tested // D6420/test_op_node_duplicate
- copypasting node -- tested // D6420/test_op_node_copypaste, D6420/test_op_node_copypaste_vanished
- making group -- tested // D6420/test_op_group_make
- ungrouping node group -- FIXED // D6420/test_op_group_ungroup
- separating node from group -- tested // D6420/test_op_group_separate_copy, D6420/test_op_group_separate_move
- duplicating group -- tested // D6420/test_op_group_duplicate
- singleusering a group -- FIXED // T72659
- cloning material -- FIXED // D6420/test_op_mat_clone, T72317
- copypasting material -- PARTIALLY FIXED // D6420/test_op_mat_clone, T72579
- singleusering a material -- FIXED
In the case of copypasting material, the call to copy is fixed, but user counters still bogus because of some other bug.
Other affected code
Basically, everything that directly or indirectly uses BKE_id_copy_ex or BKE_node_copy_ex without flag CREATE_NO_MAIN.