From 698f02d7169e9524c2c1ac83163dc19cd1a6226a Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Sat, 7 Oct 2017 01:54:10 +0200 Subject: [PATCH] Serialization now works. Node.cs is now a ScriptableObject. --- Examples/NodeToy/NodeGraphExample.asset | Bin 4180 -> 8116 bytes Examples/NodeToy/NodeGraphExample.asset.meta | 4 +- Scripts/Editor/NodeEditorAction.cs | 2 + Scripts/Node.cs | 19 +++--- Scripts/NodeGraph.cs | 17 ++++- Scripts/NodePort.cs | 68 ++++++++++++++----- 6 files changed, 81 insertions(+), 29 deletions(-) diff --git a/Examples/NodeToy/NodeGraphExample.asset b/Examples/NodeToy/NodeGraphExample.asset index 595fa1a714fd021035b0995fbd29cee202022cc8..c44ea50b8e5dac10bd72dce71b534d6e70a08b7e 100644 GIT binary patch literal 8116 zcmeI1TWlT09mfA_pV$cmO50p$0wFhWAjHHDPMkoTgL5Gv2{D*UAOw5uv$juqe2#m( zHg-^8^H4;2fGRYqTd7iL(>}D2a+4C&m!N<|3lc&o0t7?|DKC*w3l(Z!ApO3%Y<8AI z2&k1>>5M#QW_~;S&Fw$4Gh>li4~kszqKJH7WY*6SO7qgD6^%`eO?^%B<(V^Qyjrj_ zABf!d#jKgdz1fE!eQjR%;{NR)?s;f*|0jRha{B7})lY11nCPB^JgeY6_a>NR33V z7@bLp{7Id<1W)SJ$J~?ap)+c9SjJ82nOmPJ37*usAm*MNKs|RthxNOV8W6Jmuo;}~ zVw-LK2T<-QQ|?9JbRK#nS^tX_(>z)3_hRnJMwI&}=&=7UA&*pkuL=E0PmVDcFH2sl z^k?H8*5?Q0%Gb(m$h!-k=^w^i>n}6<)5xQU^>p;7lV{0YeU2wyRXnLbGv=NgM_m>n z&3aynkS?wNBaOeJKP$l-5oi6`$FpOear*NzaNXXFB>VGn!#g^{@{Q|r`LI-8KNbeX z;e4ssCWBoY@`Yg2Iz&4BZ~&2FDHjZj%DwPb#M|`5@#N)gWB-ay9Qs|`o=YD(eDL)h z2YkGI46qZ=YfT;l$yjPfQ$n3X@<7 z7$^AIiBqHab%vjvIGSUjQ2EbJ9L=$?E6#~S$MI@Icr!dFEGG`;H>kTH%!#?XAaEh4 z<3d3lPFU*9C5*^3ax0=c;mPMA)O?b&;LMMCowJ}VAcym$PU%?vg@h4#z2p%cf#*VT zB|M#n&&vtqupgkS6w^GpP&CB6UM;-4k!C$P4qAV*Q_riJKTDk{PCc(7SAL4K@Gg#d zM(OWGn)=rwtke%2XRYt{0~bTBU+3s^{59A5k04F`r3fqO(=ICMHMx7A)_)9X z>R*qrl70*GXQ}1Ze>u7Gu0HM2*8c!L9Nfq--3reyH|>Yx_$wqc@GHsTtlb_&ob}=6 zMc2o*+Z$r;+Ub_Cx=Vh?OMe& zPulIen7ekno+6RT@7V1I=FgJ5cFTFM``@+OjWKuab`yA|ez=ACv($3?VKce%?znG> zxofvu!7J%=EGp@5i*;Q6j+nc4i%m;K{o9#8`_=k)k}L1(-x2eS+9+DPy%W5W-QGnG zN4tFrHFz5F4E)`MaF!oJoP0YWoaN6VPJRy|969I3VZ_PrC4@WQ4Np1f4P{Km<$-)I z9FTz^-#-uvw>}-Eawz%Y&`5|45#no0#Ue6e<0QRt)ZHs__asBei=C7|oa>XWd``NG z{$L)HiROf>A; zbLiuyd;1Umec{Z#o0>aU-}OfL>Wp?S(^-rQho-vi(&lgg%V+hx;x6;wbY7`$yD)(w z+K;Ah#5e6y_lt|o{Uxpg%>8JsbKLncd6sq3 z$47fVS|Eq70sjCY-j8?(I%v2jlhpS7B+_hGF~v_AUP|$Q7(SHZrw#u}f^*yMp%TD2U48Z2&~Uoinkg4 zal`+gju+|-V-6cUy7c;?be0B#&aj*>_Jb7A{rxzD_~IAygR(go?<@1n66WzU>K8@= zoP#GH}KUIRm7DLntVGM1Y@^|@2O^o}5L znaTIrA9v3^);r<7TPw1~?xd^G-NRRZ6&aXw4NW!IBG>uKEb;=02NR-NeHFyks_ z5Sf4R$=`nZ`#l?eI%((pc{la$)3mv7|Fp+Hn7HN0yoSGhJ~;iTrs{?B`9bxRV`%HZ zg@q^2o6G*t!1^(NaHzobL>VMQ+h)dXKQV6G&A9C=#?QyudL;XW6JRS2qWb;!kBPk6 zF0yegJ@Z*thscta<;z=r-Ny)2U)$#l<2*h38G<+u%eLj)He3LCV+xb`GTbpYNr|=|5>p)Mp*(&S_6F xtzDwVxR3Y_^V6Nnp6s00ZNR)s*qUv#dX}&gYNqGZ*V!TS(rJCn!T*x2{TsY8>q7tl delta 434 zcmdmDe?>unfr05g1A{;a0|SE~kY<=DAY#A> Base class for all nodes [Serializable] -public abstract class Node { +public abstract class Node : ScriptableObject { /// Name of the node - [SerializeField] public string name = ""; - [SerializeField] public NodeGraph graph; + [NonSerialized] public NodeGraph graph; [SerializeField] public Rect rect = new Rect(0,0,200,200); /// Input s. It is recommended not to modify these at hand. Instead, see - [SerializeField] public NodePort[] inputs = new NodePort[0]; + [SerializeField] public List inputs = new List(); /// Output s. It is recommended not to modify these at hand. Instead, see [SerializeField] public NodePort[] outputs = new NodePort[0]; - public int InputCount { get { return inputs.Length; } } + public int InputCount { get { return inputs.Count; } } public int OutputCount { get { return outputs.Length; } } - /// Constructor protected Node() { CachePorts(); //Cache the ports at creation time so we don't have to use reflection at runtime + } + + protected void OnEnable() { Init(); } @@ -33,7 +34,7 @@ public abstract class Node { public virtual void OnCreateConnection(NodePort from, NodePort to) { } public int GetInputId(NodePort input) { - for (int i = 0; i < inputs.Length; i++) { + for (int i = 0; i < inputs.Count; i++) { if (input == inputs[i]) return i; } @@ -55,7 +56,7 @@ public abstract class Node { } public void ClearConnections() { - for (int i = 0; i < inputs.Length; i++) { + for (int i = 0; i < inputs.Count; i++) { inputs[i].ClearConnections(); } for (int i = 0; i < outputs.Length; i++) { @@ -99,7 +100,7 @@ public abstract class Node { else if (outputAttrib != null) outputPorts.Add(new NodePort(fieldInfo[i].Name, fieldInfo[i].FieldType, this, NodePort.IO.Output)); } - inputs = inputPorts.ToArray(); + inputs = inputPorts; outputs = outputPorts.ToArray(); } } diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs index 128add7..d61ec99 100644 --- a/Scripts/NodeGraph.cs +++ b/Scripts/NodeGraph.cs @@ -5,7 +5,8 @@ using System; /// Base class for all node graphs [Serializable] -public abstract class NodeGraph : ScriptableObject { +public abstract class NodeGraph : ScriptableObject, ISerializationCallbackReceiver { + /// All nodes in the graph. /// See: [SerializeField] public List nodes = new List(); @@ -15,7 +16,10 @@ public abstract class NodeGraph : ScriptableObject { } public virtual Node AddNode(Type type) { - Node node = (Node)Activator.CreateInstance(type); + Node node = ScriptableObject.CreateInstance(type) as Node; +#if UNITY_EDITOR + UnityEditor.AssetDatabase.AddObjectToAsset(node, this); +#endif nodes.Add(node); node.graph = this; return node; @@ -32,5 +36,14 @@ public abstract class NodeGraph : ScriptableObject { public void Clear() { nodes.Clear(); } + + public void OnBeforeSerialize() { + } + + public void OnAfterDeserialize() { + for (int i = 0; i < nodes.Count; i++) { + nodes[i].graph = this; + } + } } diff --git a/Scripts/NodePort.cs b/Scripts/NodePort.cs index bf626e5..c0df2bb 100644 --- a/Scripts/NodePort.cs +++ b/Scripts/NodePort.cs @@ -9,9 +9,7 @@ public class NodePort { public int ConnectionCount { get { return connections.Count; } } /// Return the first connection - public NodePort Connection { get { return connections.Count > 0 ? connections[0] : null; } } - /// Returns a copy of the connections list - public List Connections { get { return new List(connections); } } + public NodePort Connection { get { return connections.Count > 0 ? connections[0].Port : null; } } public IO direction { get { return _direction; } } /// Is this port connected to anytihng? @@ -20,11 +18,13 @@ public class NodePort { public bool IsOutput { get { return direction == IO.Output; } } public Node node { get; private set; } - public string name { get { return _name; } set { _name = value; } } + public string name { get { return _name; } } public bool enabled { get { return _enabled; } set { _enabled = value; } } + public string id { get { return _id; } } - [SerializeField] private List connections = new List(); - + [SerializeField] private List connections = new List(); + [SerializeField] private string asdf; + [SerializeField] private string _id; [SerializeField] public Type type; [SerializeField] private string _name; [SerializeField] private bool _enabled = true; @@ -35,39 +35,75 @@ public class NodePort { this.type = type; this.node = node; _direction = direction; + _id = node.GetInstanceID() + _name; } /// Connect this to another /// The to connect to public void Connect(NodePort port) { - if (connections == null) connections = new List(); + if (connections == null) connections = new List(); if (port == null) { Debug.LogWarning("Cannot connect to null port"); return; } if (port == this) { Debug.LogWarning("Attempting to connect port to self."); return; } - if (connections.Contains(port)) { Debug.LogWarning("Port already connected. "); return; } + if (IsConnectedTo(port)) { Debug.LogWarning("Port already connected. "); return; } if (direction == port.direction) { Debug.LogWarning("Cannot connect two " + (direction == IO.Input ? "input" : "output") + " connections"); return; } - connections.Add(port); - port.connections.Add(this); + connections.Add(new PortConnection(port)); + if (port.connections == null) port.connections = new List(); + port.connections.Add(new PortConnection(this)); node.OnCreateConnection(this, port); port.node.OnCreateConnection(this, port); } public NodePort GetConnection(int i) { - return connections[i]; + return connections[i].Port; } public bool IsConnectedTo(NodePort port) { - return connections.Contains(port); + for (int i = 0; i < connections.Count; i++) { + if (connections[i].Port == port) return true; + } + return false; } public void Disconnect(NodePort port) { - connections.Remove(port); - port.connections.Remove(this); + for (int i = 0; i < connections.Count; i++) { + if (connections[i].Port == port) { + connections.RemoveAt(i); + } + } + for (int i = 0; i < port.connections.Count; i++) { + if (port.connections[i].Port == this) { + port.connections.RemoveAt(i); + } + } } public void ClearConnections() { for (int i = 0; i < connections.Count; i++) { - connections[i].connections.Remove(this); + Disconnect(connections[i].Port); + } + } + + [Serializable] + public class PortConnection { + [SerializeField] public Node node; + [SerializeField] public string portID; + public NodePort Port { get { return port != null ? port : port = GetPort(); } } + [NonSerialized] private NodePort port; + + public PortConnection(NodePort port) { + this.port = port; + node = port.node; + portID = port.id; + } + + private NodePort GetPort() { + for (int i = 0; i < node.OutputCount; i++) { + if (node.outputs[i].id == portID) return node.outputs[i]; + } + for (int i = 0; i < node.InputCount; i++) { + if (node.inputs[i].id == portID) return node.inputs[i]; + } + return null; } - connections.Clear(); } }