From 14106150797a6ce35e006ffde18e78ea7ae67598 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 12 Feb 2024 20:28:56 +0100 Subject: [PATCH] Nodes: expose multi-input sockets to custom nodes in the Python API Currently the multi-input sockets are not exposed to the custom nodes Python API. This makes some features cumbersome to implement if one wants a node to process an arbitrary number of inputs. One workaround is to make inputs duplicate themselves when a link is created, but a proper multi-input would be easier to use for both add-on developers and users. This commit exposes a new `use_multi_input` boolean parameter when creating a new node socket. This makes it possible to declare a multi-input, while still leaving the existing `is_multi_input` property read-only so that existing nodes cannot be made unstable. The parameter is optional so existing scripts stay compatible. It also raises an error when used on output sockets, since it makes no sense for those to be multi-input. The Custom Node Tree Python template was updated to reflect this change by making one of the inputs of the custom node multi-input. Pull Request: https://projects.blender.org/blender/blender/pulls/114474 --- intern/cycles/blender/python.cpp | 14 ++++++-------- scripts/templates_py/custom_nodes.py | 2 +- source/blender/makesrna/intern/rna_nodetree.cc | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp index a0441c2e2c8..ea41b12bd42 100644 --- a/intern/cycles/blender/python.cpp +++ b/intern/cycles/blender/python.cpp @@ -615,14 +615,12 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args) if (!found_existing) { /* Create new socket. */ - BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data, - socket_type.c_str(), - param_label.c_str(), - param->name.c_str()) : - b_node.inputs.create(b_data, - socket_type.c_str(), - param_label.c_str(), - param->name.c_str()); + BL::NodeSocket b_sock = + (param->isoutput) ? + b_node.outputs.create( + b_data, socket_type.c_str(), param_label.c_str(), param->name.c_str(), false) : + b_node.inputs.create( + b_data, socket_type.c_str(), param_label.c_str(), param->name.c_str(), false); /* set default value */ if (data_type == BL::NodeSocket::type_VALUE) { diff --git a/scripts/templates_py/custom_nodes.py b/scripts/templates_py/custom_nodes.py index f6fe0979ac1..bf2886fd00f 100644 --- a/scripts/templates_py/custom_nodes.py +++ b/scripts/templates_py/custom_nodes.py @@ -99,7 +99,7 @@ class MyCustomNode(MyCustomTreeNode, Node): def init(self, context): self.inputs.new('CustomSocketType', "Hello") self.inputs.new('NodeSocketFloat', "World") - self.inputs.new('NodeSocketVector', "!") + self.inputs.new('NodeSocketVector', "!", use_multi_input=True) self.outputs.new('NodeSocketColor', "How") self.outputs.new('NodeSocketColor', "are") diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 479529155e7..cb35f43574c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -2232,7 +2232,8 @@ static bNodeSocket *rna_Node_inputs_new(ID *id, ReportList *reports, const char *type, const char *name, - const char *identifier) + const char *identifier, + const bool use_multi_input) { if (!allow_changing_sockets(node)) { BKE_report(reports, RPT_ERROR, "Cannot add socket to built-in node"); @@ -2246,6 +2247,9 @@ static bNodeSocket *rna_Node_inputs_new(ID *id, BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { + if (use_multi_input) { + sock->flag |= SOCK_MULTI_INPUT; + } ED_node_tree_propagate_change(nullptr, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2259,13 +2263,19 @@ static bNodeSocket *rna_Node_outputs_new(ID *id, ReportList *reports, const char *type, const char *name, - const char *identifier) + const char *identifier, + const bool use_multi_input) { if (!allow_changing_sockets(node)) { BKE_report(reports, RPT_ERROR, "Cannot add socket to built-in node"); return nullptr; } + if (use_multi_input) { + BKE_report(reports, RPT_ERROR, "Output sockets cannot be multi-input"); + return nullptr; + } + bNodeTree *ntree = reinterpret_cast(id); bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_OUT, type, identifier, name); @@ -9929,6 +9939,8 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i parm = RNA_def_string(func, "name", nullptr, MAX_NAME, "Name", ""); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); RNA_def_string(func, "identifier", nullptr, MAX_NAME, "Identifier", "Unique socket identifier"); + RNA_def_boolean( + func, "use_multi_input", false, "", "Make the socket a multi-input. Only valid for inputs"); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); RNA_def_function_return(func, parm);