diff --git a/Scripts/Editor/NodeEditorUtilities.cs b/Scripts/Editor/NodeEditorUtilities.cs index d0cbc7b..67d18d0 100644 --- a/Scripts/Editor/NodeEditorUtilities.cs +++ b/Scripts/Editor/NodeEditorUtilities.cs @@ -48,8 +48,8 @@ namespace XNodeEditor { ); return methods.Count() > 0; } - - /// Return a prettiefied type name. + + /// Return a prettified type name. public static string PrettyName(this Type type) { if (type == null) return "null"; if (type == typeof(System.Object)) return "object"; diff --git a/Scripts/Editor/NodeGraphInspector.cs b/Scripts/Editor/NodeGraphInspector.cs new file mode 100644 index 0000000..135277a --- /dev/null +++ b/Scripts/Editor/NodeGraphInspector.cs @@ -0,0 +1,157 @@ +using System; +using System.Reflection; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +using XNode; +using XNodeEditor; + +[CustomEditor(typeof(XNode.NodeGraph), true)] +public class NodeGraphInspector : Editor +{ + SerializedProperty nodesProp; + SerializedProperty variablesProp; + + void OnEnable() + { + nodesProp = serializedObject.FindProperty("nodes"); + variablesProp = serializedObject.FindProperty("variables"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawVariables(); + + serializedObject.ApplyModifiedProperties(); + } + + void DrawVariables() + { + EditorGUILayout.LabelField("Variables"); + EditorGUILayout.Space(); + for (int i = 0; i < variablesProp.arraySize; i++) + DrawVariable(i); + DrawVariablesActions(); + } + + void DrawVariable(int index) + { + var variableProp = variablesProp.GetArrayElementAtIndex(index); + + var idProp = variableProp.FindPropertyRelative("id"); + var typeProp = variableProp.FindPropertyRelative("typeString"); + + + DrawVariableId(idProp); + DrawVariableType(typeProp); + DrawVariableValue(variableProp, typeProp.stringValue); + DrawVariableActions(index); + + EditorGUILayout.Space(); + } + + void DrawVariableId(SerializedProperty idProp) + { + EditorGUILayout.PropertyField(idProp); + } + + void DrawVariableType(SerializedProperty typeProp) + { + List options = new List(); + options.Add(typeProp.stringValue); + int idx = 0; + + List additionalTypes = new List(); + additionalTypes.Add(typeof(float).AssemblyQualifiedName); + additionalTypes.Add(typeof(int).AssemblyQualifiedName); + additionalTypes.Add(typeof(bool).AssemblyQualifiedName); + additionalTypes.Add(typeof(string).AssemblyQualifiedName); + additionalTypes.Add(typeof(Vector3).AssemblyQualifiedName); + + /* + Assembly asm = typeof(Vector3).Assembly; + foreach (var colorPair in NodeEditorPreferences.typeColors) + { + var type = asm.GetType(colorPair.Key, false); + Debug.Log(colorPair.Key + " " + type); + + if (type == null) + continue; + if (additionalTypes.Contains(type.AssemblyQualifiedName)) + continue; + additionalTypes.Add(colorPair.Key); + } + */ + + foreach (var addType in additionalTypes) + { + if (!options.Contains(addType)) + options.Add(addType); + } + + List prettyOptions = new List(); + + foreach (var option in options) + { + prettyOptions.Add(System.Type.GetType(option, false).PrettyName()); + } + + + idx = EditorGUILayout.Popup(idx, prettyOptions.ToArray()); + + typeProp.stringValue = options[idx]; + } + + void DrawVariableValue(SerializedProperty variableProp, string type) + { + if (type != "") + { + type = System.Type.GetType(type, false).PrettyName(); + type = NodeGraph.GetSafeType(type); + + var valprop = variableProp.FindPropertyRelative(type + "Value"); + + if (valprop == null && type != "object") + { + type = "object"; + valprop = variableProp.FindPropertyRelative(type + "Value"); + } + + if (valprop != null) + EditorGUILayout.PropertyField(valprop); + else + EditorGUILayout.LabelField("Value"); + } + else + EditorGUILayout.LabelField("Value"); + } + + void DrawVariableActions(int index) + { + if (GUILayout.Button("Remove variable", GUILayout.Width(120))) + { + variablesProp.DeleteArrayElementAtIndex(index); + } + } + + void DrawVariablesActions() + { + GUILayout.BeginHorizontal(); + + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Add new variable", GUILayout.Width(120))) + { + variablesProp.InsertArrayElementAtIndex(variablesProp.arraySize); + var newVarProp = variablesProp.GetArrayElementAtIndex(variablesProp.arraySize -1); + newVarProp.FindPropertyRelative("id").stringValue = (target as NodeGraph).GetSafeId("new_variable"); + newVarProp.FindPropertyRelative("typeString").stringValue = typeof(float).AssemblyQualifiedName; + } + + GUILayout.EndHorizontal(); + } +} diff --git a/Scripts/Editor/NodeGraphInspector.cs.meta b/Scripts/Editor/NodeGraphInspector.cs.meta new file mode 100644 index 0000000..58f2bd6 --- /dev/null +++ b/Scripts/Editor/NodeGraphInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16edf05454c66b04ba4ebd0bf5b0af6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/NodeInspector.cs b/Scripts/Editor/NodeInspector.cs new file mode 100644 index 0000000..da797cc --- /dev/null +++ b/Scripts/Editor/NodeInspector.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +using XNode; + +[CustomEditor(typeof(Node), true)] +public class NodeInspector : Editor +{ + public override void OnInspectorGUI() { /*hides unneeded info*/ } +} diff --git a/Scripts/Editor/NodeInspector.cs.meta b/Scripts/Editor/NodeInspector.cs.meta new file mode 100644 index 0000000..0faa43e --- /dev/null +++ b/Scripts/Editor/NodeInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a079842175cdba54a8c36ad52f983502 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Node.cs b/Scripts/Node.cs index d65fc03..5bede6e 100644 --- a/Scripts/Node.cs +++ b/Scripts/Node.cs @@ -62,11 +62,11 @@ namespace XNode { protected void OnEnable() { NodeDataCache.UpdatePorts(this, ports); - Init(); + // Init(); } /// Initialize node. Called on creation. - protected virtual void Init() { name = GetType().Name; } + public virtual void Init() { name = GetType().Name; } /// Checks all connections for invalid references, and removes them. public void VerifyConnections() { diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs index c2092e0..f17d1f4 100644 --- a/Scripts/NodeGraph.cs +++ b/Scripts/NodeGraph.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Text.RegularExpressions; using System.Collections.Generic; using UnityEngine; @@ -10,6 +12,9 @@ namespace XNode { /// All nodes in the graph. /// See: [SerializeField] public List nodes = new List(); + + /// All variables in the graph. + [SerializeField] public List variables = new List(); /// Add a node to the graph by type public T AddNode() where T : Node { @@ -28,6 +33,7 @@ namespace XNode { #endif nodes.Add(node); node.graph = this; + node.Init(); return node; } @@ -44,6 +50,7 @@ namespace XNode { #endif nodes.Add(node); node.graph = this; + node.Init(); return node; } @@ -60,9 +67,10 @@ namespace XNode { nodes.Remove(node); } - /// Remove all nodes and connections from the graph + /// Remove all nodes, connections and variables from the graph public void Clear() { nodes.Clear(); + variables.Clear(); } /// Create a new deep copy of this graph @@ -74,6 +82,7 @@ namespace XNode { Node node = Instantiate(nodes[i]) as Node; node.graph = graph; graph.nodes[i] = node; + node.Init(); } // Redirect all connections @@ -85,5 +94,60 @@ namespace XNode { return graph; } + + /// Add a variable to the graph + /// the new variable data + /// the actual id used, avoiding duplicates + public string AddVariable(Variable newVariable) + { + newVariable.id = GetSafeId(newVariable.id); + newVariable.typeString = GetSafeType(newVariable.typeString); + variables.Add(newVariable); + return newVariable.id; + } + + /// Remove a variable from the graph + public void RemoveVariable(string id) + { + variables.Remove(GetVariable(id)); + } + + /// Get a variable from the graph + public Variable GetVariable(string id) + { + return variables.Find((Variable v) => v.id == id); + } + + /// Get a duplication safe id + public string GetSafeId(string id) + { + id = id.ToLower(); + id.Trim(); + var rx = new Regex(@"\s"); + rx.Replace(id, new MatchEvaluator((Match m) => "_")); + + var existingVariable = variables.Find((Variable v) => v.id == id); + if (existingVariable == null) + return id; + + int index = 1; + + while (variables.Find((Variable v) => v.id == id + "_" + index.ToString()) != null) + index++; + return id + "_" + index.ToString(); + } + + /// Get a variable safe type + public static string GetSafeType(string type) + { + const string UE = "UnityEngine."; + if (type.Contains(UE)) + { + type = type.Substring(UE.Length); + type = type.Substring(0,1).ToLower() + type.Substring(1); + } + + return type; + } } } \ No newline at end of file diff --git a/Scripts/Variable.cs b/Scripts/Variable.cs new file mode 100644 index 0000000..9d57c6c --- /dev/null +++ b/Scripts/Variable.cs @@ -0,0 +1,52 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +[System.Serializable] +public class Variable +{ + public string id; + public string typeString; + public System.Type type + { + get + { + if (typeString == typeof(float).AssemblyQualifiedName) return typeof(float); + if (typeString == typeof(int).AssemblyQualifiedName) return typeof(int); + if (typeString == typeof(string).AssemblyQualifiedName) return typeof(string); + if (typeString == typeof(bool).AssemblyQualifiedName) return typeof(bool); + if (typeString == typeof(Vector3).AssemblyQualifiedName) return typeof(Vector3); + return typeof(Object); + } + } + + public object Value + { + get + { + if (typeString == typeof(float).AssemblyQualifiedName) return floatValue; + if (typeString == typeof(int).AssemblyQualifiedName) return intValue; + if (typeString == typeof(string).AssemblyQualifiedName) return stringValue; + if (typeString == typeof(bool).AssemblyQualifiedName) return boolValue; + if (typeString == typeof(Vector3).AssemblyQualifiedName) return vector3Value; + return objectValue; + } + } + + public string stringValue; + public float floatValue; + public int intValue; + public bool boolValue; + public Vector3 vector3Value; + + // more here + + public Object objectValue; + + + public Variable() + { + id = "new_variable"; + typeString = typeof(float).AssemblyQualifiedName; + } +} diff --git a/Scripts/Variable.cs.meta b/Scripts/Variable.cs.meta new file mode 100644 index 0000000..a68dc79 --- /dev/null +++ b/Scripts/Variable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81f7d4c8803ebee4c903b0976f780d95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: