浏览代码

Started adding node based stuff (not functional atm)

/main
Thomas ICHÉ 6 年前
当前提交
8c666b84
共有 131 个文件被更改,包括 3307 次插入1 次删除
  1. 4
      Editor/GameplayIngredients-Editor.asmdef
  2. 63
      Editor/HiearchyItems.cs
  3. 11
      Editor/HiearchyItems.cs.meta
  4. 8
      NodeGraphProcessor.meta
  5. 8
      NodeGraphProcessor/Editor.meta
  6. 81
      NodeGraphProcessor/Editor/BaseGraphWindow.cs
  7. 11
      NodeGraphProcessor/Editor/BaseGraphWindow.cs.meta
  8. 8
      NodeGraphProcessor/Editor/Callbacks.meta
  9. 93
      NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs
  10. 11
      NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs.meta
  11. 22
      NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt
  12. 7
      NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt.meta
  13. 21
      NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt
  14. 7
      NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt.meta
  15. 26
      NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs
  16. 11
      NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs.meta
  17. 19
      NodeGraphProcessor/Editor/EditorAttributes.cs
  18. 11
      NodeGraphProcessor/Editor/EditorAttributes.cs.meta
  19. 8
      NodeGraphProcessor/Editor/Logic.meta
  20. 60
      NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs
  21. 11
      NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs.meta
  22. 8
      NodeGraphProcessor/Editor/Manipulators.meta
  23. 125
      NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs
  24. 11
      NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs.meta
  25. 75
      NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs
  26. 11
      NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs.meta
  27. 8
      NodeGraphProcessor/Editor/PortBehaviors.meta
  28. 19
      NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs
  29. 11
      NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs.meta
  30. 98
      NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs
  31. 11
      NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs.meta
  32. 41
      NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs
  33. 11
      NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs.meta
  34. 8
      NodeGraphProcessor/Editor/Resources.meta
  35. 8
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles.meta
  36. 4
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss
  37. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss.meta
  38. 7
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss
  39. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss.meta
  40. 4
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss
  41. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss.meta
  42. 3
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss
  43. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss.meta
  44. 50
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss
  45. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss.meta
  46. 50
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss
  47. 10
      NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss.meta
  48. 8
      NodeGraphProcessor/Editor/Utils.meta
  49. 14
      NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs
  50. 11
      NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs.meta
  51. 114
      NodeGraphProcessor/Editor/Utils/FieldFactory.cs
  52. 11
      NodeGraphProcessor/Editor/Utils/FieldFactory.cs.meta
  53. 102
      NodeGraphProcessor/Editor/Utils/NodeProvider.cs
  54. 11
      NodeGraphProcessor/Editor/Utils/NodeProvider.cs.meta
  55. 8
      NodeGraphProcessor/Editor/Views.meta
  56. 585
      NodeGraphProcessor/Editor/Views/BaseGraphView.cs
  57. 11
      NodeGraphProcessor/Editor/Views/BaseGraphView.cs.meta
  58. 245
      NodeGraphProcessor/Editor/Views/BaseNodeView.cs
  59. 11
      NodeGraphProcessor/Editor/Views/BaseNodeView.cs.meta
  60. 98
      NodeGraphProcessor/Editor/Views/CommentBlockView.cs
  61. 11
      NodeGraphProcessor/Editor/Views/CommentBlockView.cs.meta
  62. 17
      NodeGraphProcessor/Editor/Views/EdgeView.cs
  63. 11
      NodeGraphProcessor/Editor/Views/EdgeView.cs.meta
  64. 22
      NodeGraphProcessor/Editor/Views/MiniMapView.cs
  65. 11
      NodeGraphProcessor/Editor/Views/MiniMapView.cs.meta
  66. 58
      NodeGraphProcessor/Editor/Views/PinnedElementView.cs
  67. 11
      NodeGraphProcessor/Editor/Views/PinnedElementView.cs.meta
  68. 99
      NodeGraphProcessor/Editor/Views/PortView.cs
  69. 11
      NodeGraphProcessor/Editor/Views/PortView.cs.meta
  70. 36
      NodeGraphProcessor/Editor/Views/ProcessorView.cs
  71. 11
      NodeGraphProcessor/Editor/Views/ProcessorView.cs.meta
  72. 101
      NodeGraphProcessor/Editor/Views/ToolbarView.cs
  73. 11
      NodeGraphProcessor/Editor/Views/ToolbarView.cs.meta
  74. 16
      NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef
  75. 7
      NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef.meta
  76. 21
      NodeGraphProcessor/LICENSE
  77. 7
      NodeGraphProcessor/LICENSE.meta
  78. 8
      NodeGraphProcessor/Runtime.meta
  79. 8
      NodeGraphProcessor/Runtime/Elements.meta
  80. 216
      NodeGraphProcessor/Runtime/Elements/BaseNode.cs
  81. 11
      NodeGraphProcessor/Runtime/Elements/BaseNode.cs.meta
  82. 29
      NodeGraphProcessor/Runtime/Elements/CommentBlock.cs
  83. 11
      NodeGraphProcessor/Runtime/Elements/CommentBlock.cs.meta
  84. 161
      NodeGraphProcessor/Runtime/Elements/NodePort.cs
  85. 11
      NodeGraphProcessor/Runtime/Elements/NodePort.cs.meta
  86. 20
      NodeGraphProcessor/Runtime/Elements/PinnedElement.cs
  87. 11
      NodeGraphProcessor/Runtime/Elements/PinnedElement.cs.meta
  88. 8
      NodeGraphProcessor/Runtime/Graph.meta

4
Editor/GameplayIngredients-Editor.asmdef


"name": "GameplayIngredients-Editor",
"references": [
"NaughtyAttributes",
"GameplayIngredients"
"GameplayIngredients",
"com.alelievr.NodeGraphProcessor",
"com.alelievr.NodeGraphProcessor-Editor"
],
"optionalUnityReferences": [],
"includePlatforms": [

63
Editor/HiearchyItems.cs


using UnityEngine;
using UnityEditor;
namespace GameplayIngredients
{
static class HiearchyItems
{
#region TRIGGERS
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Box)", false, 10)]
static void CreateTriggerBox()
{
var go = new GameObject();
var col = go.AddComponent<BoxCollider>();
col.isTrigger = true;
var hook = go.AddComponent<Hooks.OnTriggerHook>();
go.name = "Box Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Sphere)", false, 10)]
static void CreateTriggerSphere()
{
var go = new GameObject();
var col = go.AddComponent<SphereCollider>();
col.isTrigger = true;
var hook = go.AddComponent<Hooks.OnTriggerHook>();
go.name = "Sphere Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Capsule)", false, 10)]
static void CreateTriggerCapsule()
{
var go = new GameObject();
var col = go.AddComponent<CapsuleCollider>();
col.isTrigger = true;
var hook = go.AddComponent<Hooks.OnTriggerHook>();
go.name = "Capsule Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/GameplayIngredients/Hooks/On Awake", false, 10)]
static void CreateOnAwake()
{
var go = new GameObject();
var hook = go.AddComponent<Hooks.OnAwakeHook>();
go.name = "OnAwake Hook";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
#endregion
}
}

11
Editor/HiearchyItems.cs.meta


fileFormatVersion: 2
guid: 28d66973767a30643a54411070050920
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor.meta


fileFormatVersion: 2
guid: a7f14529a2d38974cb3d53b8d5014fb0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor.meta


fileFormatVersion: 2
guid: 232f899daeba5461ebf015a1f96643b3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

81
NodeGraphProcessor/Editor/BaseGraphWindow.cs


using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEngine.Assertions;
using UnityEngine.Experimental.UIElements;
using UnityEditor.Experimental.UIElements;
using UnityEditor.Experimental.UIElements.GraphView;
namespace GraphProcessor
{
[System.Serializable]
public abstract class BaseGraphWindow : EditorWindow
{
protected VisualElement rootView;
protected BaseGraphView graphView;
[SerializeField]
protected BaseGraph graph;
public bool isGraphLoaded
{
get { return graphView != null && graphView.graph != null; }
}
protected void OnEnable()
{
InitializeRootView();
if (graph != null)
InitializeGraph(graph);
}
protected void OnDisable()
{
if (graph != null)
graphView.SaveGraphToDisk();
}
void InitializeRootView()
{
rootView = this.GetRootVisualContainer();
rootView.name = "graphRootView";
rootView.AddStyleSheetPath("GraphProcessorStyles/BaseGraphView");
}
public void InitializeGraph(BaseGraph graph)
{
this.graph = graph;
if (graphView != null)
rootView.Remove(graphView);
//Initialize will provide the BaseGraphView
Initialize(graph);
graphView = rootView.Children().FirstOrDefault(e => e is BaseGraphView) as BaseGraphView;
if (graphView == null)
{
Debug.LogError("GraphView has not been added to the BaseGraph root view !");
return ;
}
graphView.Initialize(graph);
}
public virtual void OnGraphDeleted()
{
if (graph != null)
rootView.Remove(graphView);
graphView = null;
}
protected abstract void Initialize(BaseGraph graph);
}
}

11
NodeGraphProcessor/Editor/BaseGraphWindow.cs.meta


fileFormatVersion: 2
guid: 2b4b18f42b137457bbc04f077fe5fd56
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Callbacks.meta


fileFormatVersion: 2
guid: 63fdfc474ed0f4db7aa1432eaf667691
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

93
NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Reflection;
using UnityEditor.ProjectWindowCallback;
namespace ProceduralWorlds.Editor
{
public static class NodeScriptMenuItem
{
static readonly string nodeBaseName = "Node.cs";
static readonly string nodeViewBaseName = "NodeView.cs";
static readonly string nodeTemplatePath = "Assets/NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt";
static readonly string nodeViewTemplatePath = "Assets/NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt";
static string GetCurrentPath()
{
var path = "";
var obj = Selection.activeObject;
if (obj == null)
return null;
else
path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
if (path.Length > 0)
{
if (Directory.Exists(path))
return path;
else
return new FileInfo(path).Directory.FullName;
}
return null;
}
[MenuItem("Assets/Create/Node C# Script", false, 20)]
private static void CreateNodeCSharpScritpt()
{
string path = GetCurrentPath() + "/" + nodeBaseName;
path = AssetDatabase.GenerateUniqueAssetPath(path);
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(
0,
ScriptableObject.CreateInstance< DoCreateNodeScript >(),
path,
EditorGUIUtility.FindTexture("cs Script Icon"),
Path.GetFullPath(nodeTemplatePath)
);
AssetDatabase.Refresh();
}
[MenuItem("Assets/Create/Node View C# Script", false, 21)]
private static void CreateNodeViewCSharpScritpt()
{
string path = GetCurrentPath() + "/" + nodeViewBaseName;
path = AssetDatabase.GenerateUniqueAssetPath(path);
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(
0,
ScriptableObject.CreateInstance< DoCreateNodeScript >(),
path,
EditorGUIUtility.FindTexture("cs Script Icon"),
Path.GetFullPath(nodeViewTemplatePath)
);
AssetDatabase.Refresh();
}
class DoCreateNodeScript : EndNameEditAction
{
static MethodInfo createScriptAsset = typeof(ProjectWindowUtil).GetMethod("CreateScriptAssetFromTemplate", BindingFlags.Static | BindingFlags.NonPublic);
public override void Action(int instanceId, string pathName, string resourceFile)
{
if (!File.Exists(resourceFile))
{
Debug.LogError("Can't find template: " + resourceFile);
return ;
}
createScriptAsset.Invoke(null, new object[]{ pathName, resourceFile });
var asset = AssetDatabase.LoadAssetAtPath(pathName, typeof(MonoScript));
ProjectWindowUtil.ShowCreatedAsset(asset);
AssetDatabase.Refresh();
}
}
}
}

11
NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs.meta


fileFormatVersion: 2
guid: a2c7e2490c5456c4ca6d567178222b16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

22
NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GraphProcessor;
using System.Linq;
[System.Serializable, NodeMenuItem("Custom/#NAME#")]
public class #SCRIPTNAME# : BaseNode
{
[Input(name = "In")]
public float input;
[Output(name = "Out")]
public float output;
public override string name => "#NAME#";
protected override void Process()
{
output = input * 42;
}
}

7
NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt.meta


fileFormatVersion: 2
guid: a9cbafe2f8c9a0042ad9fcc60c538f05
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

21
NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.UIElements;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using GraphProcessor;
[NodeCustomEditor(typeof(NODE_TYPE))]
public class #SCRIPTNAME# : BaseNodeView
{
public override void Enable()
{
var node = nodeTarget as NODE_TYPE;
// Create your fields using node's variables and add them to the controlsContainer
controlsContainer.Add(new Label("Hello World !"));
}
}

7
NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt.meta


fileFormatVersion: 2
guid: 1cff9adb4a6bd6b4aac3a5472648a524
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

26
NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
namespace GraphProcessor
{
[ExecuteInEditMode]
public class DeleteCallback : UnityEditor.AssetModificationProcessor
{
static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options)
{
var graph = AssetDatabase.LoadAssetAtPath(path, typeof(BaseGraph));
if (graph != null)
{
foreach (var graphWindow in Resources.FindObjectsOfTypeAll< BaseGraphWindow >())
graphWindow.OnGraphDeleted();
}
return AssetDeleteResult.DidNotDelete;
}
}
}

11
NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs.meta


fileFormatVersion: 2
guid: 59cb170ad7b9d4c7394a1a7bfd6b11a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

19
NodeGraphProcessor/Editor/EditorAttributes.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
namespace GraphProcessor
{
[AttributeUsage(AttributeTargets.Class)]
public class NodeCustomEditor : Attribute
{
public Type nodeType;
public NodeCustomEditor(Type nodeType)
{
this.nodeType = nodeType;
}
}
}

11
NodeGraphProcessor/Editor/EditorAttributes.cs.meta


fileFormatVersion: 2
guid: 5c50a793169754f699b4987ff8e0733f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Logic.meta


fileFormatVersion: 2
guid: ae3080c0c3f0d42f38d4300d12b41091
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

60
NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
namespace GraphProcessor
{
public sealed class EdgeConnectorListener : IEdgeConnectorListener
{
readonly BaseGraphView graphView;
Dictionary< Edge, PortView > edgeInputPorts = new Dictionary< Edge, PortView >();
Dictionary< Edge, PortView > edgeOutputPorts = new Dictionary< Edge, PortView >();
public EdgeConnectorListener(BaseGraphView graphView)
{
this.graphView = graphView;
}
public void OnDropOutsidePort(Edge edge, Vector2 position)
{
this.graphView.RegisterCompleteObjectUndo("Disconnect edge");
//If the edge was already existing, remove it
if (!edge.isGhostEdge)
graphView.Disconnect(edge as EdgeView);
//TODO: open new nodes selector and connect the created node if there is one
}
public void OnDrop(GraphView graphView, Edge edge)
{
var edgeView = edge as EdgeView;
bool wasOnTheSamePort = false;
if (edgeView?.input == null || edgeView?.output == null)
return ;
//If the edge was moved to another port
if (edgeView.isConnected)
{
if (edgeInputPorts.ContainsKey(edge) && edgeOutputPorts.ContainsKey(edge))
if (edgeInputPorts[edge] == edge.input && edgeOutputPorts[edge] == edge.output)
wasOnTheSamePort = true;
if (!wasOnTheSamePort)
this.graphView.Disconnect(edgeView);
}
if (edgeView.input.node == null || edgeView.output.node == null)
return;
edgeInputPorts[edge] = edge.input as PortView;
edgeOutputPorts[edge] = edge.output as PortView;
this.graphView.RegisterCompleteObjectUndo("Connected " + edgeView.input.node.name + " and " + edgeView.output.node.name);
this.graphView.Connect(edge as EdgeView, autoDisconnectInputs: !wasOnTheSamePort);
}
}
}

11
NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs.meta


fileFormatVersion: 2
guid: 594eed6e129424e83abd868b8d10d7a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Manipulators.meta


fileFormatVersion: 2
guid: c6072e601ba164a9baaee07146ebd0a2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

125
NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs


using UnityEngine.Experimental.UIElements;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine;
namespace GraphProcessor
{
public class BorderResizer : MouseManipulator
{
bool active;
Vector2 startMousePosition;
Vector2 startComponentSize;
Vector2 startComponentPosition;
readonly int dragBorderSize = 15;
Vector2 dragDirection;
readonly string cursorBorderStyleSheet = "GraphProcessorStyles/BorderResizer";
GraphElement elem;
public BorderResizer()
{
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
}
protected override void RegisterCallbacksOnTarget()
{
elem = target as GraphElement;
if (elem == null)
throw new System.InvalidOperationException("BorderReiszer can only be added to a GraphElement");
target.RegisterCallback< MouseDownEvent >(OnMouseDown);
target.RegisterCallback< MouseMoveEvent >(OnMouseMove);
target.RegisterCallback< MouseUpEvent >(OnMouseUp);
if (!target.HasStyleSheetPath(cursorBorderStyleSheet))
target.AddStyleSheetPath(cursorBorderStyleSheet);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback< MouseDownEvent >(OnMouseDown);
target.UnregisterCallback< MouseMoveEvent >(OnMouseMove);
target.UnregisterCallback< MouseUpEvent >(OnMouseUp);
}
void OnMouseDown(MouseDownEvent e)
{
if (active)
{
e.StopPropagation();
return ;
}
if (MouseCaptureController.IsMouseCaptured())
return ;
if (!IsMouseOverBorders(e.localMousePosition))
return;
if (CanStartManipulation(e))
{
active = true;
target.CaptureMouse();
e.StopPropagation();
startComponentSize = new Vector2(elem.style.width, elem.style.height);
startMousePosition = e.localMousePosition;
startComponentPosition = elem.transform.position;
}
else
Debug.Log("can't start manipulation !");
}
void OnMouseMove(MouseMoveEvent e)
{
if (!active)
return ;
Vector2 delta = e.localMousePosition - startMousePosition + (Vector2)elem.transform.position - startComponentPosition;
elem.style.width = startComponentSize.x + delta.x * dragDirection.x;
elem.style.height = startComponentSize.y + delta.y * dragDirection.y;
elem.transform.position -= (Vector3)(e.mouseDelta * Vector2.Min(Vector2.zero, dragDirection));
}
void OnMouseUp(MouseUpEvent e)
{
if (!active)
return ;
if (CanStopManipulation(e))
{
target.ReleaseMouse();
e.StopPropagation();
GraphView graphView = elem.GetFirstAncestorOfType<GraphView>();
if (graphView != null && graphView.elementResized != null)
graphView.elementResized(elem);
}
active = false;
}
bool IsMouseOverBorders(Vector2 mousePosition)
{
Rect borders = new Rect(Vector2.zero, target.localBound.size);
dragDirection = Vector2.zero;
if (mousePosition.x - borders.xMin < dragBorderSize)
dragDirection.x = -1;
if (borders.xMax - mousePosition.x < dragBorderSize)
dragDirection.x = 1;
if (mousePosition.y - borders.yMin < dragBorderSize)
dragDirection.y = -1;
if (borders.yMax - mousePosition.y < dragBorderSize)
dragDirection.y = 1;
return dragDirection != Vector2.zero;
}
}
}

11
NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs.meta


fileFormatVersion: 2
guid: 2184598ff73294c1b9dd5255d8545679
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

75
NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs


using System;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEngine.Experimental.UIElements.StyleSheets;
namespace GraphProcessor
{
public class ConfinedDragger : MouseManipulator
{
bool active;
Vector3 offset;
VisualElement container;
VisualElement handle;
public Action onDragEnd;
public ConfinedDragger(VisualElement container)
{
this.container = container;
active = false;
}
protected override void RegisterCallbacksOnTarget()
{
handle = target;
handle.RegisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDown.NoTrickleDown);
handle.RegisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDown.NoTrickleDown);
handle.RegisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDown.NoTrickleDown);
}
protected override void UnregisterCallbacksFromTarget()
{
handle.UnregisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDown.NoTrickleDown);
handle.UnregisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDown.NoTrickleDown);
handle.UnregisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDown.NoTrickleDown);
}
void OnMouseDown(MouseDownEvent evt)
{
active = true;
offset = evt.mousePosition - (Vector2)target.transform.position;
handle.CaptureMouse();
evt.StopImmediatePropagation();
}
void OnMouseMove(MouseMoveEvent evt)
{
if (active)
{
Vector3 position = (Vector3)evt.mousePosition - offset;
position.x = Mathf.Clamp(position.x, -target.layout.position.x, container.layout.width - target.layout.position.x - target.localBound.size.x);
position.y = Mathf.Clamp(position.y, -target.layout.position.y, container.layout.height - target.layout.position.y - target.localBound.size.y);
target.transform.position = position;
}
}
void OnMouseUp(MouseUpEvent evt)
{
active = false;
if (handle.HasMouseCapture())
handle.ReleaseMouse();
evt.StopImmediatePropagation();
if (onDragEnd != null)
onDragEnd();
}
}
}

11
NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs.meta


fileFormatVersion: 2
guid: 8984ae8e754a344d7a6361c06cd1b9b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/PortBehaviors.meta


fileFormatVersion: 2
guid: cffd7e4ce183a9f48927dc1c49f90616
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

19
NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEngine;
using System.Reflection;
using System.Linq;
namespace GraphProcessor
{
public class DefaultPortBehavior
{
public DefaultPortBehavior(BaseNodeView nodeView, FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name)
{
nodeView.AddPort(fieldInfo, direction, listener, isMultiple, name);
}
}
}

11
NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs.meta


fileFormatVersion: 2
guid: 0c02c9f760c77ef44a7696e41c76d3a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

98
NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEngine;
using System.Reflection;
using System.Linq;
namespace GraphProcessor
{
[CustomPortBehavior(typeof(MultiPorts))]
public class MultiPortBehavior
{
MultiPorts multiPorts;
BaseNodeView node;
Dictionary< Edge, PortView > portViews = new Dictionary< Edge, PortView >();
FieldInfo fieldInfo;
Direction direction;
EdgeConnectorListener listener;
bool isMultiple;
string name;
public MultiPortBehavior(BaseNodeView nodeView, FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name)
{
this.multiPorts = fieldInfo.GetValue(nodeView.nodeTarget) as MultiPorts;
this.node = nodeView;
this.fieldInfo = fieldInfo;
this.direction = direction;
this.listener = listener;
this.isMultiple = isMultiple;
this.name = name;
// Initialize the MultiPort field if null
if (multiPorts == null)
{
multiPorts = new MultiPorts();
fieldInfo.SetValue(nodeView.nodeTarget, multiPorts);
}
// Instantiate all ports needed to create the serialized connections
// Minus one because we count our current instance
for (int i = 0; i < multiPorts.portCount; i++)
AddPort();
}
void AddPort()
{
PortView pv = node.AddPort(fieldInfo, direction, listener, isMultiple, name);
// We force the AddPort in the BaseNode class because the port list is not updated except at the construction of the class
node.nodeTarget.AddPort(direction == Direction.Input, pv.fieldName);
pv.OnConnected += OnPortConnected;
pv.OnDisconnected += OnPortDisconnected;
}
public void OnPortConnected(PortView pv, Edge edge)
{
// Fix port datas
if (pv.direction == Direction.Input)
edge.input = pv;
else
edge.output = pv;
// If the edge is already connected, ignore it
if (portViews.ContainsKey(edge))
return ;
portViews[edge] = pv;
if (pv.GetEdges().Count == 0)
{
multiPorts.AddUniqueId(multiPorts.GetUniqueId());
AddPort();
}
}
public void OnPortDisconnected(PortView pv, Edge edge)
{
if (pv.GetEdges().Count == 0)
{
if ((edge as EdgeView).isConnected && portViews.ContainsKey(edge))
{
var portToRemove = portViews[edge];
node.RemovePort(portToRemove);
node.nodeTarget.RemovePort(direction == Direction.Input, portToRemove.fieldName);
portViews.Remove(edge);
multiPorts.RemoveUniqueId(0);
}
}
}
}
}

11
NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs.meta


fileFormatVersion: 2
guid: 9a47c447ebb4fe54c8922feadb2782f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

41
NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
using System.Linq;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
namespace GraphProcessor
{
public static class PortBehaviorFactory
{
static Dictionary<Type, Type> portBehaviors = new Dictionary<Type, Type>();
static PortBehaviorFactory()
{
foreach (var type in AppDomain.CurrentDomain.GetAllTypes())
{
var customPortBehaviorAttr = type.GetCustomAttribute< CustomPortBehaviorAttribute >();
if (customPortBehaviorAttr == null)
continue ;
portBehaviors[customPortBehaviorAttr.targetType] = type;
}
}
public static void CreatePortBehavior(BaseNodeView nodeView, FieldInfo field, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name)
{
Type behaviorType;
portBehaviors.TryGetValue(field.FieldType, out behaviorType);
if (behaviorType == null)
behaviorType = typeof(DefaultPortBehavior);
Activator.CreateInstance(behaviorType, nodeView, field, direction, listener, isMultiple, name);
}
}
}

11
NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs.meta


fileFormatVersion: 2
guid: 379e2785adbd6ab43adf7682b6d77b69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Resources.meta


fileFormatVersion: 2
guid: a15334d6fa12046e5afcb22ac791a43d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles.meta


fileFormatVersion: 2
guid: 6562f61ebe4c045d29fe4b1a3457379a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

4
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss


#graphRootView
{
background-color: #101010;
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss.meta


fileFormatVersion: 2
guid: 2769cf0fb82ce4c2691edb49469f5f17
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

7
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss


#node {
background-color: rgba(0, 63, 63, 0.8);
}
#controls {
background-color: rgba(63, 63, 63, 0.8);
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss.meta


fileFormatVersion: 2
guid: 7aed4ab0823d4432996ae4614575bc7c
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

4
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss


#headerColorPicker {
width: 50;
align: right;
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss.meta


fileFormatVersion: 2
guid: 778f73de1e04f4acd871308e30971a42
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

3
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss


EdgeView.Single {
color: #800080
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss.meta


fileFormatVersion: 2
guid: 28f83445e912a4e25aa30a4f0cd22636
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

50
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss


#PinnedElementView {
flex-direction: column;
position-type: absolute;
position-right: 10;
position-bottom: 10;
background-color: rgb(79, 79, 79);
justify-content: flex-start;
border-radius: 6;
border-top-width: 1;
border-bottom-width: 1;
border-left-width: 1;
border-right-width: 1;
border-color: rgb(25,25,25);
}
#PinnedElementView > #header {
flex-direction: row;
justify-content: space-between;
background-color: rgb(64, 64, 64);
padding-top: 8;
padding-bottom: 8;
padding-left: 8;
padding-right: 8;
border-top-left-radius: 6;
border-top-right-radius: 6;
}
#PinnedElementView > #header > #title {
font-size: 12;
text-color: rgb(180, 180, 180);
padding-top: 1;
padding-bottom: 2;
padding-left: 2;
padding-right: 2;
}
#PinnedElementView > #content {
flex-grow: 1;
border-width: 10;
flex-direction: row;
border-color: rgb(0,10,190);
}
#PinnedElementView.collapsed{
background-color: rgb(206, 53, 185);
}
#PinnedElementView.expanded{
background-color: rgb(206, 53, 185);
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss.meta


fileFormatVersion: 2
guid: 2fdbf4d830a3942a18aafb8fd7a5fa53
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

50
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss


PortView {
height: 24;
align-items: center;
padding-left: 4;
padding-right: 4;
port-color: rgb(200, 200, 00);
disabled-port-color: rgb(0, 70, 70);
}
PortView.input {
flex-direction: row;
}
PortView.output {
flex-direction: row-reverse;
}
PortView > #connector {
border-color: rgb(255, 255, 0);
background-color: #212121;
width: 8;
height: 8;
border-radius: 8;
align-items: center;
justify-content: center;
margin-left: 4;
margin-right: 4;
border-left-width:1;
border-top-width:1;
border-right-width:1;
border-bottom-width:1;
}
PortView > #connector:hover {
border-color: #f0f0f0
}
PortView > #connector > #cap
{
background-color: #212121;
width: 4;
height: 4;
border-radius: 4;
}
PortView > #connector > #cap:hover
{
background-color: #f0f0f0;
}

10
NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss.meta


fileFormatVersion: 2
guid: 7f9f1707b6119456581ab1a100d96aaa
ScriptedImporter:
fileIDToRecycleName:
11400000: stylesheet
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}

8
NodeGraphProcessor/Editor/Utils.meta


fileFormatVersion: 2
guid: 5e5f8827aa14940f59f6f29179b03d0c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

14
NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GraphProcessor
{
[System.Serializable]
public class CopyPasteHelper
{
public List< JsonElement > copiedNodes = new List< JsonElement >();
public List< JsonElement > copiedCommentBlocks = new List< JsonElement >();
}
}

11
NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs.meta


fileFormatVersion: 2
guid: ad4ab8e74dd9540cab3bc65ba3b8b58c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

