diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 97ab6b7786c..6cd0705a402 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -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); 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; } - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { - if (link->tosock == linked_socket) { - if (!replacement_socket) { - nodeRemLink(ntree, link); - BKE_ntree_update_tag_link_removed(ntree); + displaced_link->tosock = replacement_socket; + + if (replacement_socket->is_multi_input()) { + /* Check for duplicate links when linking to multi input sockets. */ + for (bNodeLink *existing_link : replacement_socket->runtime->directly_linked_links) { + if (existing_link->fromsock == displaced_link->fromsock) { + nodeRemLink(ntree, displaced_link); 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) { @@ -976,29 +980,46 @@ static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTre { 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); + Set links_to_remove; - if (link_count < link_limit) { - return; - } + ntree.ensure_topology_cache(); - if (linked_socket.is_input()) { - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { - if (link->tosock == &linked_socket) { - nodeRemLink(&ntree, link); - return; + /* Remove duplicate links first. */ + for (const bNodeLink dragged_link : nldrag.links) { + if (linked_socket.is_input()) { + for (bNodeLink *link : linked_socket.runtime->directly_linked_links) { + 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) { - if (link->fromsock == &linked_socket) { - nodeRemLink(&ntree, link); - return; + + for (bNodeLink *link : linked_socket.runtime->directly_linked_links) { + const bool link_limit_exceeded = !(link_count < link_limit); + if (link_limit_exceeded) { + 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)