// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using System.Collections.Generic;
using System.Linq;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
namespace Doozy.Runtime.Nody
{
/// Utility methods for the Nody system
public static class NodyUtils
{
/// Check if a port is connected to one of the ports of the given node
/// Target port
/// Target node
/// True if the given port (id) is found in the node's connections, false otherwise
public static bool IsPortConnectedToNode(FlowPort port, FlowNode node)
{
if (port == null) return false; //null port -> nope
if (node == null) return false; //null node -> nope
List connections =
port.direction switch
{
PortDirection.Input => node.outputConnections,
PortDirection.Output => node.inputConnections,
_ => throw new ArgumentOutOfRangeException()
};
return connections.Contains(port.portId);
}
/// Check if two nodes have are connected
/// Node 1
/// Node 2
/// True if at least one port from n1 is connected to another port in n2, false otherwise
public static bool IsNodeConnectedToNode(FlowNode n1, FlowNode n2)
{
if (n1 == null) return false; //null node -> nope
if (n2 == null) return false; //null node -> nope
return
n1.ports.Any(port => IsPortConnectedToNode(port, n2)) ||
n2.ports.Any(port => IsPortConnectedToNode(port, n1));
}
/// Check if a connection can be established between two ports
/// Port 1
/// Port 2
/// True if the ports can connect, false otherwise
public static bool CanConnect(FlowPort p1, FlowPort p2)
{
if (p1 == null) return false; //port is null -> stop
if (p2 == null) return false; //port is null -> stop
if (p1 == p2) return false; //port cannot connect to itself -> stop
if (p1.IsConnectedToPort(p2.portId)) return false; //ports are already connected -> stop
if (p1.direction == p2.direction) return false; //ports have the same direction -> stop
if (p1.portId == p2.portId) return false; //ports have the same id -> stop (wtf moment)
if (p1.nodeId == p2.nodeId) return false; //ports belong to the same node -> stop
return true; //allow connection
}
/// Remove all connections for the given port
/// Target port
/// Parent graph
/// True if the operation was successful, false otherwise
public static bool DisconnectPort(FlowPort port, FlowGraph graph)
{
if (port == null) return false; //null port -> cannot disconnect
if (graph == null) return false; //null graph -> cannot disconnect
List ports =
port.direction switch
{
PortDirection.Input => graph.outputPorts,
PortDirection.Output => graph.inputPorts,
_ => throw new ArgumentOutOfRangeException()
};
ports.ForEach(p =>
{
p.RemoveConnection(port.portId);
FlowPort otherPort = graph.GetPortById(port.portId);
p.onDisconnected?.Invoke(otherPort);
otherPort.onDisconnected?.Invoke(p);
});
port.connections.Clear();
return true;
}
/// Disconnect the given ports
/// Port 1
/// Port 2
/// True if the operation was successful, false otherwise
public static bool DisconnectPortFromPort(FlowPort p1, FlowPort p2)
{
if (p1 == null) return false; //null port -> cannot disconnect
if (p2 == null) return false; //null port -> cannot disconnect
if (!p1.IsConnectedToPort(p2.portId)) return false; //not connected -> cannot disconnect
p1.RemoveConnection(p2.portId);
p1.onDisconnected?.Invoke(p2);
p2.RemoveConnection(p1.portId);
p2.onDisconnected?.Invoke(p1);
return true;
}
/// Remove all connections from the target port to the given node
/// Target port
/// Target node
/// True if the operation was successful, false otherwise
public static bool DisconnectPortFromNode(FlowPort port, FlowNode node)
{
if (port == null) return false; //null port -> cannot disconnect
if (node == null) return false; //null node -> cannot disconnect
List ports =
port.direction switch
{
PortDirection.Input => node.outputPorts,
PortDirection.Output => node.inputPorts,
_ => throw new ArgumentOutOfRangeException()
};
ports.ForEach(nodePort =>
{
nodePort.RemoveConnection(port.portId);
nodePort.onDisconnected?.Invoke(port);
port.RemoveConnection(nodePort.portId);
port.onDisconnected?.Invoke(nodePort);
});
return true;
}
/// Remove all connections from the given node
/// Target node
/// Parent graph
/// True if the operation was successful, false otherwise
public static bool DisconnectNode(FlowNode node, FlowGraph graph)
{
if (node == null) return false; //null node -> cannot disconnect
if (graph == null) return false; //null graph -> cannot disconnect
node.ports.ForEach(port =>
{
DisconnectPort(port, graph);
});
return true;
}
/// Remove all connections between the two nodes
/// Node 1
/// Node 2
/// True if the operation was successful, false otherwise
public static bool DisconnectNodeFromNode(FlowNode n1, FlowNode n2)
{
if (n1 == null) return false; //null node -> cannot disconnect
if (n2 == null) return false; //null node -> cannot disconnect
n1.ports.ForEach(port => DisconnectPortFromNode(port, n2));
n2.ports.ForEach(port => DisconnectPortFromNode(port, n1));
return true;
}
}
}