114
NodeGraphProcessor/Editor/Utils/FieldFactory.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
using UnityEditor.Experimental.UIElements;
using System;
using System.Linq;
using System.Reflection;
namespace GraphProcessor
{
public static class FieldFactory
{
static readonly Dictionary< Type, Type > fieldDrawers = new Dictionary< Type, Type >();
static readonly MethodInfo createFieldMethod = typeof(FieldFactory).GetMethod("CreateFieldSpecific", BindingFlags.Static | BindingFlags.Public);
static FieldFactory()
{
foreach (var type in AppDomain.CurrentDomain.GetAllTypes())
{
var drawerAttribute = type.GetCustomAttributes(typeof(FieldDrawerAttribute), false).FirstOrDefault() as FieldDrawerAttribute;
if (drawerAttribute == null)
continue ;
AddDrawer(drawerAttribute.fieldType, type);
}
// щ(ºДºщ) ...
AddDrawer(typeof(int), typeof(IntegerField));
AddDrawer(typeof(long), typeof(LongField));
AddDrawer(typeof(float), typeof(FloatField));
AddDrawer(typeof(double), typeof(DoubleField));
AddDrawer(typeof(string), typeof(TextField));
AddDrawer(typeof(Bounds), typeof(BoundsField));
AddDrawer(typeof(Color), typeof(ColorField));
AddDrawer(typeof(Vector2), typeof(Vector2Field));
AddDrawer(typeof(Vector3), typeof(Vector3Field));
AddDrawer(typeof(Vector4), typeof(Vector4Field));
AddDrawer(typeof(AnimationCurve), typeof(CurveField));
AddDrawer(typeof(Enum), typeof(EnumField));
AddDrawer(typeof(Gradient), typeof(GradientField));
AddDrawer(typeof(UnityEngine.Object), typeof(ObjectField));
AddDrawer(typeof(Rect), typeof(RectField));
}
static void AddDrawer(Type fieldType, Type drawerType)
{
var iNotifyType = typeof(INotifyValueChanged<>).MakeGenericType(fieldType);
if (!iNotifyType.IsAssignableFrom(drawerType))
{
Debug.LogWarning("The custom field drawer " + drawerType + " does not implements INotifyValueChanged< " + fieldType + " >");
return ;
}
fieldDrawers[fieldType] = drawerType;
}
public static INotifyValueChanged< T > CreateField< T >()
{
return CreateField(typeof(T)) as INotifyValueChanged< T >;
}
public static VisualElement CreateField(Type t)
{
Type drawerType;
fieldDrawers.TryGetValue(t, out drawerType);
if (drawerType == null)
drawerType = fieldDrawers.FirstOrDefault(kp => kp.Key.IsReallyAssignableFrom(t)).Value;
if (drawerType == null)
{
Debug.LogWarning("Can't find field drawer for type: " + t);
return null;
}
var field = Activator.CreateInstance(drawerType);
// For mutiline
if (field is TextField)
{
(field as TextField).multiline = true;
}
return field as VisualElement;
}
public static INotifyValueChanged< T > CreateFieldSpecific< T >(FieldInfo field, T value, Action< object > onValueChanged)
{
var fieldDrawer = CreateField< T >();
if (fieldDrawer == null)
return null;
fieldDrawer.value = value;
fieldDrawer.OnValueChanged((e) => {
onValueChanged(e.newValue);
});
return fieldDrawer as INotifyValueChanged< T >;
}
public static VisualElement CreateField(FieldInfo field, object value, Action< object > onValueChanged)
{
var createFieldSpecificMethod = createFieldMethod.MakeGenericMethod(field.FieldType);
return createFieldSpecificMethod.Invoke(null, new object[]{field, value, onValueChanged}) as VisualElement;
}
}
}

11
NodeGraphProcessor/Editor/Utils/FieldFactory.cs.meta


fileFormatVersion: 2
guid: 8e070bfe6917e4be9bff3e56c4cda092
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

102
NodeGraphProcessor/Editor/Utils/NodeProvider.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using UnityEngine.Experimental.UIElements;
using System.Linq;
namespace GraphProcessor
{
public static class NodeProvider
{
static Dictionary< Type, Type > nodeViewPerType = new Dictionary< Type, Type >();
static Dictionary< string, Type > nodePerMenuTitle = new Dictionary< string, Type >();
static Dictionary< Type, string > nodeViewScripts = new Dictionary< Type, string >();
static Dictionary< Type, string > nodeScripts = new Dictionary< Type, string >();
static NodeProvider()
{
foreach (var type in AppDomain.CurrentDomain.GetAllTypes())
{
if (type.IsClass && !type.IsAbstract)
{
if (type.IsSubclassOf(typeof(BaseNode)))
AddNodeType(type);
if (type.IsSubclassOf(typeof(BaseNodeView)))
AddNodeViewType(type);
}
}
}
static void AddNodeType(Type type)
{
var attrs = type.GetCustomAttributes(typeof(NodeMenuItemAttribute), false) as NodeMenuItemAttribute[];
if (attrs != null && attrs.Length > 0)
nodePerMenuTitle[attrs.First().menuTitle] = type;
var nodeScriptAsset = FindScriptFromClassName(type.Name);
if (nodeScriptAsset != null)
nodeScripts[type] = nodeScriptAsset;
}
static void AddNodeViewType(Type type)
{
var attrs = type.GetCustomAttributes(typeof(NodeCustomEditor), false) as NodeCustomEditor[];
if (attrs != null && attrs.Length > 0)
{
Type nodeType = attrs.First().nodeType;
nodeViewPerType[nodeType] = type;
var nodeViewScriptAsset = FindScriptFromClassName(type.Name);
if (nodeViewScriptAsset != null)
nodeViewScripts[type] = nodeViewScriptAsset;
}
}
static string FindScriptFromClassName(string className)
{
var scriptGUIDs = AssetDatabase.FindAssets(className);
if (scriptGUIDs.Length == 0)
return null;
return AssetDatabase.GUIDToAssetPath(scriptGUIDs[0]);
}
public static Type GetNodeViewTypeFromType(Type nodeType)
{
Type view;
nodeViewPerType.TryGetValue(nodeType, out view);
return view;
}
public static Dictionary< string, Type > GetNodeMenuEntries()
{
return nodePerMenuTitle;
}
public static string GetNodeViewScript(Type type)
{
string scriptPath;
nodeViewScripts.TryGetValue(type, out scriptPath);
return scriptPath;
}
public static string GetNodeScript(Type type)
{
string scriptPath;
nodeScripts.TryGetValue(type, out scriptPath);
return scriptPath;
}
}
}

11
NodeGraphProcessor/Editor/Utils/NodeProvider.cs.meta


fileFormatVersion: 2
guid: 0f90580539cbf48d58ba35c626500169
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Editor/Views.meta


fileFormatVersion: 2
guid: 600ac8da8b308477fa0dfcd14d40ce53
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

