Fix #142636: Crash with node interface that's an input and an ouput
For a brief period it was possible to create these node interface sockets that were both inputs and outputs. Nowadays we're implementing the row-alignment in a different way, and we expect the input and output status to be mutually exclusive. This PR adds versioning to properly split such sockets. The implementation relies on the unique identifier space being separate for the input and output sockets. Pull Request: https://projects.blender.org/blender/blender/pulls/144807
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 63
|
||||
#define BLENDER_FILE_SUBVERSION 64
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -1698,6 +1698,63 @@ void do_versions_after_linking_500(FileData *fd, Main *bmain)
|
||||
*/
|
||||
}
|
||||
|
||||
static void remove_in_and_out_node_panel_recursive(bNodeTreeInterfacePanel &panel)
|
||||
{
|
||||
using namespace blender;
|
||||
const Span old_sockets(panel.items_array, panel.items_num);
|
||||
|
||||
Vector<bNodeTreeInterfaceItem *> new_sockets;
|
||||
for (bNodeTreeInterfaceItem *item : old_sockets) {
|
||||
if (item->item_type == NODE_INTERFACE_PANEL) {
|
||||
remove_in_and_out_node_panel_recursive(*reinterpret_cast<bNodeTreeInterfacePanel *>(item));
|
||||
continue;
|
||||
}
|
||||
bNodeTreeInterfaceSocket *socket = reinterpret_cast<bNodeTreeInterfaceSocket *>(item);
|
||||
constexpr int in_and_out = NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT;
|
||||
if ((socket->flag & in_and_out) != in_and_out) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bNodeTreeInterfaceSocket *new_output = MEM_callocN<bNodeTreeInterfaceSocket>(__func__);
|
||||
new_output->item.item_type = NODE_INTERFACE_SOCKET;
|
||||
new_output->name = BLI_strdup_null(socket->name);
|
||||
new_output->description = BLI_strdup_null(socket->description);
|
||||
new_output->socket_type = BLI_strdup_null(socket->socket_type);
|
||||
new_output->flag = socket->flag & ~NODE_INTERFACE_SOCKET_INPUT;
|
||||
new_output->attribute_domain = socket->attribute_domain;
|
||||
new_output->default_input = socket->default_input;
|
||||
new_output->default_attribute_name = BLI_strdup_null(socket->default_attribute_name);
|
||||
new_output->identifier = BLI_strdup(socket->identifier);
|
||||
if (socket->properties) {
|
||||
new_output->properties = IDP_CopyProperty_ex(socket->properties,
|
||||
LIB_ID_CREATE_NO_USER_REFCOUNT);
|
||||
}
|
||||
new_output->structure_type = socket->structure_type;
|
||||
new_sockets.append(reinterpret_cast<bNodeTreeInterfaceItem *>(new_output));
|
||||
|
||||
socket->flag &= ~NODE_INTERFACE_SOCKET_OUTPUT;
|
||||
}
|
||||
|
||||
if (new_sockets.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
new_sockets.extend(old_sockets);
|
||||
VectorData new_socket_data = new_sockets.release();
|
||||
MEM_freeN(panel.items_array);
|
||||
panel.items_array = new_socket_data.data;
|
||||
panel.items_num = new_socket_data.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix node interface sockest that could become both inputs and outputs before the current design
|
||||
* was settled on.
|
||||
*/
|
||||
static void remove_in_and_out_node_interface(bNodeTree &node_tree)
|
||||
{
|
||||
remove_in_and_out_node_panel_recursive(node_tree.tree_interface.root_panel);
|
||||
}
|
||||
|
||||
void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
||||
{
|
||||
using namespace blender;
|
||||
@@ -2335,6 +2392,13 @@ void blo_do_versions_500(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 64)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
|
||||
remove_in_and_out_node_interface(*node_tree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
||||
Reference in New Issue
Block a user