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);
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<bNodeLink *> 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)