1
0
mirror of https://github.com/Siccity/xNode.git synced 2026-02-06 15:24:55 +08:00

Streamlined creation of custom node ports

Instead of initializing port arrays in Init();, ports are now defined by attributes on public fields
This commit is contained in:
Unknown 2017-09-24 21:54:53 +02:00
parent 97bbc236be
commit 59085db16a
5 changed files with 61 additions and 29 deletions

View File

@ -3,6 +3,8 @@
[System.Serializable]
public class BaseNode : Node {
[Input] public string input;
[Output] public string output;
public bool concat;
[TextArea]
public string SomeString;
@ -10,11 +12,4 @@ public class BaseNode : Node {
public Color col;
public AnimationCurve anim;
public Vector3 vec;
protected override void Init() {
inputs = new NodePort[2];
inputs[0] = CreateNodeInput("IntInput", typeof(int));
inputs[1] = CreateNodeInput("StringInput", typeof(string));
outputs = new NodePort[1];
outputs[0] = CreateNodeOutput("StringOutput", typeof(string));
}
}

View File

@ -2,25 +2,11 @@
[System.Serializable]
public class MathNode : Node {
[Input] public float a;
[Input] public float b;
[Output] public float result;
public enum ValueType { Float, Int }
public enum MathType { Add, Subtract, Multiply, Divide}
public ValueType valueType = ValueType.Float;
public MathType mathType = MathType.Add;
protected override void Init() {
inputs = new NodePort[2];
inputs[0] = CreateNodeInput("A", typeof(float));
inputs[1] = CreateNodeInput("B", typeof(float));
outputs = new NodePort[1];
outputs[0] = CreateNodeOutput("Result", typeof(float));
}
public void OnValidate() {
System.Type type = typeof(int);
if (valueType == ValueType.Float) type = typeof(float);
inputs[0].type = type;
inputs[1].type = type;
outputs[0].type = type;
}
}

View File

@ -14,11 +14,11 @@ public class NodeEditor {
public virtual void OnNodeGUI() {
portRects.Clear();
DrawNodePortsGUI();
DrawDefaultNodeGUI();
DrawDefaultNodeBody();
}
/// <summary> Draws standard field editors for all public fields </summary>
protected void DrawDefaultNodeGUI() {
protected void DrawDefaultNodeBody() {
FieldInfo[] fields = GetInspectorFields(target);
for (int i = 0; i < fields.Length; i++) {
Type fieldType = fields[i].FieldType;
@ -31,6 +31,9 @@ public class NodeEditor {
EditorGUILayout.LabelField(headerAttrib.header);
}
//Skip if field has input or output attribute
if (NodeEditorUtilities.HasAttrib<Node.InputAttribute>(fieldAttribs) || NodeEditorUtilities.HasAttrib<Node.OutputAttribute>(fieldAttribs)) continue;
EditorGUI.BeginChangeCheck();
if (fieldType == typeof(int)) {
fieldValue = EditorGUILayout.IntField(fieldName, (int)fieldValue);

View File

@ -23,6 +23,15 @@ public static class NodeEditorUtilities {
return false;
}
public static bool HasAttrib<T>(object[] attribs) where T : Attribute {
for (int i = 0; i < attribs.Length; i++) {
if (attribs[i].GetType() == typeof(T)) {
return true;
}
}
return false;
}
/// <summary> Return color based on type </summary>
public static Color GetTypeColor(Type type) {
UnityEngine.Random.InitState(type.Name.GetHashCode());

View File

@ -14,18 +14,21 @@ public abstract class Node {
[SerializeField] private string nodeType;
[SerializeField] public Rect position = new Rect(0,0,200,200);
[SerializeField] protected NodePort[] inputs = new NodePort[0];
[SerializeField] protected NodePort[] outputs = new NodePort[0];
[SerializeField] private NodePort[] inputs = new NodePort[0];
[SerializeField] private NodePort[] outputs = new NodePort[0];
public int InputCount { get { return inputs.Length; } }
public int OutputCount { get { return outputs.Length; } }
protected Node() {
nodeType = GetType().ToString();
CachePorts();
Init();
}
protected abstract void Init();
protected virtual void Init() {
}
public int GetInputId(NodePort input) {
for (int i = 0; i < inputs.Length; i++) {
@ -75,4 +78,40 @@ public abstract class Node {
public override int GetHashCode() {
return JsonUtility.ToJson(this).GetHashCode();
}
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public class InputAttribute : Attribute {
public InputAttribute() {
}
}
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public class OutputAttribute : Attribute {
public OutputAttribute() {
}
}
/// <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 CachePorts() {
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].Name, fieldInfo[i].FieldType, this, NodePort.IO.Input));
else if (outputAttrib != null) outputPorts.Add(new NodePort(fieldInfo[i].Name, fieldInfo[i].FieldType, this, NodePort.IO.Output));
}
inputs = inputPorts.ToArray();
outputs = outputPorts.ToArray();
}
}