585
NodeGraphProcessor/Editor/Views/BaseGraphView.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.UIElements;
using UnityEngine.Experimental.UIElements;
using UnityEditor.Experimental.UIElements.GraphView;
using System.Linq;
using System;
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags;
using Object = UnityEngine.Object;
namespace GraphProcessor
{
public class BaseGraphView : GraphView
{
public BaseGraph graph;
public EdgeConnectorListener connectorListener;
public List< BaseNodeView > nodeViews = new List< BaseNodeView >();
public Dictionary< BaseNode, BaseNodeView > nodeViewsPerNode = new Dictionary< BaseNode, BaseNodeView >();
public List< EdgeView > edgeViews = new List< EdgeView >();
public List< CommentBlockView > commentBlockViews = new List< CommentBlockView >();
Dictionary< Type, PinnedElementView > pinnedElements = new Dictionary< Type, PinnedElementView >();
public delegate void ComputeOrderUpdatedDelegate();
public event Action initialized;
public event ComputeOrderUpdatedDelegate computeOrderUpdated;
public BaseGraphView()
{
serializeGraphElements = SerializeGraphElementsCallback;
canPasteSerializedData = CanPasteSerializedDataCallback;
unserializeAndPaste = UnserializeAndPasteCallback;
graphViewChanged = GraphViewChangedCallback;
viewTransformChanged = ViewTransformChangedCallback;
elementResized = ElementResizedCallback;
InitializeManipulators();
RegisterCallback< KeyDownEvent >(KeyDownCallback);
SetupZoom(0.05f, 2f);
Undo.undoRedoPerformed += ReloadView;
this.StretchToParentSize();
}
#region Callbacks
protected override bool canCopySelection
{
get { return selection.Any(e => e is BaseNodeView || e is CommentBlockView); }
}
protected override bool canCutSelection
{
get { return selection.Any(e => e is BaseNodeView || e is CommentBlockView); }
}
string SerializeGraphElementsCallback(IEnumerable<GraphElement> elements)
{
var data = new CopyPasteHelper();
foreach (var nodeView in elements.Where(e => e is BaseNodeView))
{
var node = ((nodeView) as BaseNodeView).nodeTarget;
data.copiedNodes.Add(JsonSerializer.Serialize< BaseNode >(node));
}
foreach (var commentBlockView in elements.Where(e => e is CommentBlockView))
{
var commentBlock = (commentBlockView as CommentBlockView).commentBlock;
data.copiedCommentBlocks.Add(JsonSerializer.Serialize< CommentBlock >(commentBlock));
}
ClearSelection();
return JsonUtility.ToJson(data, true);
}
bool CanPasteSerializedDataCallback(string serializedData)
{
try {
return JsonUtility.FromJson(serializedData, typeof(CopyPasteHelper)) != null;
} catch {
return false;
}
}
void UnserializeAndPasteCallback(string operationName, string serializedData)
{
var data = JsonUtility.FromJson< CopyPasteHelper >(serializedData);
RegisterCompleteObjectUndo(operationName);
foreach (var serializedNode in data.copiedNodes)
{
var node = JsonSerializer.DeserializeNode(serializedNode);
//Call OnNodeCreated on the new fresh copied node
node.OnNodeCreated();
//And move a bit the new node
node.position.position += new Vector2(20, 20);
AddNode(node);
//Select the new node
AddToSelection(nodeViewsPerNode[node]);
}
foreach (var serializedCommentBlock in data.copiedCommentBlocks)
{
var commentBlock = JsonSerializer.Deserialize<CommentBlock>(serializedCommentBlock);
//Same than for node
commentBlock.OnCreated();
commentBlock.position.position += new Vector2(20, 20);
AddCommentBlock(commentBlock);
}
}
GraphViewChange GraphViewChangedCallback(GraphViewChange changes)
{
if (changes.elementsToRemove != null)
{
RegisterCompleteObjectUndo("Remove Graph Elements");
//Handle ourselves the edge and node remove
changes.elementsToRemove.RemoveAll(e => {
var edge = e as EdgeView;
var node = e as BaseNodeView;
var commentBlock = e as CommentBlockView;
if (edge != null)
{
Disconnect(edge);
return true;
}
else if (node != null)
{
graph.RemoveNode(node.nodeTarget);
RemoveElement(node);
return true;
}
else if (commentBlock != null)
{
graph.RemoveCommentBlock(commentBlock.commentBlock);
RemoveElement(commentBlock);
return true;
}
return false;
});
}
return changes;
}
void ViewTransformChangedCallback(GraphView view)
{
graph.position = viewTransform.position;
graph.scale = viewTransform.scale;
}
void ElementResizedCallback(VisualElement elem)
{
var commentBlockView = elem as CommentBlockView;
if (commentBlockView != null)
commentBlockView.commentBlock.size = commentBlockView.GetPosition().size;
}
public override void OnPersistentDataReady()
{
//We set the position and scale saved in the graph asset file
Vector3 pos = graph.position;
Vector3 scale = graph.scale;
base.OnPersistentDataReady();
UpdateViewTransform(pos, scale);
}
public override List< Port > GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
var compatiblePorts = new List< Port >();
compatiblePorts.AddRange(ports.ToList().Where(p => {
var portView = p as PortView;
if (p.direction == startPort.direction)
return false;
//Check if there is custom adapters for this assignation
if (CustomPortIO.IsAssignable(startPort.portType, p.portType))
return true;
//Check for type assignability
if (!p.portType.IsReallyAssignableFrom(startPort.portType))
return false;
//Check if the edge already exists
if (portView.GetEdges().Any(e => e.input == startPort || e.output == startPort))
return false;
return true;
}));
return compatiblePorts;
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
BuildCreateContextualMenu(evt);
BuildViewContextualMenu(evt);
base.BuildContextualMenu(evt);
BuildSelectAssetContextualMenu(evt);
BuildSaveAssetContextualMenu(evt);
}
protected void BuildCreateContextualMenu(ContextualMenuPopulateEvent evt)
{
Vector2 position = evt.mousePosition - (Vector2)viewTransform.position;
evt.menu.AppendAction("Create/Comment Block", (e) => AddCommentBlock(new CommentBlock("New Comment Block", position)), DropdownMenu.MenuAction.AlwaysEnabled);
}
protected void BuildViewContextualMenu(ContextualMenuPopulateEvent evt)
{
evt.menu.AppendAction("View/Processor", (e) => ToggleView< ProcessorView >(), (e) => GetPinnedElementStatus< ProcessorView >());
}
protected void BuildSelectAssetContextualMenu(ContextualMenuPopulateEvent evt)
{
evt.menu.AppendAction("Select Asset", (e) => EditorGUIUtility.PingObject(graph), DropdownMenu.MenuAction.AlwaysEnabled);
}
protected void BuildSaveAssetContextualMenu(ContextualMenuPopulateEvent evt)
{
evt.menu.AppendAction("Save Asset", (e) => {
EditorUtility.SetDirty(graph);
AssetDatabase.SaveAssets();
}, DropdownMenu.MenuAction.AlwaysEnabled);
}
void KeyDownCallback(KeyDownEvent e)
{
if (e.keyCode == KeyCode.S)
{
SaveGraphToDisk();
e.StopPropagation();
}
}
#endregion
#region Initialization
void ReloadView()
{
// Remove everything
RemoveNodeViews();
RemoveEdges();
RemoveCommentBlocks();
// And re-add with new up to date datas
InitializeNodeViews();
InitializeEdgeViews();
InitializeCommentBlocks();
Reload();
UpdateComputeOrder();
}
public void Initialize(BaseGraph graph)
{
if (this.graph != null)
SaveGraphToDisk();
this.graph = graph;
connectorListener = new EdgeConnectorListener(this);
InitializeNodeViews();
InitializeEdgeViews();
InitializeViews();
InitializeCommentBlocks();
UpdateComputeOrder();
if (initialized != null)
initialized();
}
void InitializeNodeViews()
{
graph.nodes.RemoveAll(n => n == null);
foreach (var node in graph.nodes)
AddNodeView(node);
}
void InitializeEdgeViews()
{
foreach (var serializedEdge in graph.edges)
{
var inputNodeView = nodeViewsPerNode[serializedEdge.inputNode];
var outputNodeView = nodeViewsPerNode[serializedEdge.outputNode];
var edgeView = new EdgeView() {
userData = serializedEdge,
input = inputNodeView.GetPortFromFieldName(serializedEdge.inputFieldName),
output = outputNodeView.GetPortFromFieldName(serializedEdge.outputFieldName)
};
Connect(edgeView, false);
}
}
void InitializeViews()
{
foreach (var viewType in graph.pinnedWindows)
OpenPinned(viewType.editorType.type);
}
void InitializeCommentBlocks()
{
foreach (var commentBlock in graph.commentBlocks)
AddCommentBlockView(commentBlock);
}
protected virtual void InitializeManipulators()
{
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ClickSelector());
}
protected virtual void Reload() {}
#endregion
#region Graph content modification
protected bool AddNode(BaseNode node)
{
AddNodeView(node);
graph.AddNode(node);
UpdateComputeOrder();
return true;
}
protected bool AddNodeView(BaseNode node)
{
var viewType = NodeProvider.GetNodeViewTypeFromType(node.GetType());
if (viewType == null)
viewType = typeof(BaseNodeView);
var baseNodeView = Activator.CreateInstance(viewType) as BaseNodeView;
baseNodeView.Initialize(this, node);
AddElement(baseNodeView);
nodeViews.Add(baseNodeView);
nodeViewsPerNode[node] = baseNodeView;
return true;
}
void RemoveNodeViews()
{
foreach (var nodeView in nodeViews)
RemoveElement(nodeView);
nodeViews.Clear();
nodeViewsPerNode.Clear();
}
public void AddCommentBlock(CommentBlock block)
{
graph.AddCommentBlock(block);
block.OnCreated();
AddCommentBlockView(block);
}
public void AddCommentBlockView(CommentBlock block)
{
var c = new CommentBlockView();
c.Initialize(this, block);
AddElement(c);
commentBlockViews.Add(c);
}
public void RemoveCommentBlocks()
{
foreach (var commentBlockView in commentBlockViews)
RemoveElement(commentBlockView);
commentBlockViews.Clear();
}
public void Connect(EdgeView e, bool serializeToGraph = true, bool autoDisconnectInputs = true)
{
if (e.input == null || e.output == null)
return ;
//If the input port does not support multi-connection, we remove them
if (autoDisconnectInputs && !(e.input as PortView).isMultiple)
foreach (var edge in edgeViews.Where(ev => ev.input == e.input))
{
// TODO: do not disconnect them if the connected port is the same than the old connected
Disconnect(edge, serializeToGraph);
}
AddElement(e);
e.input.Connect(e);
e.output.Connect(e);
var inputNodeView = e.input.node as BaseNodeView;
var outputNodeView = e.output.node as BaseNodeView;
if (inputNodeView == null || outputNodeView == null)
{
Debug.LogError("Connect aborted !");
return ;
}
edgeViews.Add(e);
if (serializeToGraph)
{
e.userData = graph.Connect(
inputNodeView.nodeTarget, (e.input as PortView).fieldName,
outputNodeView.nodeTarget, (e.output as PortView).fieldName
);
}
inputNodeView.RefreshPorts();
outputNodeView.RefreshPorts();
inputNodeView.nodeTarget.OnEdgeConnected(e.userData as SerializableEdge);
outputNodeView.nodeTarget.OnEdgeConnected(e.userData as SerializableEdge);
e.isConnected = true;
if (serializeToGraph)
UpdateComputeOrder();
}
public void Disconnect(EdgeView e, bool serializeToGraph = true)
{
var serializableEdge = e.userData as SerializableEdge;
RemoveElement(e);
if (e?.input?.node != null)
{
var inputNodeView = e.input.node as BaseNodeView;
e.input.Disconnect(e);
inputNodeView.nodeTarget.OnEdgeDisonnected(e.serializedEdge);
inputNodeView.RefreshPorts();
}
if (e?.output?.node != null)
{
var outputNodeView = e.output.node as BaseNodeView;
e.output.Disconnect(e);
outputNodeView.nodeTarget.OnEdgeDisonnected(e.serializedEdge);
outputNodeView.RefreshPorts();
}
// Remove the serialized edge if there was one
if (serializableEdge != null)
{
if (serializeToGraph)
graph.Disconnect(serializableEdge.GUID);
UpdateComputeOrder();
}
}
public void RemoveEdges()
{
foreach (var edge in edgeViews)
RemoveElement(edge);
edgeViews.Clear();
}
public void UpdateComputeOrder()
{
graph.UpdateComputeOrder();
computeOrderUpdated?.Invoke();
}
public void RegisterCompleteObjectUndo(string name)
{
Undo.RegisterCompleteObjectUndo(graph, name);
}
public void SaveGraphToDisk()
{
EditorUtility.SetDirty(graph);
}
public void ToggleView< T >() where T : PinnedElementView
{
ToggleView(typeof(T));
}
public void ToggleView(Type type)
{
PinnedElementView view;
pinnedElements.TryGetValue(type, out view);
if (view == null)
OpenPinned(type);
else
ClosePinned(type, view);
}
public void OpenPinned(Type type)
{
PinnedElementView view;
if (type == null)
return ;
PinnedElement elem = graph.OpenPinned(type);
view = Activator.CreateInstance(type) as PinnedElementView;
pinnedElements[type] = view;
view.InitializeGraphView(elem, this);
ConfinedDragger masterPreviewViewDraggable = new ConfinedDragger(this);
masterPreviewViewDraggable.onDragEnd = () => elem.position = view.transform.position;
view.AddManipulator(masterPreviewViewDraggable);
Add(view);
}
public void ClosePinned(Type type, PinnedElementView elem)
{
pinnedElements.Remove(type);
Remove(elem);
graph.ClosePinned(type);
}
public StatusFlags GetPinnedElementStatus< T >() where T : PinnedElementView
{
return GetPinnedElementStatus(typeof(T));
}
public StatusFlags GetPinnedElementStatus(Type type)
{
var pinned = graph.pinnedWindows.Find(p => p.editorType.type == type);
if (pinned != null && pinned.opened)
return StatusFlags.Normal;
else
return StatusFlags.Hidden;
}
public void ResetPositionAndZoom()
{
graph.position = Vector3.zero;
graph.scale = Vector3.one;
UpdateViewTransform(graph.position, graph.scale);
}
#endregion
}
}

