diff --git a/Example/ExampleNodeGraph.asset b/Example/ExampleNodeGraph.asset
index 16e79ec..8e72bce 100644
Binary files a/Example/ExampleNodeGraph.asset and b/Example/ExampleNodeGraph.asset differ
diff --git a/Example/ExampleNodeGraph.asset.meta b/Example/ExampleNodeGraph.asset.meta
index 723ec56..6ec3d2f 100644
--- a/Example/ExampleNodeGraph.asset.meta
+++ b/Example/ExampleNodeGraph.asset.meta
@@ -1,6 +1,6 @@
fileFormatVersion: 2
-guid: 5398d565241ec2d489f41c368ca6cf24
-timeCreated: 1507498811
+guid: e8c47bc953732464a9bf3a76273d99ef
+timeCreated: 1507916591
licenseType: Free
NativeFormatImporter:
mainObjectFileID: 11400000
diff --git a/Example/Nodes/BaseNode.cs b/Example/Nodes/BaseNode.cs
deleted file mode 100644
index 26d4a8d..0000000
--- a/Example/Nodes/BaseNode.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using UnityEngine;
-
-[System.Serializable]
-public class BaseNode : Node {
-
- [Input] public string input;
- [Output] public string output;
- public bool concat;
- [TextArea]
- public string SomeString;
- [Header("New stuff")]
- public Color col;
- public AnimationCurve anim;
- public Vector3 vec;
-}
diff --git a/Example/Nodes/ConstantValue.cs b/Example/Nodes/ConstantValue.cs
new file mode 100644
index 0000000..b0b99ce
--- /dev/null
+++ b/Example/Nodes/ConstantValue.cs
@@ -0,0 +1,13 @@
+[System.Serializable]
+public class ConstantValue : ExampleNodeBase {
+ public float a;
+ [Output] public float value;
+
+ protected override void Init() {
+ name = "Constant Value";
+ }
+
+ public override object GetValue(NodePort port) {
+ return a;
+ }
+}
diff --git a/Example/Nodes/BaseNode.cs.meta b/Example/Nodes/ConstantValue.cs.meta
similarity index 76%
rename from Example/Nodes/BaseNode.cs.meta
rename to Example/Nodes/ConstantValue.cs.meta
index e525d86..e836841 100644
--- a/Example/Nodes/BaseNode.cs.meta
+++ b/Example/Nodes/ConstantValue.cs.meta
@@ -1,6 +1,6 @@
fileFormatVersion: 2
-guid: 23665941e8cd89a48b1272ac5fd6510c
-timeCreated: 1505462705
+guid: 707240ce8955a0240a7c0c4177d83bf5
+timeCreated: 1505937586
licenseType: Free
MonoImporter:
serializedVersion: 2
diff --git a/Example/Nodes/DisplayValue.cs b/Example/Nodes/DisplayValue.cs
index 01a2b0f..d19dd21 100644
--- a/Example/Nodes/DisplayValue.cs
+++ b/Example/Nodes/DisplayValue.cs
@@ -1,5 +1,6 @@
using UnityEngine;
-public class DisplayValue : Node {
+public class DisplayValue : ExampleNodeBase {
[Input] public float value;
+
}
diff --git a/Example/Nodes/Editor/DisplayValueEditor.cs b/Example/Nodes/Editor/DisplayValueEditor.cs
index b0f4643..0530c18 100644
--- a/Example/Nodes/Editor/DisplayValueEditor.cs
+++ b/Example/Nodes/Editor/DisplayValueEditor.cs
@@ -12,21 +12,7 @@ public class DisplayValueEditor : NodeEditor {
}
public float GetResult() {
- float result = 0f;
- NodePort port = target.GetInputByFieldName("value");
- if (port == null) return result;
- int connectionCount = port.ConnectionCount;
- for (int i = 0; i < connectionCount; i++) {
-
- NodePort connection = port.GetConnection(i);
- if (connection == null) continue;
-
- object obj = connection.GetValue();
- if (obj == null) continue;
-
- if (connection.type == typeof(int)) result += (int)obj;
- else if (connection.type == typeof(float)) result += (float)obj;
- }
- return result;
+ ExampleNodeBase t = target as ExampleNodeBase;
+ return t.GetInputFloat("value");
}
}
diff --git a/Example/Nodes/ExampleNodeBase.cs b/Example/Nodes/ExampleNodeBase.cs
new file mode 100644
index 0000000..c47cff0
--- /dev/null
+++ b/Example/Nodes/ExampleNodeBase.cs
@@ -0,0 +1,22 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class ExampleNodeBase : Node {
+
+ public float GetInputFloat(string fieldName) {
+ float result = 0f;
+ NodePort port = GetInputByFieldName(fieldName);
+ if (port == null) return result;
+ int connectionCount = port.ConnectionCount;
+ for (int i = 0; i < connectionCount; i++) {
+ NodePort connection = port.GetConnection(i);
+ if (connection == null) continue;
+ object obj = connection.GetValue();
+ if (obj == null) continue;
+ if (connection.type == typeof(int)) result += (int)obj;
+ else if (connection.type == typeof(float)) result += (float)obj;
+ }
+ return result;
+ }
+}
diff --git a/Scripts/Editor/NodeEditorToolbar.cs.meta b/Example/Nodes/ExampleNodeBase.cs.meta
similarity index 76%
rename from Scripts/Editor/NodeEditorToolbar.cs.meta
rename to Example/Nodes/ExampleNodeBase.cs.meta
index cc85b52..1cc1c43 100644
--- a/Scripts/Editor/NodeEditorToolbar.cs.meta
+++ b/Example/Nodes/ExampleNodeBase.cs.meta
@@ -1,6 +1,6 @@
fileFormatVersion: 2
-guid: fa774a466fc664148b43879d282ea071
-timeCreated: 1505932458
+guid: 923bada49e668fd4a98b04fcb49999d7
+timeCreated: 1507917099
licenseType: Free
MonoImporter:
serializedVersion: 2
diff --git a/Example/Nodes/MathNode.cs b/Example/Nodes/MathNode.cs
index 32aa322..475698d 100644
--- a/Example/Nodes/MathNode.cs
+++ b/Example/Nodes/MathNode.cs
@@ -1,9 +1,9 @@
using UnityEngine;
[System.Serializable]
-public class MathNode : Node {
- public float a;
- public float b;
+public class MathNode : ExampleNodeBase {
+ [Input] public float c;
+ [Input] public float b;
[Output] public float result;
public enum MathType { Add, Subtract, Multiply, Divide}
public MathType mathType = MathType.Add;
@@ -13,6 +13,9 @@ public class MathNode : Node {
}
public override object GetValue(NodePort port) {
+ float a = GetInputFloat("c");
+ float b = GetInputFloat("b");
+
switch(port.fieldName) {
case "result":
switch(mathType) {
@@ -25,8 +28,4 @@ public class MathNode : Node {
}
return 0f;
}
-
- public override void OnCreateConnection(NodePort from, NodePort to) {
-
- }
}
diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs
index 901feb5..1bde7d3 100644
--- a/Scripts/Editor/NodeEditor.cs
+++ b/Scripts/Editor/NodeEditor.cs
@@ -63,14 +63,14 @@ public class NodeEditor {
/// Draw node port GUI using automatic layouting. Returns port handle position.
protected Vector2 DrawNodePortGUI(NodePort port) {
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputPort : NodeEditorResources.styles.outputPort;
- Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.name.PrettifyCamelCase()), style);
+ Rect rect = GUILayoutUtility.GetRect(new GUIContent(port.fieldName.PrettifyCamelCase()), style);
return DrawNodePortGUI(rect, port);
}
/// Draw node port GUI in rect. Returns port handle position.
protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputPort : NodeEditorResources.styles.outputPort;
- GUI.Label(rect, new GUIContent(port.name.PrettifyCamelCase()), style);
+ GUI.Label(rect, new GUIContent(port.fieldName.PrettifyCamelCase()), style);
Vector2 handlePoint = rect.center;
diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs
index cf0c44e..4a7e617 100644
--- a/Scripts/Editor/NodeEditorGUI.cs
+++ b/Scripts/Editor/NodeEditorGUI.cs
@@ -15,7 +15,6 @@ public partial class NodeEditorWindow {
DrawConnections();
DrawDraggedConnection();
DrawNodes();
- DrawToolbar();
GUI.matrix = m;
}
@@ -128,7 +127,9 @@ public partial class NodeEditorWindow {
if (!portConnectionPoints.ContainsKey(output)) continue;
Vector2 from = _portConnectionPoints[output].center;
for (int k = 0; k < output.ConnectionCount; k++) {
+
NodePort input = output.GetConnection(k);
+ if (input == null) return; //If a script has been updated and the port doesn't exist, it is removed and null is returned. If this happens, return.
Vector2 to = _portConnectionPoints[input].center;
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
}
diff --git a/Scripts/Editor/NodeEditorToolbar.cs b/Scripts/Editor/NodeEditorToolbar.cs
deleted file mode 100644
index eb89b6f..0000000
--- a/Scripts/Editor/NodeEditorToolbar.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
-using UnityEditor;
-
-public partial class NodeEditorWindow {
-
- public void DrawToolbar() {
- EditorGUILayout.BeginHorizontal("Toolbar");
-
- if (DropdownButton("File", 50)) FileContextMenu();
- if (DropdownButton("Edit", 50)) EditContextMenu();
- if (DropdownButton("View", 50)) { }
- if (DropdownButton("Settings", 70)) { }
- if (DropdownButton("Tools", 50)) ToolsContextMenu();
-
- //Draw hover info
- if (Event.current.type == EventType.Layout || Event.current.type == EventType.Repaint) {
- if (IsHoveringNode) {
- GUILayout.Space(20);
- string hoverInfo = hoveredNode.GetType().ToString();
- if (IsHoveringPort) hoverInfo += " > " + hoveredPort.name;
- GUILayout.Label(hoverInfo);
- }
- }
-
- // Make the toolbar extend all throughout the window extension.
- GUILayout.FlexibleSpace();
-
- EditorGUILayout.EndHorizontal();
- }
-
- public void FileContextMenu() {
- GenericMenu contextMenu = new GenericMenu();
-
- contextMenu.AddItem(new GUIContent("Save"), false, Save);
- contextMenu.AddItem(new GUIContent("Save As"), false, SaveAs);
-
- contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
- }
-
- public void EditContextMenu() {
- GenericMenu contextMenu = new GenericMenu();
- contextMenu.AddItem(new GUIContent("Clear"), false, () => graph.Clear());
-
- contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
- }
-
- public void ToolsContextMenu() {
- GenericMenu contextMenu = new GenericMenu();
- contextMenu.AddItem(new GUIContent("Debug Custom Node Editors"), false, () => CacheCustomNodeEditors());
-
- contextMenu.DropDown(new Rect(5f, 17f, 0f, 0f));
- }
-}
diff --git a/Scripts/Editor/NodeEditorUtilities.cs b/Scripts/Editor/NodeEditorUtilities.cs
index 9d683bd..78ee295 100644
--- a/Scripts/Editor/NodeEditorUtilities.cs
+++ b/Scripts/Editor/NodeEditorUtilities.cs
@@ -41,6 +41,7 @@ public static class NodeEditorUtilities {
/// Return color based on type
public static Color GetTypeColor(Type type) {
+ if (type == null) return Color.gray;
UnityEngine.Random.InitState(type.Name.GetHashCode());
return new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
}
diff --git a/Scripts/Node.cs b/Scripts/Node.cs
index 49f62d0..60db807 100644
--- a/Scripts/Node.cs
+++ b/Scripts/Node.cs
@@ -19,17 +19,11 @@ public abstract class Node : ScriptableObject {
public int InputCount { get { return inputs.Count; } }
public int OutputCount { get { return outputs.Count; } }
- protected Node() {
- CachePorts(); //Cache the ports at creation time so we don't have to use reflection at runtime
- }
-
protected void OnEnable() {
- VerifyConnections();
- CachePorts();
+ GetPorts();
Init();
}
-
/// Checks all connections for invalid references, and removes them.
public void VerifyConnections() {
for (int i = 0; i < InputCount; i++) {
@@ -47,21 +41,19 @@ public abstract class Node : ScriptableObject {
else return GetInputByFieldName(fieldName);
}
- /// Returns output port which matches fieldName
+ /// Returns output port which matches fieldName. Returns null if none found.
public NodePort GetOutputByFieldName(string fieldName) {
for (int i = 0; i < OutputCount; i++) {
if (outputs[i].fieldName == fieldName) return outputs[i];
}
- Debug.LogWarning("No outputs with fieldName '" + fieldName+"'");
return null;
}
- /// Returns input port which matches fieldName
+ /// Returns input port which matches. Returns null if none found.
public NodePort GetInputByFieldName(string fieldName) {
for (int i = 0; i < InputCount; i++) {
if (inputs[i].fieldName == fieldName) return inputs[i];
}
- Debug.LogWarning("No inputs with fieldName '" + fieldName+"'");
return null;
}
@@ -117,45 +109,7 @@ public abstract class Node : ScriptableObject {
}
}
- /// Use reflection to find all fields with or , and write to and
- private void CachePorts() {
- List inputPorts = new List();
- List outputPorts = new List();
-
- System.Reflection.FieldInfo[] fieldInfo = GetType().GetFields();
- for (int i = 0; i < fieldInfo.Length; i++) {
-
- //Get InputAttribute and OutputAttribute
- object[] attribs = fieldInfo[i].GetCustomAttributes(false);
- InputAttribute inputAttrib = null;
- OutputAttribute outputAttrib = null;
- for (int k = 0; k < attribs.Length; k++) {
- if (attribs[k] is InputAttribute) inputAttrib = attribs[k] as InputAttribute;
- else if (attribs[k] is OutputAttribute) outputAttrib = attribs[k] as OutputAttribute;
- }
-
- if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo + " cannot be both input and output.");
- else if (inputAttrib != null) inputPorts.Add(new NodePort(fieldInfo[i], this));
- else if (outputAttrib != null) outputPorts.Add(new NodePort(fieldInfo[i], this));
- }
-
- //Remove
- for (int i = inputs.Count-1; i >= 0; i--) {
- //If input nodeport does not exist, remove it
- if (!inputPorts.Any(x => inputs[i].fieldName == x.fieldName)) inputs.RemoveAt(i);
- }
- for (int i = outputs.Count - 1; i >= 0; i--) {
- //If output nodeport does not exist, remove it
- if (!outputPorts.Any(x => outputs[i].fieldName == x.fieldName)) outputs.RemoveAt(i);
- }
- //Add
- for (int i = 0; i < inputPorts.Count; i++) {
- //If inputports contains a new port, add it
- if (!inputs.Any(x => x.fieldName == inputPorts[i].fieldName)) inputs.Add(inputPorts[i]);
- }
- for (int i = 0; i < outputPorts.Count; i++) {
- //If inputports contains a new port, add it
- if (!outputs.Any(x => x.fieldName == outputPorts[i].fieldName)) outputs.Add(outputPorts[i]);
- }
+ private void GetPorts() {
+ NodeDataCache.UpdatePorts(this, inputs, outputs);
}
}
diff --git a/Scripts/NodeDataCache.cs b/Scripts/NodeDataCache.cs
new file mode 100644
index 0000000..f14fb9f
--- /dev/null
+++ b/Scripts/NodeDataCache.cs
@@ -0,0 +1,115 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Reflection;
+using System.Linq;
+using UnityEditor;
+
+/// Precaches reflection data in editor so we won't have to do it runtime
+public static class NodeDataCache {
+ private static PortDataCache portDataCache;
+ private static bool Initialized { get { return portDataCache != null; } }
+
+ /// Checks for invalid and removes them.
+ /// Checks for missing ports and adds them.
+ /// Checks for invalid connections and removes them.
+ public static void UpdatePorts(Node node, List inputs, List outputs) {
+ if (!Initialized) BuildCache();
+
+ List inputPorts = new List();
+ List outputPorts = new List();
+
+ System.Type nodeType = node.GetType();
+ inputPorts = new List();
+ outputPorts = new List();
+ if (!portDataCache.ContainsKey(nodeType)) return;
+ for (int i = 0; i < portDataCache[nodeType].Count; i++) {
+ if (portDataCache[nodeType][i].direction == NodePort.IO.Input) inputPorts.Add(new NodePort(portDataCache[nodeType][i], node));
+ else outputPorts.Add(new NodePort(portDataCache[nodeType][i], node));
+ }
+
+ for (int i = inputs.Count-1; i >= 0; i--) {
+ int index = inputPorts.FindIndex(x => inputs[i].fieldName == x.fieldName);
+ //If input nodeport does not exist, remove it
+ if (index == -1) inputs.RemoveAt(i);
+ //If input nodeport does exist, update it
+ else inputs[i].type = inputPorts[index].type;
+ }
+ for (int i = outputs.Count - 1; i >= 0; i--) {
+ int index = outputPorts.FindIndex(x => outputs[i].fieldName == x.fieldName);
+ //If output nodeport does not exist, remove it
+ if (index == -1) outputs.RemoveAt(i);
+ //If output nodeport does exist, update it
+ else outputs[i].type = outputPorts[index].type;
+ }
+ //Add
+ for (int i = 0; i < inputPorts.Count; i++) {
+ //If inputports contains a new port, add it
+ if (!inputs.Any(x => x.fieldName == inputPorts[i].fieldName)) inputs.Add(inputPorts[i]);
+ }
+ for (int i = 0; i < outputPorts.Count; i++) {
+ //If inputports contains a new port, add it
+ if (!outputs.Any(x => x.fieldName == outputPorts[i].fieldName)) outputs.Add(outputPorts[i]);
+ }
+ }
+
+ private static void BuildCache() {
+ portDataCache = new PortDataCache();
+ System.Type baseType = typeof(Node);
+ Assembly assembly = Assembly.GetAssembly(baseType);
+ System.Type[] nodeTypes = assembly.GetTypes().Where(t =>
+ !t.IsAbstract &&
+ baseType.IsAssignableFrom(t)
+ ).ToArray();
+
+ for (int i = 0; i < nodeTypes.Length; i++) {
+ CachePorts(nodeTypes[i]);
+ }
+ }
+
+ private static void CachePorts(System.Type nodeType) {
+ System.Reflection.FieldInfo[] fieldInfo = nodeType.GetFields();
+ for (int i = 0; i < fieldInfo.Length; i++) {
+
+ //Get InputAttribute and OutputAttribute
+ object[] attribs = fieldInfo[i].GetCustomAttributes(false);
+ Node.InputAttribute inputAttrib = attribs.FirstOrDefault(x => x is Node.InputAttribute) as Node.InputAttribute;
+ Node.OutputAttribute outputAttrib = attribs.FirstOrDefault(x => x is Node.OutputAttribute) as Node.OutputAttribute;
+
+ if (inputAttrib == null && outputAttrib == null) continue;
+
+ if (inputAttrib != null && outputAttrib != null) Debug.LogError("Field " + fieldInfo + " cannot be both input and output.");
+ else {
+ if (!portDataCache.ContainsKey(nodeType)) portDataCache.Add(nodeType, new List());
+ portDataCache[nodeType].Add(new NodePort(fieldInfo[i]));
+ }
+ }
+ }
+
+ [System.Serializable]
+ private class PortDataCache : Dictionary>, ISerializationCallbackReceiver {
+ [SerializeField] private List keys = new List();
+ [SerializeField] private List> values = new List>();
+
+ // save the dictionary to lists
+ public void OnBeforeSerialize() {
+ keys.Clear();
+ values.Clear();
+ foreach (var pair in this) {
+ keys.Add(pair.Key);
+ values.Add(pair.Value);
+ }
+ }
+
+ // load dictionary from lists
+ public void OnAfterDeserialize() {
+ this.Clear();
+
+ if (keys.Count != values.Count)
+ throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable."));
+
+ for (int i = 0; i < keys.Count; i++)
+ this.Add(keys[i], values[i]);
+ }
+ }
+}
diff --git a/Scripts/NodeDataCache.cs.meta b/Scripts/NodeDataCache.cs.meta
new file mode 100644
index 0000000..34482f2
--- /dev/null
+++ b/Scripts/NodeDataCache.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 64ea6af1e195d024d8df0ead1921e517
+timeCreated: 1507566823
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs
index 58baa23..4c1d798 100644
--- a/Scripts/NodeGraph.cs
+++ b/Scripts/NodeGraph.cs
@@ -1,5 +1,4 @@
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
using UnityEngine;
using System;
@@ -50,17 +49,17 @@ public abstract class NodeGraph : ScriptableObject, ISerializationCallbackReceiv
}
public void OnAfterDeserialize() {
- for (int i = 0; i < nodes.Count; i++) {
+ /*for (int i = 0; i < nodes.Count; i++) {
nodes[i].graph = this;
- }
- VerifyConnections();
+ }*/
+ //VerifyConnections();
}
- /// Checks all connections for invalid references, and removes them.
+ /*/// Checks all connections for invalid references, and removes them.
public void VerifyConnections() {
for (int i = 0; i < nodes.Count; i++) {
nodes[i].VerifyConnections();
}
- }
+ }*/
}
diff --git a/Scripts/NodePort.cs b/Scripts/NodePort.cs
index dfef17c..1980935 100644
--- a/Scripts/NodePort.cs
+++ b/Scripts/NodePort.cs
@@ -18,23 +18,18 @@ public class NodePort {
public bool IsInput { get { return direction == IO.Input; } }
public bool IsOutput { get { return direction == IO.Output; } }
- public Node node { get; private set; }
- [SerializeField] public string name;
- public bool enabled { get { return _enabled; } set { _enabled = value; } }
public string fieldName { get { return _fieldName; } }
- [SerializeField] private List connections = new List();
+ [SerializeField] public Node node;
[SerializeField] private string _fieldName;
[SerializeField] public Type type;
- [SerializeField] private bool _enabled = true;
+ [SerializeField] private List connections = new List();
[SerializeField] private IO _direction;
- public NodePort(FieldInfo fieldInfo, Node node) {
+ public NodePort(FieldInfo fieldInfo) {
_fieldName = fieldInfo.Name;
- name = _fieldName;
type = fieldInfo.FieldType;
- this.node = node;
var attribs = fieldInfo.GetCustomAttributes(false);
for (int i = 0; i < attribs.Length; i++) {
@@ -43,6 +38,13 @@ public class NodePort {
}
}
+ public NodePort(NodePort nodePort, Node node) {
+ _fieldName = nodePort._fieldName;
+ type = nodePort.type;
+ this.node = node;
+ _direction = nodePort.direction;
+ }
+
/// Checks all connections for invalid references, and removes them.
public void VerifyConnections() {
for (int i = 0; i < connections.Count; i++) {
@@ -75,7 +77,17 @@ public class NodePort {
}
public NodePort GetConnection(int i) {
- return connections[i].Port;
+ //If the connection is broken for some reason, remove it.
+ if (connections[i].node == null || string.IsNullOrEmpty(connections[i].fieldName)) {
+ connections.RemoveAt(i);
+ return null;
+ }
+ NodePort port = connections[i].node.GetPortByFieldName(connections[i].fieldName);
+ if (port == null) {
+ connections.RemoveAt(i);
+ return null;
+ }
+ return port;
}
public bool IsConnectedTo(NodePort port) {
@@ -99,15 +111,15 @@ public class NodePort {
}
public void ClearConnections() {
- for (int i = 0; i < connections.Count; i++) {
- Disconnect(connections[i].Port);
+ while(connections.Count > 0) {
+ Disconnect(connections[0].Port);
}
}
[Serializable]
public class PortConnection {
- [SerializeField] public Node node;
[SerializeField] public string fieldName;
+ [SerializeField] public Node node;
public NodePort Port { get { return port != null ? port : port = GetPort(); } }
[NonSerialized] private NodePort port;
@@ -118,6 +130,7 @@ public class NodePort {
}
private NodePort GetPort() {
+
for (int i = 0; i < node.OutputCount; i++) {
if (node.outputs[i].fieldName == fieldName) return node.outputs[i];
}