1
0
mirror of https://github.com/Siccity/xNode.git synced 2025-12-20 17:26:02 +08:00

Added public overrides for custom NodePort CanConnect conditions in GraphEditor

This commit is contained in:
Thor Brigsted 2022-09-21 13:53:28 +02:00
parent fa62765daa
commit 0e7e4aa254
3 changed files with 22 additions and 15 deletions

View File

@ -221,7 +221,7 @@ namespace XNodeEditor {
//Port drag release //Port drag release
if (IsDraggingPort) { if (IsDraggingPort) {
// If connection is valid, save it // If connection is valid, save it
if (draggedOutputTarget != null && draggedOutput.CanConnectTo(draggedOutputTarget)) { if (draggedOutputTarget != null && graphEditor.CanConnect(draggedOutput, draggedOutputTarget)) {
XNode.Node node = draggedOutputTarget.node; XNode.Node node = draggedOutputTarget.node;
if (graph.nodes.Count != 0) draggedOutput.Connect(draggedOutputTarget); if (graph.nodes.Count != 0) draggedOutput.Connect(draggedOutputTarget);
@ -553,12 +553,9 @@ namespace XNodeEditor {
public void AutoConnect(XNode.Node node) { public void AutoConnect(XNode.Node node) {
if (autoConnectOutput == null) return; if (autoConnectOutput == null) return;
// Find input port of same type // Find compatible input port
XNode.NodePort inputPort = node.Ports.FirstOrDefault(x => x.IsInput && x.ValueType == autoConnectOutput.ValueType); XNode.NodePort inputPort = node.Ports.FirstOrDefault(x => x.IsInput && graphEditor.CanConnect(autoConnectOutput, x));
// Fallback to input port if (inputPort != null) autoConnectOutput.Connect(inputPort);
if (inputPort == null) inputPort = node.Ports.FirstOrDefault(x => x.IsInput);
// Autoconnect if connection is compatible
if (inputPort != null && inputPort.CanConnectTo(autoConnectOutput)) autoConnectOutput.Connect(inputPort);
// Save changes // Save changes
EditorUtility.SetDirty(graph); EditorUtility.SetDirty(graph);

View File

@ -59,6 +59,13 @@ namespace XNodeEditor {
return 0; return 0;
} }
/// <summary>
/// Called before connecting two ports in the graph view to see if the output port is compatible with the input port
/// </summary>
public virtual bool CanConnect(XNode.NodePort output, XNode.NodePort input) {
return output.CanConnectTo(input);
}
/// <summary> /// <summary>
/// Add items for the context menu when right-clicking this node. /// Add items for the context menu when right-clicking this node.
/// Override to add custom menu items. /// Override to add custom menu items.

View File

@ -70,20 +70,23 @@ namespace XNode {
for (int i = 0; i < reconnectConnections.Count; i++) { for (int i = 0; i < reconnectConnections.Count; i++) {
NodePort connection = reconnectConnections[i]; NodePort connection = reconnectConnections[i];
if (connection == null) continue; if (connection == null) continue;
// CAVEAT: Ports connected under special conditions defined in graphEditor.CanConnect overrides will not auto-connect.
// To fix this, this code would need to be moved to an editor script and call graphEditor.CanConnect instead of port.CanConnectTo.
// This is only a problem in the rare edge case where user is using non-standard CanConnect overrides and changes port type of an already connected port
if (port.CanConnectTo(connection)) port.Connect(connection); if (port.CanConnectTo(connection)) port.Connect(connection);
} }
} }
ports.Add(staticPort.fieldName, port); ports.Add(staticPort.fieldName, port);
} }
} }
// Finally, make sure dynamic list port settings correspond to the settings of their "backing port" // Finally, make sure dynamic list port settings correspond to the settings of their "backing port"
foreach (NodePort listPort in dynamicListPorts) { foreach (NodePort listPort in dynamicListPorts) {
// At this point we know that ports here are dynamic list ports // At this point we know that ports here are dynamic list ports
// which have passed name/"backing port" checks, ergo we can proceed more safely. // which have passed name/"backing port" checks, ergo we can proceed more safely.
string backingPortName = listPort.fieldName.Split(' ')[0]; string backingPortName = listPort.fieldName.Split(' ')[0];
NodePort backingPort = staticPorts[backingPortName]; NodePort backingPort = staticPorts[backingPortName];
// Update port constraints. Creating a new port instead will break the editor, mandating the need for setters. // Update port constraints. Creating a new port instead will break the editor, mandating the need for setters.
listPort.ValueType = GetBackingValueType(backingPort.ValueType); listPort.ValueType = GetBackingValueType(backingPort.ValueType);
listPort.direction = backingPort.direction; listPort.direction = backingPort.direction;
@ -95,7 +98,7 @@ namespace XNode {
/// <summary> /// <summary>
/// Extracts the underlying types from arrays and lists, the only collections for dynamic port lists /// Extracts the underlying types from arrays and lists, the only collections for dynamic port lists
/// currently supported. If the given type is not applicable (i.e. if the dynamic list port was not /// currently supported. If the given type is not applicable (i.e. if the dynamic list port was not
/// defined as an array or a list), returns the given type itself. /// defined as an array or a list), returns the given type itself.
/// </summary> /// </summary>
private static System.Type GetBackingValueType(System.Type portValType) { private static System.Type GetBackingValueType(System.Type portValType) {
if (portValType.HasElementType) { if (portValType.HasElementType) {
@ -114,10 +117,10 @@ namespace XNode {
// Thus, we need to check for attributes... (but at least we don't need to look at all fields this time) // Thus, we need to check for attributes... (but at least we don't need to look at all fields this time)
string[] fieldNameParts = port.fieldName.Split(' '); string[] fieldNameParts = port.fieldName.Split(' ');
if (fieldNameParts.Length != 2) return false; if (fieldNameParts.Length != 2) return false;
FieldInfo backingPortInfo = port.node.GetType().GetField(fieldNameParts[0]); FieldInfo backingPortInfo = port.node.GetType().GetField(fieldNameParts[0]);
if (backingPortInfo == null) return false; if (backingPortInfo == null) return false;
object[] attribs = backingPortInfo.GetCustomAttributes(true); object[] attribs = backingPortInfo.GetCustomAttributes(true);
return attribs.Any(x => { return attribs.Any(x => {
Node.InputAttribute inputAttribute = x as Node.InputAttribute; Node.InputAttribute inputAttribute = x as Node.InputAttribute;
@ -126,7 +129,7 @@ namespace XNode {
outputAttribute != null && outputAttribute.dynamicPortList; outputAttribute != null && outputAttribute.dynamicPortList;
}); });
} }
/// <summary> Cache node types </summary> /// <summary> Cache node types </summary>
private static void BuildCache() { private static void BuildCache() {
portDataCache = new PortDataCache(); portDataCache = new PortDataCache();
@ -196,10 +199,10 @@ namespace XNode {
portDataCache[nodeType].Add(new NodePort(fieldInfo[i])); portDataCache[nodeType].Add(new NodePort(fieldInfo[i]));
} }
if(formerlySerializedAsAttribute != null) { if (formerlySerializedAsAttribute != null) {
if (formerlySerializedAsCache == null) formerlySerializedAsCache = new Dictionary<System.Type, Dictionary<string, string>>(); if (formerlySerializedAsCache == null) formerlySerializedAsCache = new Dictionary<System.Type, Dictionary<string, string>>();
if (!formerlySerializedAsCache.ContainsKey(nodeType)) formerlySerializedAsCache.Add(nodeType, new Dictionary<string, string>()); if (!formerlySerializedAsCache.ContainsKey(nodeType)) formerlySerializedAsCache.Add(nodeType, new Dictionary<string, string>());
if (formerlySerializedAsCache[nodeType].ContainsKey(formerlySerializedAsAttribute.oldName)) Debug.LogError("Another FormerlySerializedAs with value '" + formerlySerializedAsAttribute.oldName + "' already exist on this node."); if (formerlySerializedAsCache[nodeType].ContainsKey(formerlySerializedAsAttribute.oldName)) Debug.LogError("Another FormerlySerializedAs with value '" + formerlySerializedAsAttribute.oldName + "' already exist on this node.");
else formerlySerializedAsCache[nodeType].Add(formerlySerializedAsAttribute.oldName, fieldInfo[i].Name); else formerlySerializedAsCache[nodeType].Add(formerlySerializedAsAttribute.oldName, fieldInfo[i].Name);
} }