11
NodeGraphProcessor/Editor/Views/BaseGraphView.cs.meta


fileFormatVersion: 2
guid: 82433700726b148b2af8af687c24fa3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

245
NodeGraphProcessor/Editor/Views/BaseNodeView.cs


using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEditor;
using System.Reflection;
using System;
using System.Linq;
using UnityEditorInternal;
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags;
using NodeView = UnityEditor.Experimental.UIElements.GraphView.Node;
namespace GraphProcessor
{
[NodeCustomEditor(typeof(BaseNode))]
public class BaseNodeView : NodeView
{
public BaseNode nodeTarget;
public List< Port > inputPorts = new List< Port >();
public List< Port > outputPorts = new List< Port >();
public BaseGraphView owner { private set; get; }
protected Dictionary< string, Port > portsPerFieldName = new Dictionary< string, Port >();
protected VisualElement controlsContainer;
protected VisualElement debugContainer;
Label computeOrderLabel = new Label();
#region Initialization
public void Initialize(BaseGraphView owner, BaseNode node)
{
nodeTarget = node;
this.owner = owner;
owner.computeOrderUpdated += ComputeOrderUpdatedCallback;
AddStyleSheetPath("GraphProcessorStyles/BaseNodeView");
InitializePorts();
InitializeView();
InitializeDebug();
Enable();
this.RefreshPorts();
}
void InitializePorts()
{
foreach (var fieldInfo in nodeTarget.nodeFields)
{
// This will automatically create our visual ports
PortBehaviorFactory.CreatePortBehavior(
this,
fieldInfo.Value.info,
fieldInfo.Value.input ? Direction.Input : Direction.Output,
owner.connectorListener,
fieldInfo.Value.isMultiple,
fieldInfo.Value.name
);
}
}
void InitializeView()
{
controlsContainer = new VisualElement{ name = "controls" };
mainContainer.Add(controlsContainer);
debugContainer = new VisualElement{ name = "debug" };
mainContainer.Add(debugContainer);
title = (string.IsNullOrEmpty(nodeTarget.name)) ? nodeTarget.GetType().Name : nodeTarget.name;
SetPosition(nodeTarget.position);
}
void InitializeDebug()
{
ComputeOrderUpdatedCallback();
debugContainer.Add(computeOrderLabel);
}
#endregion
#region API
public Port GetPortFromFieldName(string fieldName)
{
Port ret;
portsPerFieldName.TryGetValue(fieldName, out ret);
return ret;
}
public PortView AddPort(FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple = false, string name = null)
{
// TODO: hardcoded value
PortView p = new PortView(Orientation.Horizontal, direction, fieldInfo, listener);
if (p.direction == Direction.Input)
{
inputPorts.Add(p);
inputContainer.Add(p);
}
else
{
outputPorts.Add(p);
outputContainer.Add(p);
}
p.Initialize(this, isMultiple, name);
portsPerFieldName[p.fieldName] = p;
return p;
}
public void RemovePort(PortView p)
{
if (p.direction == Direction.Input)
{
inputPorts.Remove(p);
inputContainer.Remove(p);
}
else
{
outputPorts.Remove(p);
outputContainer.Remove(p);
}
portsPerFieldName.Remove(p.fieldName);
}
public void OpenNodeViewScript()
{
var scriptPath = NodeProvider.GetNodeViewScript(GetType());
if (scriptPath != null)
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0);
}
public void OpenNodeScript()
{
var scriptPath = NodeProvider.GetNodeScript(nodeTarget.GetType());
if (scriptPath != null)
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0);
}
#endregion
#region Callbacks & Overrides
void ComputeOrderUpdatedCallback()
{
//Update debug compute order
computeOrderLabel.text = "Compute order: " + nodeTarget.computeOrder;
}
public virtual void Enable()
{
DrawDefaultInspector();
}
public virtual void DrawDefaultInspector()
{
var fields = nodeTarget.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
//skip if the field is not serializable
if (!field.IsPublic && field.GetCustomAttribute(typeof(SerializeField)) == null)
continue ;
//skip if the field is an input/output and not marked as SerializedField
if (field.GetCustomAttribute(typeof(SerializeField)) == null && (field.GetCustomAttribute(typeof(InputAttribute)) != null || field.GetCustomAttribute(typeof(OutputAttribute)) != null))
continue ;
//skip if marked with NonSerialized or HideInInspector
if (field.GetCustomAttribute(typeof(System.NonSerializedAttribute)) != null || field.GetCustomAttribute(typeof(HideInInspector)) != null)
continue ;
var controlLabel = new Label(field.Name);
controlsContainer.Add(controlLabel);
var element = FieldFactory.CreateField(field, field.GetValue(nodeTarget), (newValue) => {
field.SetValue(nodeTarget, newValue);
owner.RegisterCompleteObjectUndo("Updated " + newValue);
});
if (element != null)
controlsContainer.Add(element);
}
}
public virtual void OnPortConnected(PortView port) {}
public virtual void OnPortDisconnected(PortView port) {}
public override void SetPosition(Rect newPos)
{
base.SetPosition(newPos);
nodeTarget.position = newPos;
}
public override bool expanded
{
get { return base.expanded; }
set
{
base.expanded = value;
nodeTarget.expanded = value;
}
}
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
{
evt.menu.AppendAction("Open Node Script", (e) => OpenNodeScript(), OpenNodeScriptStatus);
evt.menu.AppendAction("Open Node View Script", (e) => OpenNodeViewScript(), OpenNodeViewScriptStatus);
}
StatusFlags OpenNodeScriptStatus(DropdownMenu.MenuAction action)
{
if (NodeProvider.GetNodeScript(nodeTarget.GetType()) != null)
return StatusFlags.Normal;
return StatusFlags.Disabled;
}
StatusFlags OpenNodeViewScriptStatus(DropdownMenu.MenuAction action)
{
if (NodeProvider.GetNodeViewScript(GetType()) != null)
return StatusFlags.Normal;
return StatusFlags.Disabled;
}
#endregion
}
}

11
NodeGraphProcessor/Editor/Views/BaseNodeView.cs.meta


fileFormatVersion: 2
guid: 82efb95f0451b4cc88cc103f2a013dd5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

98
NodeGraphProcessor/Editor/Views/CommentBlockView.cs


using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEditor.Experimental.UIElements;
using UnityEngine.Experimental.UIElements;
using System.Collections;
using System.Collections.Generic;
namespace GraphProcessor
{
public class CommentBlockView : Group
{
public BaseGraphView owner;
public CommentBlock commentBlock;
Label titleLabel;
ColorField colorField;
public CommentBlockView()
{
AddStyleSheetPath("GraphProcessorStyles/CommentBlockView");
}
public void Initialize(BaseGraphView graphView, CommentBlock block)
{
commentBlock = block;
owner = graphView;
title = block.title;
SetSize(block.size);
SetPosition(block.position);
headerContainer.Q<TextField>().RegisterCallback<ChangeEvent<string>>(TitleChangedCallback);
titleLabel = headerContainer.Q<Label>();
colorField = new ColorField{ value = commentBlock.color, name = "headerColorPicker" };
colorField.OnValueChanged(e =>
{
UpdateCommentBlockColor(e.newValue);
});
UpdateCommentBlockColor(commentBlock.color);
headerContainer.Add(colorField);
InitializeInnerNodes();
}
void InitializeInnerNodes()
{
foreach (var nodeGUID in commentBlock.innerNodeGUIDs)
{
if (!owner.graph.nodesPerGUID.ContainsKey(nodeGUID))
{
Debug.LogWarning("Node GUID not found: " + nodeGUID);
continue ;
}
var node = owner.graph.nodesPerGUID[nodeGUID];
var nodeView = owner.nodeViewsPerNode[node];
AddElement(nodeView);
}
}
protected override void OnElementsAdded(IEnumerable<GraphElement> elements)
{
foreach (var element in elements)
{
var node = element as BaseNodeView;
if (node == null)
throw new System.ArgumentException("Adding another thing than node is not currently supported");
if (!commentBlock.innerNodeGUIDs.Contains(node.nodeTarget.GUID))
commentBlock.innerNodeGUIDs.Add(node.nodeTarget.GUID);
}
base.OnElementsAdded(elements);
}
public void UpdateCommentBlockColor(Color newColor)
{
commentBlock.color = newColor;
style.backgroundColor = newColor;
titleLabel.style.color = new Color(1 - newColor.r, 1 - newColor.g, 1 - newColor.b, 1);
}
void TitleChangedCallback(ChangeEvent< string > e)
{
commentBlock.title = e.newValue;
}
public override void SetPosition(Rect newPos)
{
base.SetPosition(newPos);
commentBlock.position = newPos;
}
}
}

11
NodeGraphProcessor/Editor/Views/CommentBlockView.cs.meta


fileFormatVersion: 2
guid: e577ba4ccbfd74da5a0ea1c19bc93bd2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

17
NodeGraphProcessor/Editor/Views/EdgeView.cs


