From 1606c583f985884069995a06fae12b5a39853f53 Mon Sep 17 00:00:00 2001 From: Thor Brigsted Date: Wed, 20 Sep 2017 23:04:49 +0200 Subject: [PATCH] Basic serialization --- Examples/Nodes/AddNode.cs | 15 ++++ Examples/Nodes/AddNode.cs.meta | 12 +++ Examples/Nodes/BaseNode.cs | 7 +- Scripts/Editor/NodeEditorGUI.cs | 110 ++++++++++++++--------- Scripts/Editor/NodeEditorToolbar.cs | 47 ++++++++++ Scripts/Editor/NodeEditorToolbar.cs.meta | 12 +++ Scripts/Editor/NodeEditorWindow.cs | 82 ++++------------- Scripts/Node.cs | 6 ++ Scripts/NodeGraph.cs | 58 +++++++++++- 9 files changed, 236 insertions(+), 113 deletions(-) create mode 100644 Examples/Nodes/AddNode.cs create mode 100644 Examples/Nodes/AddNode.cs.meta create mode 100644 Scripts/Editor/NodeEditorToolbar.cs create mode 100644 Scripts/Editor/NodeEditorToolbar.cs.meta diff --git a/Examples/Nodes/AddNode.cs b/Examples/Nodes/AddNode.cs new file mode 100644 index 0000000..6b02b82 --- /dev/null +++ b/Examples/Nodes/AddNode.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +[System.Serializable] +public class AddNode : Node { + + public string thisIsAddNode = "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)); + } +} diff --git a/Examples/Nodes/AddNode.cs.meta b/Examples/Nodes/AddNode.cs.meta new file mode 100644 index 0000000..118fe96 --- /dev/null +++ b/Examples/Nodes/AddNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 22e05e2a1f5ad7645850d52212143629 +timeCreated: 1505937586 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Examples/Nodes/BaseNode.cs b/Examples/Nodes/BaseNode.cs index 203ddd8..04b0319 100644 --- a/Examples/Nodes/BaseNode.cs +++ b/Examples/Nodes/BaseNode.cs @@ -1,6 +1,9 @@ -public class BaseNode : Node { +using UnityEngine; - public string asdf; +[System.Serializable] +public class BaseNode : Node { + + public string thisIsBaseNode = "ASDF"; protected override void Init() { inputs = new NodePort[2]; diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index a7373db..70db270 100644 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -74,27 +74,6 @@ public partial class NodeEditorWindow { GUI.DrawTextureWithTexCoords(rect, crossTex, new Rect(tileOffset + new Vector2(0.5f,0.5f), tileAmount)); } - 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)) { } - 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 static bool DropdownButton(string name, float width) { return GUILayout.Button(name, EditorStyles.toolbarDropDown, GUILayout.Width(width)); } @@ -118,25 +97,6 @@ public partial class NodeEditorWindow { contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); } - public static void FileContextMenu() { - GenericMenu contextMenu = new GenericMenu(); - contextMenu.AddItem(new GUIContent("Create New"), false, null); - contextMenu.AddItem(new GUIContent("Load"), false, null); - - contextMenu.AddSeparator(""); - contextMenu.AddItem(new GUIContent("Save"), false, null); - contextMenu.AddItem(new GUIContent("Save As"), false, null); - - 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 DrawConnection(Vector2 startPoint, Vector2 endPoint) { startPoint = GridToWindowPosition(startPoint); endPoint = GridToWindowPosition(endPoint); @@ -152,4 +112,74 @@ public partial class NodeEditorWindow { Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, Color.gray, null, 4); Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, Color.white, null, 2); } + + public void DrawConnections() { + foreach (Node node in graph.nodes) { + for (int i = 0; i < node.OutputCount; i++) { + NodePort output = node.GetOutput(i); + Vector2 from = _portConnectionPoints[output]; + for (int k = 0; k < output.ConnectionCount; k++) { + NodePort input = output.GetConnection(k); + Vector2 to = _portConnectionPoints[input]; + DrawConnection(from, to); + } + } + } + } + + private void DrawNodes() { + portConnectionPoints.Clear(); + Event e = Event.current; + + BeginWindows(); + BeginZoomed(position, zoom); + if (e.type == EventType.Repaint) portRects.Clear(); + foreach (Node node in graph.nodes) { + //Get node position + Vector2 nodePos = GridToWindowPositionNoClipped(node.position.position); + + Rect windowRect = new Rect(nodePos, node.position.size); + + GUIStyle style = (node == selectedNode) ? (GUIStyle)"flow node 0 on" : (GUIStyle)"flow node 0"; + GUILayout.BeginArea(windowRect, node.ToString(), style); + GUILayout.BeginHorizontal(); + + //Inputs + GUILayout.BeginVertical(); + for (int i = 0; i < node.InputCount; i++) { + NodePort input = node.GetInput(i); + Rect r = GUILayoutUtility.GetRect(new GUIContent(input.name), styles.GetInputStyle(input.type)); + GUI.Label(r, input.name, styles.GetInputStyle(input.type)); + if (e.type == EventType.Repaint) portRects.Add(input, r); + portConnectionPoints.Add(input, new Vector2(r.xMin, r.yMin + (r.height * 0.5f)) + node.position.position); + } + GUILayout.EndVertical(); + + //Outputs + GUILayout.BeginVertical(); + for (int i = 0; i < node.OutputCount; i++) { + NodePort output = node.GetOutput(i); + Rect r = GUILayoutUtility.GetRect(new GUIContent(output.name), styles.GetOutputStyle(output.type)); + GUI.Label(r, output.name, styles.GetOutputStyle(output.type)); + if (e.type == EventType.Repaint) portRects.Add(output, r); + portConnectionPoints.Add(output, new Vector2(r.xMax, r.yMin + (r.height * 0.5f)) + node.position.position); + } + GUILayout.EndVertical(); + + GUILayout.EndHorizontal(); + + // GUI + + GUILayout.EndArea(); + + if (windowRect.position != nodePos) { + nodePos = windowRect.position; + node.position.position = WindowToGridPosition(nodePos); + //Vector2 newPos = windowRect = + } + + } + EndZoomed(position, zoom); + EndWindows(); + } } diff --git a/Scripts/Editor/NodeEditorToolbar.cs b/Scripts/Editor/NodeEditorToolbar.cs new file mode 100644 index 0000000..2ea2857 --- /dev/null +++ b/Scripts/Editor/NodeEditorToolbar.cs @@ -0,0 +1,47 @@ +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)) { } + 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("Create New"), false, null); + contextMenu.AddItem(new GUIContent("Load"), false, Load); + + contextMenu.AddSeparator(""); + contextMenu.AddItem(new GUIContent("Save"), false, Save); + contextMenu.AddItem(new GUIContent("Save As"), false, null); + + 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)); + } +} diff --git a/Scripts/Editor/NodeEditorToolbar.cs.meta b/Scripts/Editor/NodeEditorToolbar.cs.meta new file mode 100644 index 0000000..cc85b52 --- /dev/null +++ b/Scripts/Editor/NodeEditorToolbar.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fa774a466fc664148b43879d282ea071 +timeCreated: 1505932458 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs index 361c3c0..bad2e31 100644 --- a/Scripts/Editor/NodeEditorWindow.cs +++ b/Scripts/Editor/NodeEditorWindow.cs @@ -2,10 +2,13 @@ using System.Collections.Generic; using UnityEngine; using UnityEditor; +using System.IO; [InitializeOnLoad] -public partial class NodeEditorWindow : EditorWindow { +public partial class NodeEditorWindow : EditorWindow { + string saved; + public Dictionary portConnectionPoints { get { return _portConnectionPoints; } } private Dictionary _portConnectionPoints = new Dictionary(); private Dictionary portRects = new Dictionary(); @@ -26,80 +29,25 @@ public partial class NodeEditorWindow : EditorWindow { w.Show(); } - public void DrawConnections() { - foreach(Node node in graph.nodes) { - for (int i = 0; i < node.OutputCount; i++) { - NodePort output = node.GetOutput(i); - Vector2 from = _portConnectionPoints[output]; - for (int k = 0; k < output.ConnectionCount; k++) { - NodePort input = output.GetConnection(k); - Vector2 to = _portConnectionPoints[input]; - DrawConnection(from, to); - } - } - } + public void Save() { + saved = graph.Serialize(); } - private void DrawNodes() { - portConnectionPoints.Clear(); - Event e = Event.current; - - BeginWindows(); - BeginZoomed(position, zoom); - if (e.type == EventType.Repaint) portRects.Clear(); - foreach (Node node in graph.nodes) { - //Get node position - Vector2 nodePos = GridToWindowPositionNoClipped(node.position.position); - - Rect windowRect = new Rect(nodePos, node.position.size); - - GUIStyle style = (node == selectedNode) ? (GUIStyle)"flow node 0 on" : (GUIStyle)"flow node 0"; - GUILayout.BeginArea(windowRect, node.ToString(), style); - GUILayout.BeginHorizontal(); - - //Inputs - GUILayout.BeginVertical(); - for (int i = 0; i < node.InputCount; i++) { - NodePort input = node.GetInput(i); - Rect r = GUILayoutUtility.GetRect(new GUIContent(input.name), styles.GetInputStyle(input.type)); - GUI.Label(r, input.name, styles.GetInputStyle(input.type)); - if (e.type == EventType.Repaint) portRects.Add(input, r); - portConnectionPoints.Add(input, new Vector2(r.xMin, r.yMin + (r.height * 0.5f)) + node.position.position); - } - GUILayout.EndVertical(); - - //Outputs - GUILayout.BeginVertical(); - for (int i = 0; i < node.OutputCount; i++) { - NodePort output = node.GetOutput(i); - Rect r = GUILayoutUtility.GetRect(new GUIContent(output.name), styles.GetOutputStyle(output.type)); - GUI.Label(r, output.name, styles.GetOutputStyle(output.type)); - if (e.type == EventType.Repaint) portRects.Add(output, r); - portConnectionPoints.Add(output, new Vector2(r.xMax, r.yMin + (r.height * 0.5f)) + node.position.position); - } - GUILayout.EndVertical(); - - GUILayout.EndHorizontal(); - - // GUI - - GUILayout.EndArea(); - - if (windowRect.position != nodePos) { - nodePos = windowRect.position; - node.position.position = WindowToGridPosition(nodePos); - //Vector2 newPos = windowRect = - } - - } - EndZoomed(position, zoom); - EndWindows(); + public void Load() { + _graph = NodeGraph.Deserialize(saved); } private void DraggableWindow(int windowID) { GUI.DragWindow(); } + public byte[] ProtoSerialize(T value) { + using (var ms = new MemoryStream()) { + ProtoBuf.Serializer.Serialize(ms, value); + return ms.ToArray(); + } + } + public Vector2 WindowToGridPosition(Vector2 windowPosition) { return (windowPosition - (position.size * 0.5f) - (panOffset / zoom)) * zoom; } diff --git a/Scripts/Node.cs b/Scripts/Node.cs index 08366a1..7af4c2b 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -4,7 +4,12 @@ using UnityEngine; using System; /// Base class for all nodes +[Serializable] public abstract class Node { + + public string NodeType { get { return nodeType; } } + [SerializeField] private string nodeType; + public Rect position = new Rect(0,0,200,200); protected NodePort[] inputs = new NodePort[0]; protected NodePort[] outputs = new NodePort[0]; @@ -13,6 +18,7 @@ public abstract class Node { public int OutputCount { get { return outputs.Length; } } protected Node() { + nodeType = GetType().ToString(); Init(); } diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs index b07b1ba..64a8ec7 100644 --- a/Scripts/NodeGraph.cs +++ b/Scripts/NodeGraph.cs @@ -2,21 +2,24 @@ using System.Collections.Generic; using UnityEngine; using System; - /// Base class for all node graphs +[Serializable] public class NodeGraph { - /// All nodes in the graph. /// See: - public List nodes = new List(); + [NonSerialized] public List nodes = new List(); + /// Serialized nodes. + [SerializeField] public string[] s_nodes; + + public List strings = new List() { "ASDF", "3523" }; public T AddNode() where T : Node { T node = default(T); nodes.Add(node); return node; } - public Node AddNode(Type type) { + public Node AddNode(Type type) { Node node = (Node)Activator.CreateInstance(type); if (node == null) { Debug.LogError("Node could node be instanced"); @@ -26,6 +29,16 @@ public class NodeGraph { return node; } + public Node AddNode(string type) { + Node node = (Node)Activator.CreateInstance(null,type).Unwrap(); + if (node == null) { + Debug.LogError("Node could node be instanced"); + return null; + } + nodes.Add(node); + return node; + } + /// Safely remove a node and all its connections /// public void RemoveNode(Node node) { @@ -36,4 +49,41 @@ public class NodeGraph { public void Clear() { nodes.Clear(); } + + public string Serialize() { + //Unity serializer doesn't support polymorphism, so we'll have to use a hack + s_nodes = new string[nodes.Count]; + for (int i = 0; i < nodes.Count; i++) { + s_nodes[i] = JsonUtility.ToJson(nodes[i]); + } + //s_nodes = new string[] { "" }; + string json = JsonUtility.ToJson(this); + //json = json.Replace("\"\"", GetSerializedList(nodes)); + return json; + } + + private string GetSerializedList(List list) { + string[] s_list = new string[list.Count]; + for (int i = 0; i < list.Count; i++) { + s_list[i] = JsonUtility.ToJson(list[i]); + } + return string.Join(",", s_list); + + } + + public static NodeGraph Deserialize(string json) { + NodeGraph nodeGraph = JsonUtility.FromJson(json); + for (int i = 0; i < nodeGraph.s_nodes.Length; i++) { + NodeTyper tempNode = new NodeTyper(); + JsonUtility.FromJsonOverwrite(nodeGraph.s_nodes[i],tempNode); + Node node = nodeGraph.AddNode(tempNode.nodeType); + JsonUtility.FromJsonOverwrite(nodeGraph.s_nodes[i], node); + } + return nodeGraph; + } + + private class NodeTyper { + public string nodeType; + } } +