diff --git a/Scripts/Attributes/CreateNodeMenuAttribute.cs b/Scripts/Attributes/CreateNodeMenuAttribute.cs
new file mode 100644
index 0000000..74884d3
--- /dev/null
+++ b/Scripts/Attributes/CreateNodeMenuAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace XNode {
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class CreateNodeMenuAttribute : Attribute {
+ public string menuName;
+ /// Manually supply node class with a context menu path
+ /// Path to this node in the context menu. Null or empty hides it.
+ public CreateNodeMenuAttribute(string menuName) {
+ this.menuName = menuName;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Editor/Interfaces/ICustomEditor.cs.meta b/Scripts/Attributes/CreateNodeMenuAttribute.cs.meta
similarity index 83%
rename from Scripts/Editor/Interfaces/ICustomEditor.cs.meta
rename to Scripts/Attributes/CreateNodeMenuAttribute.cs.meta
index 788dc4e..8f93f37 100644
--- a/Scripts/Editor/Interfaces/ICustomEditor.cs.meta
+++ b/Scripts/Attributes/CreateNodeMenuAttribute.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 5085db84cab1cba42ad78c9310b87f36
+guid: 5fbc123731a209b47a4ada9ac41875f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Scripts/Attributes/InputAttribute.cs b/Scripts/Attributes/InputAttribute.cs
new file mode 100644
index 0000000..63249bc
--- /dev/null
+++ b/Scripts/Attributes/InputAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace XNode {
+ /// Mark a serializable field as an input port. You can access this through
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
+ public class InputAttribute : Attribute {
+ public ShowBackingValue backingValue;
+ public ConnectionType connectionType;
+ public bool dynamicPortList;
+ public TypeConstraint typeConstraint;
+
+ /// Mark a serializable field as an input port. You can access this through
+ /// Should we display the backing value for this port as an editor field?
+ /// Should we allow multiple connections?
+ /// Constrains which input connections can be made to this port
+ /// If true, will display a reorderable list of inputs instead of a single port. Will automatically add and display values for lists and arrays
+ public InputAttribute(ShowBackingValue backingValue = ShowBackingValue.Unconnected, ConnectionType connectionType = ConnectionType.Multiple, TypeConstraint typeConstraint = TypeConstraint.None, bool dynamicPortList = false) {
+ this.backingValue = backingValue;
+ this.connectionType = connectionType;
+ this.dynamicPortList = dynamicPortList;
+ this.typeConstraint = typeConstraint;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Attributes/InputAttribute.cs.meta b/Scripts/Attributes/InputAttribute.cs.meta
new file mode 100644
index 0000000..4a15387
--- /dev/null
+++ b/Scripts/Attributes/InputAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6d1e987ec989e04684a50162742a10b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/Attributes/NodeEnum.cs b/Scripts/Attributes/NodeEnumAttribute.cs
similarity index 100%
rename from Scripts/Attributes/NodeEnum.cs
rename to Scripts/Attributes/NodeEnumAttribute.cs
diff --git a/Scripts/Attributes/NodeEnum.cs.meta b/Scripts/Attributes/NodeEnumAttribute.cs.meta
similarity index 100%
rename from Scripts/Attributes/NodeEnum.cs.meta
rename to Scripts/Attributes/NodeEnumAttribute.cs.meta
diff --git a/Scripts/Attributes/NodeTintAttribute.cs b/Scripts/Attributes/NodeTintAttribute.cs
new file mode 100644
index 0000000..4369d0d
--- /dev/null
+++ b/Scripts/Attributes/NodeTintAttribute.cs
@@ -0,0 +1,30 @@
+using System;
+using UnityEngine;
+
+namespace XNode {
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class NodeTintAttribute : Attribute {
+ public Color color;
+ /// Specify a color for this node type
+ /// Red [0.0f .. 1.0f]
+ /// Green [0.0f .. 1.0f]
+ /// Blue [0.0f .. 1.0f]
+ public NodeTintAttribute(float r, float g, float b) {
+ color = new Color(r, g, b);
+ }
+
+ /// Specify a color for this node type
+ /// HEX color value
+ public NodeTintAttribute(string hex) {
+ ColorUtility.TryParseHtmlString(hex, out color);
+ }
+
+ /// Specify a color for this node type
+ /// Red [0 .. 255]
+ /// Green [0 .. 255]
+ /// Blue [0 .. 255]
+ public NodeTintAttribute(byte r, byte g, byte b) {
+ color = new Color32(r, g, b, byte.MaxValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Attributes/NodeTintAttribute.cs.meta b/Scripts/Attributes/NodeTintAttribute.cs.meta
new file mode 100644
index 0000000..668803f
--- /dev/null
+++ b/Scripts/Attributes/NodeTintAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 69fbc77b18c1fe3418cf19a02d0d273b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/Attributes/NodeWidthAttribute.cs b/Scripts/Attributes/NodeWidthAttribute.cs
new file mode 100644
index 0000000..fa8505c
--- /dev/null
+++ b/Scripts/Attributes/NodeWidthAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace XNode {
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public class NodeWidthAttribute : Attribute {
+ public int width;
+ /// Specify a width for this node type
+ /// Width
+ public NodeWidthAttribute(int width) {
+ this.width = width;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Attributes/NodeWidthAttribute.cs.meta b/Scripts/Attributes/NodeWidthAttribute.cs.meta
new file mode 100644
index 0000000..e80b405
--- /dev/null
+++ b/Scripts/Attributes/NodeWidthAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 068cc89d1268616429d0a01ad64e2959
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/Attributes/OutputAttribute.cs b/Scripts/Attributes/OutputAttribute.cs
new file mode 100644
index 0000000..e40781b
--- /dev/null
+++ b/Scripts/Attributes/OutputAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace XNode {
+ /// Mark a serializable field as an output port. You can access this through
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
+ public class OutputAttribute : Attribute {
+ public ShowBackingValue backingValue;
+ public ConnectionType connectionType;
+ public bool dynamicPortList;
+
+ /// Mark a serializable field as an output port. You can access this through
+ /// Should we display the backing value for this port as an editor field?
+ /// Should we allow multiple connections?
+ /// If true, will display a reorderable list of outputs instead of a single port. Will automatically add and display values for lists and arrays
+ public OutputAttribute(ShowBackingValue backingValue = ShowBackingValue.Never, ConnectionType connectionType = ConnectionType.Multiple, bool dynamicPortList = false) {
+ this.backingValue = backingValue;
+ this.connectionType = connectionType;
+ this.dynamicPortList = dynamicPortList;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Attributes/OutputAttribute.cs.meta b/Scripts/Attributes/OutputAttribute.cs.meta
new file mode 100644
index 0000000..eeefe14
--- /dev/null
+++ b/Scripts/Attributes/OutputAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e79589a039fb6f94a9215b71335c5641
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/Editor/Interfaces/ICustomEditor.cs b/Scripts/Editor/Interfaces/ICustomEditor.cs
deleted file mode 100644
index d87fd46..0000000
--- a/Scripts/Editor/Interfaces/ICustomEditor.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using UnityEditor;
-using UnityEngine;
-
-namespace XNodeEditor {
- ///
- /// Workaround since c# doesn't support nested interfaces.
- ///
- /// Used with INodeEditor and INodeGraphEditor.
- ///
- public interface ICustomEditor {
- T Target { get; }
- SerializedObject SerializedObject { get; }
- }
-}
\ No newline at end of file
diff --git a/Scripts/Editor/Interfaces/INodeEditor.cs b/Scripts/Editor/Interfaces/INodeEditor.cs
index eb62e65..f3bd8ae 100644
--- a/Scripts/Editor/Interfaces/INodeEditor.cs
+++ b/Scripts/Editor/Interfaces/INodeEditor.cs
@@ -6,43 +6,25 @@ using UnityEngine;
using XNode;
namespace XNodeEditor {
- public interface INodeGraphEditor {
- INodeGraph target { get; }
- void OnGUI();
- void OnOpen();
- Texture2D GetGridTexture();
- Texture2D GetSecondaryGridTexture();
- /// Return default settings for this graph type. This is the settings the user will load if no previous settings have been saved.
- NodeEditorPreferences.Settings GetDefaultPreferences();
- /// Returns context node menu path. Null or empty strings for hidden nodes.
- string GetNodeMenuName(Type type);
+ public interface INodeEditor {
+ Editor editor { get; }
+ void OnBodyGUI();
+ void OnHeaderGUI();
/// Add items for the context menu when right-clicking this node. Override to add custom menu items.
void AddContextMenuItems(GenericMenu menu);
- Color GetPortColor(XNode.NodePort port);
- Color GetTypeColor(Type type);
- /// Create a node and save it in the graph asset
- XNode.INode CreateNode(Type type, Vector2 position);
- /// Creates a copy of the original node in the graph
- XNode.INode CopyNode(XNode.INode original);
- /// Safely remove a node and all its connections.
- void RemoveNode(XNode.INode node);
}
[AttributeUsage(AttributeTargets.Class)]
- public class CustomNodeGraphEditorAttribute : Attribute,
- XNodeEditor.Internal.INodeEditorAttrib {
- private Type inspectedType;
- public string editorPrefsKey;
- /// Tells a NodeGraphEditor which Graph type it is an editor for
- /// Type that this editor can edit
- /// Define unique key for unique layout settings instance
- public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") {
- this.inspectedType = inspectedType;
- this.editorPrefsKey = editorPrefsKey;
- }
-
- public Type GetInspectedType() {
- return inspectedType;
- }
+ public class CustomNodeEditorAttribute : Attribute, XNodeEditor.Internal.INodeEditorAttrib {
+ private Type inspectedType;
+ /// Tells a NodeEditor which Node type it is an editor for
+ /// Type that this editor can edit
+ public CustomNodeEditorAttribute(Type inspectedType) {
+ this.inspectedType = inspectedType;
}
+
+ public Type GetInspectedType() {
+ return inspectedType;
+ }
+ }
}
\ No newline at end of file
diff --git a/Scripts/Editor/Interfaces/INodeGraphEditor.cs b/Scripts/Editor/Interfaces/INodeGraphEditor.cs
index ce02796..bb05142 100644
--- a/Scripts/Editor/Interfaces/INodeGraphEditor.cs
+++ b/Scripts/Editor/Interfaces/INodeGraphEditor.cs
@@ -1,16 +1,48 @@
-using System.Collections;
+using System;
+using System.Collections;
using System.Collections.Generic;
+using UnityEditor;
using UnityEngine;
+using XNode;
-public class INodeGraphEditor : MonoBehaviour {
+namespace XNodeEditor {
+ public interface INodeGraphEditor {
+ NodeEditorWindow window { get; set; }
+ Editor editor { get; }
+ void OnGUI();
+ void OnOpen();
+ Texture2D GetGridTexture();
+ Texture2D GetSecondaryGridTexture();
+ /// Return default settings for this graph type. This is the settings the user will load if no previous settings have been saved.
+ NodeEditorPreferences.Settings GetDefaultPreferences();
+ /// Returns context node menu path. Null or empty strings for hidden nodes.
+ string GetNodeMenuName(Type type);
+ /// Add items for the context menu when right-clicking this node. Override to add custom menu items.
+ void AddContextMenuItems(GenericMenu menu);
+ Color GetPortColor(XNode.NodePort port);
+ Color GetTypeColor(Type type);
+ /// Create a node and save it in the graph asset
+ XNode.INode CreateNode(Type type, Vector2 position);
+ /// Creates a copy of the original node in the graph
+ XNode.INode CopyNode(XNode.INode original);
+ /// Safely remove a node and all its connections.
+ void RemoveNode(XNode.INode node);
+ }
- // Use this for initialization
- void Start () {
-
+ [AttributeUsage(AttributeTargets.Class)]
+ public class CustomNodeGraphEditorAttribute : Attribute, XNodeEditor.Internal.INodeEditorAttrib {
+ private Type inspectedType;
+ public string editorPrefsKey;
+ /// Tells a NodeGraphEditor which Graph type it is an editor for
+ /// Type that this editor can edit
+ /// Define unique key for unique layout settings instance
+ public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings") {
+ this.inspectedType = inspectedType;
+ this.editorPrefsKey = editorPrefsKey;
+ }
+
+ public Type GetInspectedType() {
+ return inspectedType;
+ }
}
-
- // Update is called once per frame
- void Update () {
-
- }
-}
+}
\ No newline at end of file
diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs
index 69da749..38e251b 100644
--- a/Scripts/Editor/NodeEditor.cs
+++ b/Scripts/Editor/NodeEditor.cs
@@ -6,14 +6,18 @@ using UnityEngine;
namespace XNodeEditor {
/// Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes.
+ [CustomNodeEditor(typeof(XNode.Node))]
+ public class NodeEditor : Editor, INodeEditor {
+ public new XNode.Node target { get { return _target != null? _target : _target = base.target as XNode.Node; } }
+ private XNode.Node _target;
- [CustomNodeEditor(typeof(XNode.INode))]
- public class NodeEditor : XNodeEditor.Internal.NodeEditorBase {
-
- /// Fires every whenever a node was modified through the editor
- public static Action onUpdateNode;
+ /// Fires whenever a node was modified through the editor
public readonly static Dictionary portPositions = new Dictionary();
+#region Interface implementation
+ Editor INodeEditor.editor { get { return this; } }
+#endregion
+
public new virtual void OnHeaderGUI() {
GUILayout.Label(target.name, NodeEditorResources.styles.nodeHeader, GUILayout.Height(30));
}
@@ -89,20 +93,5 @@ namespace XNodeEditor {
target.name = newName;
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target));
}
-
- [AttributeUsage(AttributeTargets.Class)]
- public class CustomNodeEditorAttribute : Attribute,
- XNodeEditor.Internal.INodeEditorAttrib {
- private Type inspectedType;
- /// Tells a NodeEditor which Node type it is an editor for
- /// Type that this editor can edit
- public CustomNodeEditorAttribute(Type inspectedType) {
- this.inspectedType = inspectedType;
- }
-
- public Type GetInspectedType() {
- return inspectedType;
- }
- }
}
}
\ No newline at end of file
diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs
index f3e1d57..70fb23a 100644
--- a/Scripts/Editor/NodeEditorAction.cs
+++ b/Scripts/Editor/NodeEditorAction.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
+using XNodeEditor.Internal;
namespace XNodeEditor {
public partial class NodeEditorWindow {
@@ -160,7 +161,6 @@ namespace XNodeEditor {
hoveredPort.Disconnect(output);
draggedOutput = output;
draggedOutputTarget = hoveredPort;
- if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node);
}
}
} else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
@@ -215,7 +215,6 @@ namespace XNodeEditor {
int connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget);
if (connectionIndex != -1) {
draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes);
- if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node);
EditorUtility.SetDirty((UnityEngine.Object) graph);
}
}
@@ -271,7 +270,7 @@ namespace XNodeEditor {
} else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
if (!Selection.Contains((UnityEngine.Object) hoveredNode)) SelectNode(hoveredNode, false);
GenericMenu menu = new GenericMenu();
- NodeEditor.GetEditor(hoveredNode, this).AddContextMenuItems(menu);
+ hoveredNode.GetNodeEditor().AddContextMenuItems(menu);
menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
e.Use(); // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places.
} else if (!IsHoveringNode) {
@@ -387,8 +386,8 @@ namespace XNodeEditor {
if (srcNode.Graph != graph) continue; // ignore nodes selected in another graph
XNode.INode newNode = graphEditor.CopyNode(srcNode);
substitutes.Add(srcNode, newNode);
- newnode.Position = srcnode.Position + new Vector2(30, 30);
- newNodes[i] = newNode;
+ newNode.Position = srcNode.Position + new Vector2(30, 30);
+ newNodes[i] = newNode as UnityEngine.Object;
}
}
@@ -396,7 +395,7 @@ namespace XNodeEditor {
for (int i = 0; i < Selection.objects.Length; i++) {
if (Selection.objects[i] is XNode.INode) {
XNode.INode srcNode = Selection.objects[i] as XNode.INode;
- if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
+ if (srcNode.Graph != graph) continue; // ignore nodes selected in another graph
foreach (XNode.NodePort port in srcNode.Ports) {
for (int c = 0; c < port.ConnectionCount; c++) {
XNode.NodePort inputPort = port.direction == XNode.NodePort.IO.Input ? port : port.GetConnection(c);
diff --git a/Scripts/Editor/NodeEditorAssetModProcessor.cs b/Scripts/Editor/NodeEditorAssetModProcessor.cs
index 97b46c4..6591b51 100644
--- a/Scripts/Editor/NodeEditorAssetModProcessor.cs
+++ b/Scripts/Editor/NodeEditorAssetModProcessor.cs
@@ -27,9 +27,9 @@ namespace XNodeEditor {
for (int k = 0; k < objs.Length; k++) {
XNode.INode node = objs[k] as XNode.INode;
if (node.GetType () == scriptType) {
- if (node != null && node.graph != null) {
+ if (node != null && node.Graph != null) {
// Delete the node and notify the user
- Debug.LogWarning (node.name + " of " + node.graph + " depended on deleted script and has been removed automatically.", node.graph);
+ Debug.LogWarning (node.Name + " of " + node.Graph + " depended on deleted script and has been removed automatically.", node.Graph);
node.graph.RemoveNode (node);
}
}
diff --git a/Scripts/Editor/NodeEditorBase.cs b/Scripts/Editor/NodeEditorBase.cs
deleted file mode 100644
index 39ae942..0000000
--- a/Scripts/Editor/NodeEditorBase.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Reflection;
-using UnityEditor;
-using UnityEngine;
-
-namespace XNodeEditor.Internal {
- /// Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type)
- /// Editor Type. Should be the type of the deriving script itself (eg. NodeEditor)
- /// Attribute Type. The attribute used to connect with the runtime type (eg. CustomNodeEditorAttribute)
- /// Runtime Type. The Object this can be an editor for (eg. INode )
- public abstract class NodeEditorBase : Editor where T : NodeEditorBase, ICustomEditor where A : Attribute, INodeEditorAttrib where K : class {
- /// Custom editors defined with [CustomNodeEditor]
- private static Dictionary editorTypes;
- private static Dictionary editors = new Dictionary();
- public NodeEditorWindow window;
- public new K target { get { return _target as UnityEngine.Object == base.target ? _target : _target = base.target as K; } set { base.target = value as UnityEngine.Object; } }
- private K _target;
-
- public static T GetEditor(Q target, NodeEditorWindow window) where Q : class {
- if ((target as UnityEngine.Object) == null) return default(T);
- T editor;
- if (!editors.TryGetValue(target as K, out editor)) {
- Type type = target.GetType();
- Type editorType = GetEditorType(type);
- editor = (T) Editor.CreateEditor(target as UnityEngine.Object, editorType);
- editor.window = window;
- editors.Add(target as K, editor);
- }
- if (editor.target == null) editor.Initialize(new UnityEngine.Object[] { target as UnityEngine.Object });
- if (editor.window != window) editor.window = window;
- return editor;
- }
-
- private static Type GetEditorType(Type type) {
- if (type == null) return null;
- if (editorTypes == null) CacheCustomEditors();
- Type result;
- if (editorTypes.TryGetValue(type, out result)) return result;
- //If type isn't found, try base type
- return GetEditorType(type.BaseType);
- }
-
- private static void CacheCustomEditors() {
- editorTypes = new Dictionary();
-
- //Get all classes deriving from NodeEditor via reflection
- Type[] nodeEditors = XNodeEditor.NodeEditorWindow.GetDerivedTypes(typeof(T));
- for (int i = 0; i < nodeEditors.Length; i++) {
- if (nodeEditors[i].IsAbstract) continue;
- var attribs = nodeEditors[i].GetCustomAttributes(typeof(A), false);
- if (attribs == null || attribs.Length == 0) continue;
- A attrib = attribs[0] as A;
- editorTypes.Add(attrib.GetInspectedType(), nodeEditors[i]);
- }
- }
- }
-
- public interface INodeEditorAttrib {
- Type GetInspectedType();
- }
-}
\ No newline at end of file
diff --git a/Scripts/Editor/NodeEditorExtensions.cs b/Scripts/Editor/NodeEditorExtensions.cs
new file mode 100644
index 0000000..8a9f7d4
--- /dev/null
+++ b/Scripts/Editor/NodeEditorExtensions.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEditor;
+using UnityEngine;
+using Object = UnityEngine.Object;
+using XNode;
+
+namespace XNodeEditor.Internal {
+ /// Handles caching of custom editor classes and their target types. Accessible with GetEditor(Type type)
+ public static class NodeEditorExtensions {
+ /// Custom editors defined with [CustomNodeEditor]
+ private static Dictionary nodeEditorTypes;
+ /// Custom editors defined with [CustomGraphEditor]
+ private static Dictionary graphEditorTypes;
+ private static Dictionary