using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine;
namespace GraphProcessor
{
public class EdgeView : Edge
{
public bool isConnected = false;
public SerializableEdge serializedEdge { get { return userData as SerializableEdge; } }
public EdgeView()
{
AddStyleSheetPath("GraphProcessorStyles/EdgeView");
}
}
}

11
NodeGraphProcessor/Editor/Views/EdgeView.cs.meta


fileFormatVersion: 2
guid: e38753fb1fe624181b84aa5b468ebc01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

22
NodeGraphProcessor/Editor/Views/MiniMapView.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
namespace GraphProcessor
{
public class MiniMapView : MiniMap
{
BaseGraphView graphView;
Vector2 size;
public MiniMapView(BaseGraphView baseGraphView)
{
this.graphView = baseGraphView;
SetPosition(new Rect(0, 0, 100, 100));
size = new Vector2(100, 100);
}
}
}

11
NodeGraphProcessor/Editor/Views/MiniMapView.cs.meta


fileFormatVersion: 2
guid: 76246e393040b425e8d74ff93388a1d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

58
NodeGraphProcessor/Editor/Views/PinnedElementView.cs


using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEditor;
using UnityEngine;
namespace GraphProcessor
{
public abstract class PinnedElementView : VisualElement
{
protected VisualElement header;
protected PinnedElement pinnedElement;
private Label titleLabel;
public string title
{
get => titleLabel.text;
set => titleLabel.text = value;
}
public PinnedElementView()
{
AddStyleSheetPath("GraphProcessorStyles/PinnedElementView");
name = "PinnedElementView";
clippingOptions = ClippingOptions.ClipAndCacheContents;
header = new VisualElement { name = "header" };
{
titleLabel = new Label { name = "title", text = "Title" };
header.Add(titleLabel);
}
Add(header);
}
public override void OnPersistentDataReady()
{
transform.position = pinnedElement.position;
}
public void InitializeGraphView(PinnedElement pinnedElement, BaseGraphView graphView)
{
this.pinnedElement = pinnedElement;
transform.position = pinnedElement.position;
Initialize(graphView);
}
protected abstract void Initialize(BaseGraphView graphView);
~PinnedElementView()
{
Destroy();
}
protected virtual void Destroy() {}
}
}

11
NodeGraphProcessor/Editor/Views/PinnedElementView.cs.meta


fileFormatVersion: 2
guid: ed45305e038bd465d8f37499a7d22489
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

99
NodeGraphProcessor/Editor/Views/PortView.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine.Experimental.UIElements;
using System;
using System.Reflection;
using UnityEngine.Experimental.UIElements.StyleEnums;
namespace GraphProcessor
{
public class PortView : Port
{
public bool isMultiple;
public string fieldName { get; protected set; }
public new Type portType;
public BaseNodeView owner { get; private set; }
public event Action< PortView, Edge > OnConnected;
public event Action< PortView, Edge > OnDisconnected;
protected FieldInfo fieldInfo;
protected EdgeConnectorListener listener;
string userPortStyleFile = "PortViewTypes";
List< EdgeView > edges = new List< EdgeView >();
public PortView(Orientation portOrientation, Direction direction, FieldInfo fieldInfo, EdgeConnectorListener edgeConnectorListener)
: base(portOrientation, direction, Capacity.Multi, fieldInfo.FieldType)
{
AddStyleSheetPath("GraphProcessorStyles/PortView");
if (Resources.Load< UnityEngine.Object >(userPortStyleFile) != null)
AddStyleSheetPath(userPortStyleFile);
this.m_EdgeConnector = new EdgeConnector< EdgeView >(edgeConnectorListener);
this.AddManipulator(m_EdgeConnector);
fieldName = fieldInfo.Name;
portType = fieldInfo.FieldType;
this.fieldInfo = fieldInfo;
this.listener = edgeConnectorListener;
}
public virtual void Initialize(BaseNodeView nodeView, bool isMultiple, string name)
{
this.isMultiple = isMultiple;
this.owner = nodeView;
// Correct port type if port accept multiple values (and so is a container)
if (isMultiple)
portType = portType.GetGenericArguments()[0];
if (name != null)
portName = name;
visualClass = "Port_" + portType.Name;
}
public override void Connect(Edge edge)
{
OnConnected?.Invoke(this, edge);
base.Connect(edge);
var inputNode = (edge.input as PortView).owner;
var outputNode = (edge.output as PortView).owner;
inputNode.OnPortConnected(edge.input as PortView);
outputNode.OnPortConnected(edge.output as PortView);
edges.Add(edge as EdgeView);
}
public override void Disconnect(Edge edge)
{
OnDisconnected?.Invoke(this, edge);
base.Disconnect(edge);
if (!(edge as EdgeView).isConnected)
return ;
var inputNode = (edge.input as PortView).owner;
var outputNode = (edge.output as PortView).owner;
inputNode.OnPortDisconnected(edge.input as PortView);
outputNode.OnPortDisconnected(edge.output as PortView);
edges.Remove(edge as EdgeView);
}
public List< EdgeView > GetEdges()
{
return edges;
}
}
}

11
NodeGraphProcessor/Editor/Views/PortView.cs.meta


fileFormatVersion: 2
guid: 69c0ad40b9eda46c89c464f0b6d81a38
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

36
NodeGraphProcessor/Editor/Views/ProcessorView.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEditor.Experimental.UIElements;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEngine.Experimental.UIElements;
namespace GraphProcessor
{
public class ProcessorView : PinnedElementView
{
BaseGraphProcessor processor;
public ProcessorView()
{
title = "Process panel";
}
protected override void Initialize(BaseGraphView graphView)
{
processor = new ProcessGraphProcessor(graphView.graph);
graphView.computeOrderUpdated += processor.UpdateComputeOrder;
Button b = new Button(OnPlay) { name = "ActionButton", text = "Play !" };
Add(b);
}
void OnPlay()
{
processor.Run();
}
}
}

11
NodeGraphProcessor/Editor/Views/ProcessorView.cs.meta


fileFormatVersion: 2
guid: ba435dc6c3986437ebc9baec443d80b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

101
NodeGraphProcessor/Editor/Views/ToolbarView.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEditor.Experimental.UIElements;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEngine.Experimental.UIElements;
using UnityEditor;
using System;
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags;
namespace GraphProcessor
{
public class ToolbarView : VisualElement
{
class ToolbarButtonData
{
public string name;
public bool toggle;
public bool value;
public Action buttonCallback;
public Action< bool > toggleCallback;
}
List< ToolbarButtonData > leftButtonDatas = new List< ToolbarButtonData >();
List< ToolbarButtonData > rightButtonDatas = new List< ToolbarButtonData >();
protected BaseGraphView graphView;
public ToolbarView(BaseGraphView graphView)
{
name = "ToolbarView";
this.graphView = graphView;
graphView.initialized += AddButtons;
Add(new IMGUIContainer(DrawImGUIToolbar));
}
protected void AddButton(string name, Action callback, bool left = true)
{
((left) ? leftButtonDatas : rightButtonDatas).Add(new ToolbarButtonData{
name = name,
toggle = false,
buttonCallback = callback
});
}
protected void AddToggle(string name, bool defaultValue, Action< bool > callback, bool left = true)
{
((left) ? leftButtonDatas : rightButtonDatas).Add(new ToolbarButtonData{
name = name,
toggle = true,
value = defaultValue,
toggleCallback = callback
});
}
protected virtual void AddButtons()
{
AddButton("Center", graphView.ResetPositionAndZoom);
bool processorVisible = graphView.GetPinnedElementStatus< ProcessorView >() != StatusFlags.Hidden;
AddToggle("Show Processor", processorVisible, (v) => graphView.ToggleView< ProcessorView>());
AddButton("Show In Project", () => EditorGUIUtility.PingObject(graphView.graph), false);
}
void DrawImGUIButtonList(List< ToolbarButtonData > buttons)
{
foreach (var button in buttons)
{
if (button.toggle)
{
EditorGUI.BeginChangeCheck();
button.value = GUILayout.Toggle(button.value, button.name, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck() && button.toggleCallback != null)
button.toggleCallback(button.value);
}
else
{
if (GUILayout.Button(button.name, EditorStyles.toolbarButton) && button.buttonCallback != null)
button.buttonCallback();
}
}
}
void DrawImGUIToolbar()
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
DrawImGUIButtonList(leftButtonDatas);
GUILayout.FlexibleSpace();
DrawImGUIButtonList(rightButtonDatas);
GUILayout.EndHorizontal();
}
}
}

11
NodeGraphProcessor/Editor/Views/ToolbarView.cs.meta


fileFormatVersion: 2
guid: 3844ba2924c064729bd5589ba9d3ad59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

16
NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef


