Fix #105601: Remove duplicates when inserting links into multi inputs

Fix a regression that allowed to create several links between an
output socket and a multi input socket either by inserting
links or using the link swap feature.

This regression was caused by the link swapping feature
introduced in commit 89aae4ac82.

Pull Request: https://projects.blender.org/blender/blender/pulls/105631
This commit is contained in:
Leon Schittek 2023-03-11 08:27:56 +01:00
parent fe58ccfafb
commit 7d22b11352

@ -898,27 +898,31 @@ static void displace_links(bNodeTree *ntree, const bNode *node, bNodeLink *inser
bNodeSocket *replacement_socket = node_find_linkable_socket(*ntree, node, linked_socket); bNodeSocket *replacement_socket = node_find_linkable_socket(*ntree, node, linked_socket);
if (linked_socket->is_input()) { if (linked_socket->is_input()) {
if (linked_socket->limit + 1 < nodeSocketLinkLimit(linked_socket)) { BLI_assert(!linked_socket->is_multi_input());
ntree->ensure_topology_cache();
bNodeLink *displaced_link = linked_socket->runtime->directly_linked_links.first();
if (!replacement_socket) {
nodeRemLink(ntree, displaced_link);
return; return;
} }
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { displaced_link->tosock = replacement_socket;
if (link->tosock == linked_socket) {
if (!replacement_socket) { if (replacement_socket->is_multi_input()) {
nodeRemLink(ntree, link); /* Check for duplicate links when linking to multi input sockets. */
BKE_ntree_update_tag_link_removed(ntree); for (bNodeLink *existing_link : replacement_socket->runtime->directly_linked_links) {
if (existing_link->fromsock == displaced_link->fromsock) {
nodeRemLink(ntree, displaced_link);
return; return;
} }
link->tosock = replacement_socket;
if (replacement_socket->is_multi_input()) {
link->multi_input_socket_index = node_socket_count_links(*ntree, *replacement_socket) -
1;
}
BKE_ntree_update_tag_link_changed(ntree);
return;
} }
const int multi_input_index = node_socket_count_links(*ntree, *replacement_socket) - 1;
displaced_link->multi_input_socket_index = multi_input_index;
} }
BKE_ntree_update_tag_link_changed(ntree);
return;
} }
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
@ -976,29 +980,46 @@ static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTre
{ {
bNodeSocket &linked_socket = *nldrag.hovered_socket; bNodeSocket &linked_socket = *nldrag.hovered_socket;
const int link_count = node_socket_count_links(ntree, linked_socket); int link_count = node_socket_count_links(ntree, linked_socket);
const int link_limit = nodeSocketLinkLimit(&linked_socket); const int link_limit = nodeSocketLinkLimit(&linked_socket);
Set<bNodeLink *> links_to_remove;
if (link_count < link_limit) { ntree.ensure_topology_cache();
return;
}
if (linked_socket.is_input()) { /* Remove duplicate links first. */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { for (const bNodeLink dragged_link : nldrag.links) {
if (link->tosock == &linked_socket) { if (linked_socket.is_input()) {
nodeRemLink(&ntree, link); for (bNodeLink *link : linked_socket.runtime->directly_linked_links) {
return; const bool duplicate_link = link->fromsock == dragged_link.fromsock;
if (duplicate_link) {
links_to_remove.add(link);
link_count--;
}
}
}
else {
for (bNodeLink *link : linked_socket.runtime->directly_linked_links) {
const bool duplicate_link = link->tosock == dragged_link.tosock;
if (duplicate_link) {
links_to_remove.add(link);
link_count--;
}
} }
} }
} }
else {
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { for (bNodeLink *link : linked_socket.runtime->directly_linked_links) {
if (link->fromsock == &linked_socket) { const bool link_limit_exceeded = !(link_count < link_limit);
nodeRemLink(&ntree, link); if (link_limit_exceeded) {
return; if (links_to_remove.add(link)) {
link_count--;
} }
} }
} }
for (bNodeLink *link : links_to_remove) {
nodeRemLink(&ntree, link);
}
} }
static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag) static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag)