mirror of
https://github.com/Siccity/xNode.git
synced 2025-12-21 01:36:03 +08:00
Merge branch 'development' of https://github.com/Siccity/UnityNodeEditorCore.git
This commit is contained in:
commit
e089f8fa7f
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 5398d565241ec2d489f41c368ca6cf24
|
guid: e8c47bc953732464a9bf3a76273d99ef
|
||||||
timeCreated: 1507498811
|
timeCreated: 1507916591
|
||||||
licenseType: Free
|
licenseType: Free
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
13
Example/Nodes/ConstantValue.cs
Normal file
13
Example/Nodes/ConstantValue.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 23665941e8cd89a48b1272ac5fd6510c
|
guid: 707240ce8955a0240a7c0c4177d83bf5
|
||||||
timeCreated: 1505462705
|
timeCreated: 1505937586
|
||||||
licenseType: Free
|
licenseType: Free
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class DisplayValue : Node {
|
public class DisplayValue : ExampleNodeBase {
|
||||||
[Input] public float value;
|
[Input] public float value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,21 +12,7 @@ public class DisplayValueEditor : NodeEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public float GetResult() {
|
public float GetResult() {
|
||||||
float result = 0f;
|
ExampleNodeBase t = target as ExampleNodeBase;
|
||||||
NodePort port = target.GetInputByFieldName("value");
|
return t.GetInputFloat("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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
Example/Nodes/ExampleNodeBase.cs
Normal file
22
Example/Nodes/ExampleNodeBase.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: fa774a466fc664148b43879d282ea071
|
guid: 923bada49e668fd4a98b04fcb49999d7
|
||||||
timeCreated: 1505932458
|
timeCreated: 1507917099
|
||||||
licenseType: Free
|
licenseType: Free
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@ -1,9 +1,9 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class MathNode : Node {
|
public class MathNode : ExampleNodeBase {
|
||||||
public float a;
|
[Input] public float c;
|
||||||
public float b;
|
[Input] public float b;
|
||||||
[Output] public float result;
|
[Output] public float result;
|
||||||
public enum MathType { Add, Subtract, Multiply, Divide}
|
public enum MathType { Add, Subtract, Multiply, Divide}
|
||||||
public MathType mathType = MathType.Add;
|
public MathType mathType = MathType.Add;
|
||||||
@ -13,6 +13,9 @@ public class MathNode : Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override object GetValue(NodePort port) {
|
public override object GetValue(NodePort port) {
|
||||||
|
float a = GetInputFloat("c");
|
||||||
|
float b = GetInputFloat("b");
|
||||||
|
|
||||||
switch(port.fieldName) {
|
switch(port.fieldName) {
|
||||||
case "result":
|
case "result":
|
||||||
switch(mathType) {
|
switch(mathType) {
|
||||||
@ -25,8 +28,4 @@ public class MathNode : Node {
|
|||||||
}
|
}
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCreateConnection(NodePort from, NodePort to) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,14 +63,14 @@ public class NodeEditor {
|
|||||||
/// <summary> Draw node port GUI using automatic layouting. Returns port handle position. </summary>
|
/// <summary> Draw node port GUI using automatic layouting. Returns port handle position. </summary>
|
||||||
protected Vector2 DrawNodePortGUI(NodePort port) {
|
protected Vector2 DrawNodePortGUI(NodePort port) {
|
||||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputPort : NodeEditorResources.styles.outputPort;
|
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);
|
return DrawNodePortGUI(rect, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Draw node port GUI in rect. Returns port handle position. </summary>
|
/// <summary> Draw node port GUI in rect. Returns port handle position. </summary>
|
||||||
protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
|
protected Vector2 DrawNodePortGUI(Rect rect, NodePort port) {
|
||||||
GUIStyle style = port.direction == NodePort.IO.Input ? NodeEditorResources.styles.inputPort : NodeEditorResources.styles.outputPort;
|
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;
|
Vector2 handlePoint = rect.center;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ public partial class NodeEditorWindow {
|
|||||||
DrawConnections();
|
DrawConnections();
|
||||||
DrawDraggedConnection();
|
DrawDraggedConnection();
|
||||||
DrawNodes();
|
DrawNodes();
|
||||||
DrawToolbar();
|
|
||||||
|
|
||||||
GUI.matrix = m;
|
GUI.matrix = m;
|
||||||
}
|
}
|
||||||
@ -128,7 +127,9 @@ public partial class NodeEditorWindow {
|
|||||||
if (!portConnectionPoints.ContainsKey(output)) continue;
|
if (!portConnectionPoints.ContainsKey(output)) continue;
|
||||||
Vector2 from = _portConnectionPoints[output].center;
|
Vector2 from = _portConnectionPoints[output].center;
|
||||||
for (int k = 0; k < output.ConnectionCount; k++) {
|
for (int k = 0; k < output.ConnectionCount; k++) {
|
||||||
|
|
||||||
NodePort input = output.GetConnection(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;
|
Vector2 to = _portConnectionPoints[input].center;
|
||||||
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
|
DrawConnection(from, to, NodeEditorUtilities.GetTypeColor(output.type));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -41,6 +41,7 @@ public static class NodeEditorUtilities {
|
|||||||
|
|
||||||
/// <summary> Return color based on type </summary>
|
/// <summary> Return color based on type </summary>
|
||||||
public static Color GetTypeColor(Type type) {
|
public static Color GetTypeColor(Type type) {
|
||||||
|
if (type == null) return Color.gray;
|
||||||
UnityEngine.Random.InitState(type.Name.GetHashCode());
|
UnityEngine.Random.InitState(type.Name.GetHashCode());
|
||||||
return new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
|
return new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,17 +19,11 @@ public abstract class Node : ScriptableObject {
|
|||||||
public int InputCount { get { return inputs.Count; } }
|
public int InputCount { get { return inputs.Count; } }
|
||||||
public int OutputCount { get { return outputs.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() {
|
protected void OnEnable() {
|
||||||
VerifyConnections();
|
GetPorts();
|
||||||
CachePorts();
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
||||||
public void VerifyConnections() {
|
public void VerifyConnections() {
|
||||||
for (int i = 0; i < InputCount; i++) {
|
for (int i = 0; i < InputCount; i++) {
|
||||||
@ -47,21 +41,19 @@ public abstract class Node : ScriptableObject {
|
|||||||
else return GetInputByFieldName(fieldName);
|
else return GetInputByFieldName(fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Returns output port which matches fieldName </summary>
|
/// <summary> Returns output port which matches fieldName. Returns null if none found. </summary>
|
||||||
public NodePort GetOutputByFieldName(string fieldName) {
|
public NodePort GetOutputByFieldName(string fieldName) {
|
||||||
for (int i = 0; i < OutputCount; i++) {
|
for (int i = 0; i < OutputCount; i++) {
|
||||||
if (outputs[i].fieldName == fieldName) return outputs[i];
|
if (outputs[i].fieldName == fieldName) return outputs[i];
|
||||||
}
|
}
|
||||||
Debug.LogWarning("No outputs with fieldName '" + fieldName+"'");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Returns input port which matches fieldName </summary>
|
/// <summary> Returns input port which matches. Returns null if none found. </summary>
|
||||||
public NodePort GetInputByFieldName(string fieldName) {
|
public NodePort GetInputByFieldName(string fieldName) {
|
||||||
for (int i = 0; i < InputCount; i++) {
|
for (int i = 0; i < InputCount; i++) {
|
||||||
if (inputs[i].fieldName == fieldName) return inputs[i];
|
if (inputs[i].fieldName == fieldName) return inputs[i];
|
||||||
}
|
}
|
||||||
Debug.LogWarning("No inputs with fieldName '" + fieldName+"'");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,45 +109,7 @@ public abstract class Node : ScriptableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Use reflection to find all fields with <see cref="InputAttribute"/> or <see cref="OutputAttribute"/>, and write to <see cref="inputs"/> and <see cref="outputs"/> </summary>
|
private void GetPorts() {
|
||||||
private void CachePorts() {
|
NodeDataCache.UpdatePorts(this, inputs, outputs);
|
||||||
List<NodePort> inputPorts = new List<NodePort>();
|
|
||||||
List<NodePort> outputPorts = new List<NodePort>();
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
115
Scripts/NodeDataCache.cs
Normal file
115
Scripts/NodeDataCache.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
/// <summary> Precaches reflection data in editor so we won't have to do it runtime </summary>
|
||||||
|
public static class NodeDataCache {
|
||||||
|
private static PortDataCache portDataCache;
|
||||||
|
private static bool Initialized { get { return portDataCache != null; } }
|
||||||
|
|
||||||
|
/// <summary> Checks for invalid and removes them.
|
||||||
|
/// Checks for missing ports and adds them.
|
||||||
|
/// Checks for invalid connections and removes them. </summary>
|
||||||
|
public static void UpdatePorts(Node node, List<NodePort> inputs, List<NodePort> outputs) {
|
||||||
|
if (!Initialized) BuildCache();
|
||||||
|
|
||||||
|
List<NodePort> inputPorts = new List<NodePort>();
|
||||||
|
List<NodePort> outputPorts = new List<NodePort>();
|
||||||
|
|
||||||
|
System.Type nodeType = node.GetType();
|
||||||
|
inputPorts = new List<NodePort>();
|
||||||
|
outputPorts = new List<NodePort>();
|
||||||
|
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<NodePort>());
|
||||||
|
portDataCache[nodeType].Add(new NodePort(fieldInfo[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
private class PortDataCache : Dictionary<System.Type, List<NodePort>>, ISerializationCallbackReceiver {
|
||||||
|
[SerializeField] private List<System.Type> keys = new List<System.Type>();
|
||||||
|
[SerializeField] private List<List<NodePort>> values = new List<List<NodePort>>();
|
||||||
|
|
||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Scripts/NodeDataCache.cs.meta
Normal file
12
Scripts/NodeDataCache.cs.meta
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 64ea6af1e195d024d8df0ead1921e517
|
||||||
|
timeCreated: 1507566823
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Collections;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -50,17 +49,17 @@ public abstract class NodeGraph : ScriptableObject, ISerializationCallbackReceiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void OnAfterDeserialize() {
|
public void OnAfterDeserialize() {
|
||||||
for (int i = 0; i < nodes.Count; i++) {
|
/*for (int i = 0; i < nodes.Count; i++) {
|
||||||
nodes[i].graph = this;
|
nodes[i].graph = this;
|
||||||
}
|
}*/
|
||||||
VerifyConnections();
|
//VerifyConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
/*/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
||||||
public void VerifyConnections() {
|
public void VerifyConnections() {
|
||||||
for (int i = 0; i < nodes.Count; i++) {
|
for (int i = 0; i < nodes.Count; i++) {
|
||||||
nodes[i].VerifyConnections();
|
nodes[i].VerifyConnections();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,23 +18,18 @@ public class NodePort {
|
|||||||
public bool IsInput { get { return direction == IO.Input; } }
|
public bool IsInput { get { return direction == IO.Input; } }
|
||||||
public bool IsOutput { get { return direction == IO.Output; } }
|
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; } }
|
public string fieldName { get { return _fieldName; } }
|
||||||
|
|
||||||
|
|
||||||
[SerializeField] private List<PortConnection> connections = new List<PortConnection>();
|
[SerializeField] public Node node;
|
||||||
[SerializeField] private string _fieldName;
|
[SerializeField] private string _fieldName;
|
||||||
[SerializeField] public Type type;
|
[SerializeField] public Type type;
|
||||||
[SerializeField] private bool _enabled = true;
|
[SerializeField] private List<PortConnection> connections = new List<PortConnection>();
|
||||||
[SerializeField] private IO _direction;
|
[SerializeField] private IO _direction;
|
||||||
|
|
||||||
public NodePort(FieldInfo fieldInfo, Node node) {
|
public NodePort(FieldInfo fieldInfo) {
|
||||||
_fieldName = fieldInfo.Name;
|
_fieldName = fieldInfo.Name;
|
||||||
name = _fieldName;
|
|
||||||
type = fieldInfo.FieldType;
|
type = fieldInfo.FieldType;
|
||||||
this.node = node;
|
|
||||||
|
|
||||||
var attribs = fieldInfo.GetCustomAttributes(false);
|
var attribs = fieldInfo.GetCustomAttributes(false);
|
||||||
for (int i = 0; i < attribs.Length; i++) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
/// <summary> Checks all connections for invalid references, and removes them. </summary>
|
||||||
public void VerifyConnections() {
|
public void VerifyConnections() {
|
||||||
for (int i = 0; i < connections.Count; i++) {
|
for (int i = 0; i < connections.Count; i++) {
|
||||||
@ -75,7 +77,17 @@ public class NodePort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NodePort GetConnection(int i) {
|
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) {
|
public bool IsConnectedTo(NodePort port) {
|
||||||
@ -99,15 +111,15 @@ public class NodePort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ClearConnections() {
|
public void ClearConnections() {
|
||||||
for (int i = 0; i < connections.Count; i++) {
|
while(connections.Count > 0) {
|
||||||
Disconnect(connections[i].Port);
|
Disconnect(connections[0].Port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class PortConnection {
|
public class PortConnection {
|
||||||
[SerializeField] public Node node;
|
|
||||||
[SerializeField] public string fieldName;
|
[SerializeField] public string fieldName;
|
||||||
|
[SerializeField] public Node node;
|
||||||
public NodePort Port { get { return port != null ? port : port = GetPort(); } }
|
public NodePort Port { get { return port != null ? port : port = GetPort(); } }
|
||||||
[NonSerialized] private NodePort port;
|
[NonSerialized] private NodePort port;
|
||||||
|
|
||||||
@ -118,6 +130,7 @@ public class NodePort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private NodePort GetPort() {
|
private NodePort GetPort() {
|
||||||
|
|
||||||
for (int i = 0; i < node.OutputCount; i++) {
|
for (int i = 0; i < node.OutputCount; i++) {
|
||||||
if (node.outputs[i].fieldName == fieldName) return node.outputs[i];
|
if (node.outputs[i].fieldName == fieldName) return node.outputs[i];
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user