{
"name": "com.alelievr.NodeGraphProcessor-Editor",
"references": [
"com.alelievr.NodeGraphProcessor"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [
"Editor"
],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

7
NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef.meta


fileFormatVersion: 2
guid: 036ec4299675a444c8cda9774db433f1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

21
NodeGraphProcessor/LICENSE


MIT License
Copyright (c) 2018 Antoine Lelievre
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
NodeGraphProcessor/LICENSE.meta


fileFormatVersion: 2
guid: f80bc1a9962357243a163132b9b2ca5e
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Runtime.meta


fileFormatVersion: 2
guid: de9dcb1d4913a5646b09e2b73101162f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Runtime/Elements.meta


fileFormatVersion: 2
guid: d87d8f985f7499f40b41e67ff7212077
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

216
NodeGraphProcessor/Runtime/Elements/BaseNode.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
using Unity.Jobs;
using System.Linq;
namespace GraphProcessor
{
[Serializable]
public abstract class BaseNode
{
public virtual string name => GetType().Name;
//id
public string GUID;
public int computeOrder = -1;
public bool canProcess = true;
[NonSerialized]
public readonly NodeInputPortContainer inputPorts;
[NonSerialized]
public readonly NodeOutputPortContainer outputPorts;
//Node view datas
public Rect position;
public bool expanded;
public delegate void ProcessDelegate();
public event ProcessDelegate onProcessed;
[NonSerialized]
public Dictionary< string, NodeFieldInformation > nodeFields = new Dictionary< string, NodeFieldInformation >();
public class NodeFieldInformation
{
public string name;
public string fieldName;
public FieldInfo info;
public bool input;
public bool isMultiple;
public NodeFieldInformation(FieldInfo info, string name, bool input, bool isMultiple)
{
this.input = input;
this.isMultiple = isMultiple;
this.info = info;
this.name = name;
this.fieldName = info.Name;
}
}
public static BaseNode CreateFromType(Type nodeType, Vector2 position)
{
if (!nodeType.IsSubclassOf(typeof(BaseNode)))
return null;
var node = Activator.CreateInstance(nodeType) as BaseNode;
node.position = new Rect(position, new Vector2(100, 100));
node.OnNodeCreated();
return node;
}
#region Initialization
protected BaseNode()
{
InitializeInOutDatas();
Enable();
inputPorts = new NodeInputPortContainer(this);
outputPorts = new NodeOutputPortContainer(this);
foreach (var nodeFieldKP in nodeFields)
{
AddPort(nodeFieldKP.Value.input, nodeFieldKP.Value.fieldName);
}
}
~BaseNode()
{
Disable();
}
/// <summary>
/// Called only when the node is created, not when instantiated
/// </summary>
public virtual void OnNodeCreated()
{
GUID = Guid.NewGuid().ToString();
}
void InitializeInOutDatas()
{
var fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
var inputAttribute = field.GetCustomAttribute< InputAttribute >();
var outputAttribute = field.GetCustomAttribute< OutputAttribute >();
bool isMultiple = false;
bool input = false;
string name = field.Name;
if (inputAttribute == null && outputAttribute == null)
continue ;
//check if field is a collection type
isMultiple = (inputAttribute != null) ? inputAttribute.allowMultiple : false;
input = inputAttribute != null;
if (!String.IsNullOrEmpty(inputAttribute?.name))
name = inputAttribute.name;
if (!String.IsNullOrEmpty(outputAttribute?.name))
name = outputAttribute.name;
nodeFields[field.Name] = new NodeFieldInformation(field, name, input, isMultiple);
}
}
#endregion
#region Events and Processing
public void OnEdgeConnected(SerializableEdge edge)
{
bool input = edge.inputNode == this;
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts;
portCollection.Add(edge);
}
public void OnEdgeDisonnected(SerializableEdge edge)
{
if (edge == null)
return ;
bool input = edge.inputNode == this;
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts;
portCollection.Remove(edge);
}
public void OnProcess()
{
inputPorts.PullDatas();
Process();
onProcessed?.Invoke();
outputPorts.PushDatas();
}
protected virtual void Enable() {}
protected virtual void Disable() {}
protected virtual void Process() {}
#endregion
#region API and utils
public void AddPort(bool input, string fieldName)
{
if (input)
inputPorts.Add(new NodePort(this, fieldName));
else
outputPorts.Add(new NodePort(this, fieldName));
}
public void RemovePort(bool input, NodePort port)
{
if (input)
inputPorts.Remove(port);
else
outputPorts.Remove(port);
}
public void RemovePort(bool input, string fieldName)
{
if (input)
inputPorts.RemoveAll(p => p.fieldName == fieldName);
else
outputPorts.RemoveAll(p => p.fieldName == fieldName);
}
public IEnumerable< BaseNode > GetInputNodes()
{
foreach (var port in inputPorts)
foreach (var edge in port.GetEdges())
yield return edge.outputNode;
}
public IEnumerable< BaseNode > GetOutputNodes()
{
foreach (var port in outputPorts)
foreach (var edge in port.GetEdges())
yield return edge.inputNode;
}
public NodePort GetPort(string fieldName)
{
return inputPorts.Concat(outputPorts).FirstOrDefault(p => p.fieldName == fieldName);
}
#endregion
}
}

11
NodeGraphProcessor/Runtime/Elements/BaseNode.cs.meta


fileFormatVersion: 2
guid: d3989238b25842a4da391d2c531fac81
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

29
NodeGraphProcessor/Runtime/Elements/CommentBlock.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GraphProcessor
{
[System.Serializable]
public class CommentBlock
{
public string title;
public Color color;
public Rect position;
public Vector2 size;
public List< string > innerNodeGUIDs = new List< string >();
public CommentBlock(string title, Vector2 position)
{
this.title = title;
this.position.position = position;
}
public virtual void OnCreated()
{
size = new Vector2(300, 100);
position.size = size;
}
}
}

11
NodeGraphProcessor/Runtime/Elements/CommentBlock.cs.meta


fileFormatVersion: 2
guid: 97be34581635f0c429c2b7a84773be03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

161
NodeGraphProcessor/Runtime/Elements/NodePort.cs


using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq.Expressions;
using System;
namespace GraphProcessor
{
public class NodePort
{
public string fieldName;
public BaseNode owner;
List< SerializableEdge > edges = new List< SerializableEdge >();
Dictionary< SerializableEdge, PushDataDelegate > pushDataDelegates = new Dictionary< SerializableEdge, PushDataDelegate >();
List< SerializableEdge > edgeWithRemoteCustomIO = new List< SerializableEdge >();
CustomPortIODelegate customPortIOMethod;
FieldInfo ourValueField;
public delegate void PushDataDelegate();
public NodePort(BaseNode owner, string fieldName)
{
this.fieldName = fieldName;
this.owner = owner;
ourValueField = owner.GetType().GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
customPortIOMethod = CustomPortIO.GetCustomPortMethod(owner.GetType(), fieldName);
}
public void Add(SerializableEdge edge)
{
if (!edges.Contains(edge))
edges.Add(edge);
if (edge.inputNode == owner)
{
if (edge.outputPort.customPortIOMethod != null)
edgeWithRemoteCustomIO.Add(edge);
}
else
{
if (edge.inputPort.customPortIOMethod != null)
edgeWithRemoteCustomIO.Add(edge);
}
//if we have a custom io implementation, we don't need
if (edge.inputPort.customPortIOMethod != null || edge.outputPort.customPortIOMethod != null)
return ;
PushDataDelegate edgeDelegate = CreatePushDataDelegateForEdge(edge);
if (edgeDelegate != null)
pushDataDelegates[edge] = edgeDelegate;
}
PushDataDelegate CreatePushDataDelegateForEdge(SerializableEdge edge)
{
try
{
//Creation of the delegate to move the data from the input node to the output node:
FieldInfo inputField = edge.inputNode.GetType().GetField(edge.trueInputFieldName, BindingFlags.Public | BindingFlags.Instance);
FieldInfo outputField = edge.outputNode.GetType().GetField(edge.trueOutputFieldName, BindingFlags.Public | BindingFlags.Instance);
MemberExpression inputParamField = Expression.Field(Expression.Constant(edge.inputNode), inputField);
MemberExpression outputParamField = Expression.Field(Expression.Constant(edge.outputNode), outputField);
BinaryExpression assign = Expression.Assign(inputParamField, Expression.Convert(outputParamField, inputField.FieldType));
return Expression.Lambda< PushDataDelegate >(assign).Compile();
} catch (Exception e) {
Debug.LogError(e);
return null;
}
}
public void Remove(SerializableEdge edge)
{
pushDataDelegates.Remove(edge);
edges.Remove(edge);
}
public List< SerializableEdge > GetEdges()
{
return edges;
}
//This method can only be called on output ports
public void PushData()
{
if (customPortIOMethod != null)
{
customPortIOMethod(owner, edges);
return ;
}
foreach (var pushDataDelegate in pushDataDelegates)
pushDataDelegate.Value();
if (edgeWithRemoteCustomIO.Count == 0)
return ;
//if there are custom IO implementation on the other ports, they'll need our value in the passThrough buffer
object ourValue = ourValueField.GetValue(owner);
foreach (var edge in edgeWithRemoteCustomIO)
edge.passThroughBuffer = ourValue;
}
public void PullData()
{
if (customPortIOMethod != null)
{
customPortIOMethod(owner, edges);
}
}
}
public abstract class NodePortContainer : List< NodePort >
{
protected BaseNode node;
public NodePortContainer(BaseNode node)
{
this.node = node;
}
public void Remove(SerializableEdge edge)
{
ForEach(p => p.Remove(edge));
}
public void Add(SerializableEdge edge)
{
string portFieldName = (edge.inputNode == node) ? edge.inputFieldName : edge.outputFieldName;
var port = this.FirstOrDefault(p => p.fieldName == portFieldName);
port.Add(edge);
}
}
public class NodeInputPortContainer : NodePortContainer
{
public NodeInputPortContainer(BaseNode node) : base(node) {}
public void PullDatas()
{
ForEach(p => p.PullData());
}
}
public class NodeOutputPortContainer : NodePortContainer
{
public NodeOutputPortContainer(BaseNode node) : base(node) {}
public void PushDatas()
{
ForEach(p => p.PushData());
}
}
}

11
NodeGraphProcessor/Runtime/Elements/NodePort.cs.meta


fileFormatVersion: 2
guid: 3f706f6f8536b264cb9beb4781f59eda
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

20
NodeGraphProcessor/Runtime/Elements/PinnedElement.cs


using UnityEngine.Experimental.UIElements;
using UnityEngine.Experimental.UIElements.StyleEnums;
using UnityEngine;
using System;
namespace GraphProcessor
{
[System.Serializable]
public class PinnedElement
{
public Vector2 position = Vector2.zero;
public bool opened = true;
public SerializableType editorType;
public PinnedElement(Type editorType)
{
this.editorType = new SerializableType(editorType);
}
}
}

11
NodeGraphProcessor/Runtime/Elements/PinnedElement.cs.meta


fileFormatVersion: 2
guid: 0429aeae57996a844a00657c8913e21d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
NodeGraphProcessor/Runtime/Graph.meta


fileFormatVersion: 2
guid: db326f54ce37a86488063e8a81d25fb2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存