├── .gitignore ├── .gitlab-ci.yml ├── Attributes.cs ├── Attributes.cs.meta ├── DaGenGraph.asmdef ├── DaGenGraph.asmdef.meta ├── Edge.cs ├── Edge.cs.meta ├── Editor.meta ├── Editor ├── DaGenGraph.Editor.asmdef ├── DaGenGraph.Editor.asmdef.meta ├── DrawBase.cs ├── DrawBase.cs.meta ├── EdgeView.cs ├── EdgeView.cs.meta ├── GraphBackGround.cs ├── GraphBackGround.cs.meta ├── GraphHandle.cs ├── GraphHandle.cs.meta ├── GraphWindow.cs ├── GraphWindow.cs.meta ├── GraphWindowDraw.cs ├── GraphWindowDraw.cs.meta ├── GroupInfo.cs ├── GroupInfo.cs.meta ├── NodeView.cs ├── NodeView.cs.meta ├── Tool.meta └── Tool │ ├── ColorExtensions.cs │ ├── ColorExtensions.cs.meta │ ├── Styles.cs │ ├── Styles.cs.meta │ ├── UIColor.cs │ └── UIColor.cs.meta ├── Example.meta ├── Example ├── DaGenGraph.Example.asmdef ├── DaGenGraph.Example.asmdef.meta ├── ExampleGraph.cs ├── ExampleGraph.cs.meta ├── ExampleGraphWindow.cs ├── ExampleGraphWindow.cs.meta ├── ExampleNode.cs ├── ExampleNode.cs.meta ├── ExampleNodeView.cs └── ExampleNodeView.cs.meta ├── GraphBase.cs ├── GraphBase.cs.meta ├── JsonGraphBase.cs ├── JsonGraphBase.cs.meta ├── JsonNodeBase.cs ├── JsonNodeBase.cs.meta ├── NodeBase.cs ├── NodeBase.cs.meta ├── Port.cs ├── Port.cs.meta ├── Style.meta ├── Style ├── DarkSkin.guiskin ├── DarkSkin.guiskin.meta ├── UIColor.asset └── UIColor.asset.meta ├── Texture.meta ├── Texture ├── BackgroundRoundDark.png ├── BackgroundRoundDark.png.meta ├── BackgroundSquareDark.png ├── BackgroundSquareDark.png.meta ├── ConnectionPointMinusNormalDark.png ├── ConnectionPointMinusNormalDark.png.meta ├── ConnectionPointMultipleConnectedNormalDark.png ├── ConnectionPointMultipleConnectedNormalDark.png.meta ├── ConnectionPointMultipleEmptyNormalDark.png ├── ConnectionPointMultipleEmptyNormalDark.png.meta ├── ConnectionPointOverrideConnectedNormalDark.png ├── ConnectionPointOverrideConnectedNormalDark.png.meta ├── ConnectionPointOverrideEmptyNormalDark.png ├── ConnectionPointOverrideEmptyNormalDark.png.meta ├── NodeBodyDark.png ├── NodeBodyDark.png.meta ├── NodeDotDark.png ├── NodeDotDark.png.meta ├── NodeFooterDark.png ├── NodeFooterDark.png.meta ├── NodeGlowDark.png ├── NodeGlowDark.png.meta ├── NodeHeaderDark.png ├── NodeHeaderDark.png.meta ├── NodeOutlineDark.png └── NodeOutlineDark.png.meta ├── TypeHelper.cs ├── TypeHelper.cs.meta ├── ValueDropdownItem.cs ├── ValueDropdownItem.cs.meta ├── VirtualPoint.cs ├── VirtualPoint.cs.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | 7 | # Autogenerated VS solution and project files 8 | ExportedObj/ 9 | *.csproj 10 | *.unityproj 11 | *.sln 12 | *.suo 13 | *.tmp 14 | *.user 15 | *.userprefs 16 | *.pidb 17 | *.booproj 18 | *.svd 19 | .vs/ 20 | 21 | # VScode ide files 22 | .vscode 23 | 24 | # Unity3D generated meta files 25 | *.pidb.meta 26 | 27 | # Unity3D Generated File On Crash Reports 28 | sysinfo.txt 29 | 30 | # Builds 31 | *.apk 32 | 33 | ============ 34 | OS generated 35 | ============ 36 | .DS_Store 37 | .DS_Store? 38 | ._* 39 | .Spotlight-V100 40 | .Trashes 41 | ehthumbs.db 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/.gitlab-ci.yml -------------------------------------------------------------------------------- /Attributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | #if !ODIN_INSPECTOR 3 | using UnityEditor; 4 | #endif 5 | namespace DaGenGraph 6 | { 7 | public enum Ignore 8 | { 9 | All, 10 | Details, 11 | NodeView, 12 | } 13 | 14 | [AttributeUsage(AttributeTargets.Field)] 15 | public class DrawIgnoreAttribute : Attribute 16 | { 17 | public Ignore Ignore; 18 | 19 | public DrawIgnoreAttribute() 20 | { 21 | Ignore = Ignore.All; 22 | } 23 | 24 | public DrawIgnoreAttribute(Ignore type) 25 | { 26 | Ignore = type; 27 | } 28 | } 29 | 30 | [AttributeUsage(AttributeTargets.Class)] 31 | public class NodeViewTypeAttribute : Attribute 32 | { 33 | public NodeViewTypeAttribute(Type baseViewNode) 34 | { 35 | ViewType = baseViewNode; 36 | } 37 | 38 | public Type ViewType; 39 | } 40 | 41 | /// 42 | /// ScriptableObject专用,指定该项不是资源 43 | /// 44 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 45 | public class NotAssetsAttribute : Attribute 46 | { 47 | 48 | } 49 | 50 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 51 | public class PortGroupAttribute : Attribute 52 | { 53 | public int Group; 54 | 55 | public PortGroupAttribute(int group) 56 | { 57 | Group = group; 58 | } 59 | } 60 | 61 | 62 | #if !ODIN_INSPECTOR 63 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 64 | public class OnStateUpdateAttribute : Attribute 65 | { 66 | public string Action; 67 | 68 | public OnStateUpdateAttribute(string action) => this.Action = action; 69 | } 70 | 71 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 72 | public class OnCollectionChangedAttribute : Attribute 73 | { 74 | public string After; 75 | public OnCollectionChangedAttribute(string after) => this.After = after; 76 | } 77 | 78 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 79 | public class TypeFilterAttribute : Attribute 80 | { 81 | public string FilterGetter; 82 | public TypeFilterAttribute(string filterGetter) => this.FilterGetter = filterGetter; 83 | } 84 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 85 | public class HideReferenceObjectPickerAttribute : Attribute 86 | { 87 | } 88 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 89 | public class MinValueAttribute : Attribute 90 | { 91 | public double MinValue; 92 | public MinValueAttribute(double minValue) => this.MinValue = minValue; 93 | } 94 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 95 | public class MaxValueAttribute : Attribute 96 | { 97 | public double MaxValue; 98 | public MaxValueAttribute(double maxValue) => this.MaxValue = maxValue; 99 | } 100 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 101 | public class DisableInEditorModeAttribute : Attribute 102 | { 103 | 104 | } 105 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 106 | public class OnValueChangedAttribute : Attribute 107 | { 108 | public string Action; 109 | 110 | public OnValueChangedAttribute(string action) 111 | { 112 | Action = action; 113 | } 114 | } 115 | 116 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 117 | public class PropertyOrderAttribute : Attribute 118 | { 119 | public float Order; 120 | public PropertyOrderAttribute(){} 121 | public PropertyOrderAttribute(float order) 122 | { 123 | Order = order; 124 | } 125 | } 126 | 127 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] 128 | public class BoxGroupAttribute : Attribute 129 | { 130 | public string GroupID; 131 | 132 | public BoxGroupAttribute(string groupID) 133 | { 134 | GroupID = groupID; 135 | } 136 | } 137 | 138 | [AttributeUsage(AttributeTargets.Method)] 139 | public class ButtonAttribute : Attribute 140 | { 141 | public string Name; 142 | 143 | public ButtonAttribute(string name) 144 | { 145 | Name = name; 146 | } 147 | 148 | } 149 | 150 | public class ReadOnlyAttribute : Attribute 151 | { 152 | } 153 | 154 | public class InfoBoxAttribute : Attribute 155 | { 156 | 157 | public string Message; 158 | 159 | public MessageType InfoMessageType; 160 | 161 | public InfoBoxAttribute( 162 | string message, 163 | MessageType infoMessageType = MessageType.Info) 164 | { 165 | this.Message = message; 166 | this.InfoMessageType = infoMessageType; 167 | } 168 | 169 | public InfoBoxAttribute(string message) 170 | { 171 | this.Message = message; 172 | this.InfoMessageType = MessageType.Info; 173 | } 174 | } 175 | 176 | public class LabelTextAttribute : Attribute 177 | { 178 | public LabelTextAttribute(string text) 179 | { 180 | Text = text; 181 | } 182 | 183 | public string Text; 184 | } 185 | 186 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 187 | public class ShowIfAttribute : Attribute 188 | { 189 | 190 | public string Condition; 191 | public object Value; 192 | 193 | public ShowIfAttribute(string condition) 194 | { 195 | Condition = condition; 196 | } 197 | 198 | public ShowIfAttribute(string condition, object optionalValue) 199 | { 200 | this.Condition = condition; 201 | this.Value = optionalValue; 202 | } 203 | } 204 | 205 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 206 | public class ValueDropdownAttribute : Attribute 207 | { 208 | public string ValuesGetter; 209 | public bool AppendNextDrawer; 210 | public ValueDropdownAttribute(string valuesGetter) 211 | { 212 | ValuesGetter = valuesGetter; 213 | } 214 | } 215 | 216 | #endif 217 | } -------------------------------------------------------------------------------- /Attributes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6e4ad200c9d8413b8b423dc29246170d 3 | timeCreated: 1737185096 -------------------------------------------------------------------------------- /DaGenGraph.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DaGenGraph", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /DaGenGraph.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b637e77054d21444096d4d4e5637ed30 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Edge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Unity.Collections; 3 | using UnityEngine; 4 | 5 | namespace DaGenGraph 6 | { 7 | public class Edge: ScriptableObject 8 | { 9 | #region Properties 10 | 11 | /// [Editor Only] Pings this Edge 12 | [NonSerialized] public bool ping; 13 | /// [Editor Only] ReSet Animation Time 14 | [NonSerialized] public bool reSetTime; 15 | [NonSerialized]public Vector2 inputEdgePoint; 16 | [NonSerialized]public Vector2 outputEdgePoint; 17 | #endregion 18 | 19 | #region public Variables 20 | 21 | public string id; 22 | public string inputNodeId; 23 | public string inputPortId; 24 | public string outputNodeId; 25 | public string outputPortId; 26 | 27 | #endregion 28 | 29 | #region Constructors 30 | 31 | 32 | /// Creates a new instance for this class between two ports (Input - Output or Output - Input) 33 | /// port One 34 | /// port Two 35 | public void Init(Port port1, Port port2) 36 | { 37 | GenerateNewId(); 38 | if (port1.IsOutput() && port2.IsInput()) 39 | { 40 | inputNodeId = port2.nodeId; 41 | inputPortId = port2.id; 42 | inputEdgePoint = port2.GetClosestEdgePointToPort(port2); 43 | 44 | outputNodeId = port1.nodeId; 45 | outputPortId = port1.id; 46 | outputEdgePoint = port1.GetClosestEdgePointToPort(port1); 47 | } 48 | 49 | if (port2.IsOutput() && port1.IsInput()) 50 | { 51 | inputNodeId = port1.nodeId; 52 | inputPortId = port1.id; 53 | inputEdgePoint = port1.GetClosestEdgePointToPort(port1); 54 | 55 | outputNodeId = port2.nodeId; 56 | outputPortId = port2.id; 57 | outputEdgePoint = port2.GetClosestEdgePointToPort(port2); 58 | } 59 | } 60 | 61 | #endregion 62 | 63 | #region private Methods 64 | 65 | /// Generates a new id for this connections and returns it 66 | private string GenerateNewId() 67 | { 68 | id = Guid.NewGuid().ToString(); 69 | return id; 70 | } 71 | 72 | #endregion 73 | 74 | } 75 | } -------------------------------------------------------------------------------- /Edge.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39d2f4c7ff7e4462835d2b5f6dcb6785 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: abd3eaa5e84b4c1da5b9f93b27ee0f28 3 | timeCreated: 1623032904 -------------------------------------------------------------------------------- /Editor/DaGenGraph.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DaGenGraph.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:b637e77054d21444096d4d4e5637ed30" 6 | ], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Editor/DaGenGraph.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82c60e129e644f1a875828179b3e9c80 3 | timeCreated: 1623032884 -------------------------------------------------------------------------------- /Editor/DrawBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40c13006090b4fdbaf0a069d11ab91e3 3 | timeCreated: 1737444475 -------------------------------------------------------------------------------- /Editor/EdgeView.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor.AnimatedValues; 2 | using UnityEngine; 3 | 4 | namespace DaGenGraph.Editor 5 | { 6 | public class EdgeView 7 | { 8 | /// The connection id. Every connection will have a record on two sockets (the output socket and the input socket) 9 | public string edgeId; 10 | /// Reference to the OutputPort Node of this connections 11 | public NodeBase outputNode; 12 | /// Reference to the OutputPort Port of the OutputPort Node of this connection 13 | public Port outputPort; 14 | /// Reference to the InputPort Node of this connection 15 | public NodeBase inputNode; 16 | /// Reference to the InputPort Port of the InputPort Node of this connection 17 | public Port inputPort; 18 | /// Reference to the OutputPort Virtual Point of this connection 19 | public VirtualPoint outputVirtualPoint; 20 | /// Reference to the InputPort Virtual Point of this connection 21 | public VirtualPoint inputVirtualPoint; 22 | /// Holds the last calculated value of the OutputPort Tangent in order to draw the connection curve (huge performance boost as we won't need to recalculate it on every frame) 23 | public Vector2 outputTangent = Vector2.zero; 24 | /// Holds the last calculated value of the InputPort Tangent in order to draw the connection curve (huge performance boost as we won't need to recalculate it on every frame) 25 | public Vector2 inputTangent = Vector2.zero; 26 | // public AnimBool ping = new AnimBool {speed = 0.6f}; 27 | //TODO Edge Shader 28 | // /// Lightweight handles material 29 | // private static Material s_HandleMaterial; 30 | // 31 | // /// Returns a lightweight handles material 32 | // private static Material handleMaterial 33 | // { 34 | // get 35 | // { 36 | // if (s_HandleMaterial != null) return s_HandleMaterial; 37 | // Shader shader = Shader.Find("Hidden/Nody/LineDraw"); 38 | // var m = new Material(shader) {hideFlags = HideFlags.HideAndDontSave}; 39 | // s_HandleMaterial = m; 40 | // return s_HandleMaterial; 41 | // } 42 | // } 43 | } 44 | } -------------------------------------------------------------------------------- /Editor/EdgeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3aef23d0a7e74cdb8c058f30728ddd02 3 | timeCreated: 1623033614 -------------------------------------------------------------------------------- /Editor/GraphBackGround.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using UnityEngine.Rendering; 4 | 5 | namespace DaGenGraph.Editor 6 | { 7 | public static class GraphBackground 8 | { 9 | private const float MINOR_GRID_SIZE = 10f; 10 | private const float MAJOR_GRID_SIZE = 100f; 11 | 12 | private static readonly Color s_GridMinorColorDark = new Color(0f, 0f, 0f, 0.18f); 13 | private static readonly Color s_GridMajorColorDark = new Color(0f, 0f, 0f, 0.28f); 14 | private static readonly int s_HandleZTest = Shader.PropertyToID("_HandleZTest"); 15 | 16 | public static void DrawGrid(Rect gridRect, float zoomLevel, Vector2 panOffset) 17 | { 18 | if (Event.current.type != EventType.Repaint) return; 19 | 20 | //draw background 21 | UnityEditor.Graphs.Styles.graphBackground.Draw(gridRect, false, false, false, false); 22 | 23 | HandleUtility.ApplyWireMaterial(); 24 | GL.PushMatrix(); 25 | GL.Begin(1); 26 | var t = Mathf.InverseLerp(0.1f, 1f, zoomLevel); 27 | DrawGridLines(gridRect, MINOR_GRID_SIZE * zoomLevel, Color.Lerp(Color.clear, s_GridMinorColorDark, t), 28 | panOffset); 29 | DrawGridLines(gridRect, MAJOR_GRID_SIZE * zoomLevel, Color.Lerp(s_GridMinorColorDark, s_GridMajorColorDark, t), 30 | panOffset); 31 | GL.End(); 32 | GL.PopMatrix(); 33 | } 34 | 35 | private static void DrawGridLines(Rect gridRect, float gridSize, Color gridColor, Vector2 panOffset) 36 | { 37 | //vertical lines 38 | GL.Color(gridColor); 39 | var scaledOffsetX = -panOffset.x + panOffset.x % gridSize; 40 | var x = gridRect.xMin - gridRect.xMin % gridSize + scaledOffsetX; 41 | while (x < (double) gridRect.xMax + scaledOffsetX) 42 | { 43 | DrawLine(new Vector2(x + panOffset.x, gridRect.yMin), new Vector2(x + panOffset.x, gridRect.yMax)); 44 | x += gridSize; 45 | } 46 | //horizontal lines 47 | GL.Color(gridColor); 48 | var scaledOffsetY = -panOffset.y + panOffset.y % gridSize; 49 | var y = gridRect.yMin - gridRect.yMin % gridSize + scaledOffsetY; 50 | while (y < (double) gridRect.yMax + scaledOffsetY) 51 | { 52 | DrawLine(new Vector2(gridRect.xMin, y + panOffset.y), new Vector2(gridRect.xMax, y + panOffset.y)); 53 | y += gridSize; 54 | } 55 | } 56 | 57 | private static void DrawLine(Vector2 p1, Vector2 p2) 58 | { 59 | GL.Vertex(p1); 60 | GL.Vertex(p2); 61 | } 62 | 63 | // Implementation from UnityEditor.HandleUtility 64 | private static class HandleUtility 65 | { 66 | private static Material s_HandleWireMaterial; 67 | private static Material s_HandleWireMaterial2D; 68 | 69 | internal static void ApplyWireMaterial(CompareFunction zTest = CompareFunction.Always) 70 | { 71 | var wireMaterial = HandleUtility.handleWireMaterial; 72 | wireMaterial.SetInt(s_HandleZTest, (int) zTest); 73 | wireMaterial.SetPass(0); 74 | } 75 | 76 | private static Material handleWireMaterial 77 | { 78 | get 79 | { 80 | InitHandleMaterials(); 81 | return !Camera.current ? s_HandleWireMaterial2D : s_HandleWireMaterial; 82 | } 83 | } 84 | 85 | private static void InitHandleMaterials() 86 | { 87 | if (s_HandleWireMaterial) return; 88 | s_HandleWireMaterial = (Material) EditorGUIUtility.LoadRequired("SceneView/HandleLines.mat"); 89 | s_HandleWireMaterial2D = (Material) EditorGUIUtility.LoadRequired("SceneView/2DHandleLines.mat"); 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Editor/GraphBackGround.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1483877cf997458686e059e413fa85e5 3 | timeCreated: 1623033535 -------------------------------------------------------------------------------- /Editor/GraphHandle.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cfca6f381e44aad8f6d88641061575f 3 | timeCreated: 1623046865 -------------------------------------------------------------------------------- /Editor/GraphWindow.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection; 4 | using UnityEditor; 5 | using UnityEditor.AnimatedValues; 6 | using UnityEngine; 7 | 8 | namespace DaGenGraph.Editor 9 | { 10 | public abstract partial class GraphWindow : DrawBase 11 | { 12 | protected GraphBase m_Graph; 13 | private GraphMode m_Mode = GraphMode.None; 14 | private float m_Timer; 15 | private float m_LastUpdateTime; 16 | private float m_AniTime; 17 | private bool m_AnimateInput; 18 | private bool m_AnimateOutput; 19 | private bool m_HasFocus; 20 | private float m_CurrentZoom = 1f; 21 | private Rect m_GraphAreaIncludingTab; 22 | private Rect m_ScaledGraphArea; 23 | private bool m_DrawInspector = true; 24 | private Dictionary m_NodeViews; 25 | private Dictionary> m_Points; 26 | private Dictionary m_Ports; 27 | private Dictionary m_EdgeViews; 28 | 29 | private float m_NodeInspectorWidth = 400; 30 | private float currentZoom 31 | { 32 | get 33 | { 34 | if (m_Graph != null) 35 | { 36 | m_CurrentZoom = m_Graph.currentZoom; 37 | } 38 | 39 | return m_CurrentZoom; 40 | } 41 | set 42 | { 43 | m_CurrentZoom = value; 44 | if (m_Graph != null) 45 | { 46 | m_Graph.currentZoom = m_CurrentZoom; 47 | } 48 | } 49 | } 50 | 51 | private Dictionary edgeViews 52 | { 53 | get 54 | { 55 | if (m_EdgeViews != null) return m_EdgeViews; 56 | m_EdgeViews = new Dictionary(); 57 | foreach (var port in ports.Values) 58 | { 59 | for (int i = port.edges.Count - 1; i >= 0; i--) 60 | { 61 | var edgeId = port.edges[i]; 62 | var edge = m_Graph.GetEdge(edgeId); 63 | if (edge == null) 64 | { 65 | port.edges.RemoveAt(i); 66 | continue; 67 | } 68 | 69 | if (!nodeViews.ContainsKey(edge.inputNodeId) || 70 | !nodeViews.ContainsKey(edge.outputNodeId)) 71 | { 72 | port.ContainsEdge(edge.id); 73 | continue; 74 | } 75 | 76 | //check if the EdgeViews id has been added to the dictionary 77 | if (!m_EdgeViews.ContainsKey(edge.id)) 78 | m_EdgeViews.Add(edge.id, new EdgeView { edgeId = edge.id }); 79 | if (edge.inputPortId == port.id) 80 | m_EdgeViews[edge.id].inputPort = 81 | port; //reference this Prot if it is the EdgeViews's InputProt 82 | if (edge.inputNodeId == port.nodeId) 83 | m_EdgeViews[edge.id].inputNode = 84 | nodeViews[port.nodeId].node; //reference this Prot's parent as the InputNode 85 | if (edge.outputPortId == port.id) 86 | m_EdgeViews[edge.id].outputPort = 87 | port; //reference this socket if it is the EdgeView's OutputProt 88 | if (edge.outputNodeId == port.nodeId) 89 | m_EdgeViews[edge.id].outputNode = 90 | nodeViews[port.nodeId].node; //reference this Prot's parent as the OutputNode 91 | } 92 | } 93 | 94 | return m_EdgeViews; 95 | } 96 | } 97 | 98 | private Dictionary ports 99 | { 100 | get 101 | { 102 | if (m_Ports != null) 103 | { 104 | return m_Ports; 105 | } 106 | 107 | m_Ports = new Dictionary(); 108 | foreach (var nodeView in nodeViews.Values) 109 | { 110 | for (var i = nodeView.node.inputPorts.Count - 1; i >= 0; i--) 111 | { 112 | var inputSocket = nodeView.node.inputPorts[i]; 113 | if (inputSocket == null) 114 | { 115 | nodeView.node.inputPorts.RemoveAt(i); 116 | continue; 117 | } 118 | 119 | m_Ports.Add(inputSocket.id, inputSocket); 120 | } 121 | 122 | for (int i = nodeView.node.outputPorts.Count - 1; i >= 0; i--) 123 | { 124 | Port outputSocket = nodeView.node.outputPorts[i]; 125 | if (outputSocket == null) 126 | { 127 | nodeView.node.outputPorts.RemoveAt(i); 128 | continue; 129 | } 130 | 131 | m_Ports.Add(outputSocket.id, outputSocket); 132 | } 133 | } 134 | 135 | return m_Ports; 136 | } 137 | } 138 | 139 | private Dictionary> points 140 | { 141 | get 142 | { 143 | if (m_Points != null) 144 | { 145 | return m_Points; 146 | } 147 | 148 | m_Points = new Dictionary>(); 149 | foreach (var nodeView in nodeViews.Values) 150 | { 151 | if (nodeView.node.inputPorts != null) 152 | { 153 | foreach (var port in nodeView.node.inputPorts) 154 | { 155 | if(port==null) continue; 156 | m_Points.Add(port.id, new List()); 157 | foreach (var point in port.GetEdgePoints()) 158 | { 159 | m_Points[port.id].Add(new VirtualPoint(nodeViews[port.nodeId].node, port, 160 | point + m_Graph.currentPanOffset / currentZoom, point)); 161 | } 162 | } 163 | } 164 | 165 | if (nodeView.node.outputPorts != null) 166 | { 167 | foreach (var port in nodeView.node.outputPorts) 168 | { 169 | if(port==null) continue; 170 | m_Points.Add(port.id, new List()); 171 | foreach (var point in port.GetEdgePoints()) 172 | { 173 | m_Points[port.id].Add(new VirtualPoint(nodeViews[port.nodeId].node, port, 174 | point + m_Graph.currentPanOffset / currentZoom, point)); 175 | } 176 | } 177 | } 178 | } 179 | 180 | return m_Points; 181 | } 182 | } 183 | 184 | private Dictionary nodeViews => m_NodeViews; 185 | 186 | protected virtual void OnEnable() 187 | { 188 | m_AltKeyPressedAnimBool = new AnimBool(false, Repaint); 189 | m_NodeViews = new Dictionary(); 190 | AddButton(new GUIContent("新建"), InitGraph); 191 | AddButton(new GUIContent("打开"), LoadGraph); 192 | AddButton(new GUIContent("保存"), SaveGraph); 193 | AddButton(new GUIContent("详情面板"), ChangeDrawInspector, false); 194 | } 195 | 196 | private void OnGUI() 197 | { 198 | var evt = Event.current; 199 | if (evt.type is EventType.DragUpdated or EventType.DragPerform) 200 | { 201 | if (DragAndDrop.objectReferences.ToList().Exists(o => !(o is GameObject))) 202 | { 203 | return; 204 | } 205 | 206 | DragAndDrop.visualMode = DragAndDropVisualMode.Copy; 207 | if (evt.type == EventType.DragPerform) 208 | { 209 | DragAndDrop.AcceptDrag(); 210 | OnGameObjectsDragIn(DragAndDrop.objectReferences.Cast().ToArray(), 211 | evt.mousePosition); 212 | } 213 | } 214 | 215 | DrawViewGraph(); 216 | } 217 | 218 | private void Update() 219 | { 220 | float curTime = Time.realtimeSinceStartup; 221 | m_LastUpdateTime = Mathf.Min(m_LastUpdateTime, curTime); //very important!!! 222 | m_Timer = curTime - m_LastUpdateTime; 223 | m_LastUpdateTime = curTime; 224 | } 225 | 226 | private void OnFocus() 227 | { 228 | m_HasFocus = true; 229 | } 230 | 231 | private void OnLostFocus() 232 | { 233 | m_HasFocus = false; 234 | // m_SelectedNodes.Clear(); 235 | // UpdateNodesSelectedState(m_SelectedNodes); 236 | } 237 | 238 | private void ChangeDrawInspector() 239 | { 240 | m_DrawInspector = !m_DrawInspector; 241 | } 242 | 243 | private void DrawViewGraph() 244 | { 245 | float nodeInspectorWidth = m_DrawInspector?m_NodeInspectorWidth:0; 246 | ConstructGraphGUI(); 247 | var graphViewArea = new Rect(0, 0, position.width - nodeInspectorWidth, position.height); 248 | GraphBackground.DrawGrid(graphViewArea, currentZoom, Vector2.zero); 249 | if(m_DrawInspector) DrawInspector(graphViewArea.width, nodeInspectorWidth); 250 | m_GraphAreaIncludingTab = new Rect(0, 20, position.width, position.height); 251 | m_ScaledGraphArea = new Rect(0, 0, graphViewArea.width / currentZoom, graphViewArea.height / currentZoom); 252 | var initialMatrix = GUI.matrix; //save initial matrix 253 | HandleMouseHover(); 254 | GUI.EndClip(); 255 | GUI.BeginClip(new Rect(m_GraphAreaIncludingTab.position, m_ScaledGraphArea.size)); 256 | var translation = Matrix4x4.TRS(m_GraphAreaIncludingTab.position, Quaternion.identity, Vector3.one); 257 | var scale = Matrix4x4.Scale(Vector3.one * currentZoom); 258 | { 259 | GUI.matrix = translation * scale * translation.inverse; 260 | { 261 | DrawEdges(); 262 | DrawNodes(graphViewArea); 263 | DrawPortsEdgePoints(); 264 | DrawLineFromPortToPosition(m_ActivePort, Event.current.mousePosition); 265 | DrawSelectionBox(); 266 | } 267 | } 268 | GUI.EndClip(); 269 | GUI.BeginClip(m_GraphAreaIncludingTab); 270 | GUI.matrix = initialMatrix; //reset the matrix to the initial value 271 | DrawToolbar(); 272 | 273 | HandleZoom(); 274 | HandlePanning(); 275 | HandleMouseRightClicks(); 276 | HandleMouseMiddleClicks(); 277 | HandleMouseLeftClicks(); 278 | HandleKeys(); 279 | WhileDraggingUpdateSelectedNodes(); 280 | } 281 | 282 | private void WhileDraggingUpdateSelectedNodes() 283 | { 284 | if (m_Mode != GraphMode.Drag) return; 285 | 286 | var validatePointsDatabase = false; //bool that triggers a PointsDatabase validation 287 | var validateConnectionsDatabase = false; //bool that triggers a ConnectionsDatabase validation 288 | 289 | foreach (var selectedNode in m_SelectedNodes) //go through all the selected nodes 290 | { 291 | foreach (var virtualPoints in selectedNode.outputPorts.Select(outputSocket => points[outputSocket.id])) 292 | { 293 | if (virtualPoints == null) 294 | { 295 | validatePointsDatabase = true; 296 | continue; 297 | } 298 | 299 | foreach (var virtualPoint in virtualPoints) 300 | { 301 | if (virtualPoint == null) //point is null -> trigger validation 302 | { 303 | validatePointsDatabase = true; 304 | continue; 305 | } 306 | 307 | if (virtualPoint.node == null) //point parent Node is null -> trigger validation 308 | { 309 | validatePointsDatabase = true; 310 | continue; 311 | } 312 | 313 | virtualPoint 314 | .CalculateRect(); //recalculate the rect to reflect the new values (the new WorldPosition) 315 | } 316 | } 317 | 318 | foreach (Port inputSocket in selectedNode.inputPorts) //get the node's input sockets 319 | { 320 | List virtualPoints = points[inputSocket.id]; //get input socket's virtual points list 321 | if (virtualPoints == null) //list is null -> trigger validation 322 | { 323 | validatePointsDatabase = true; 324 | continue; 325 | } 326 | 327 | foreach (VirtualPoint virtualPoint in virtualPoints) 328 | { 329 | if (virtualPoint == null) //point is null -> trigger validation 330 | { 331 | validatePointsDatabase = true; 332 | continue; 333 | } 334 | 335 | if (virtualPoint.node == null) //point parent Node is null -> trigger validation 336 | { 337 | validatePointsDatabase = true; 338 | continue; 339 | } 340 | 341 | virtualPoint 342 | .CalculateRect(); //recalculate the rect to reflect the new values (the new WorldPosition) 343 | } 344 | } 345 | 346 | foreach (var ev in edgeViews.Values) //get all the virtual connections in the graph 347 | { 348 | //check the virtual connections for nulls -> if any null is found -> trigger validation 349 | if (ev == null || 350 | ev.outputNode == null || 351 | ev.outputPort == null || 352 | ev.outputVirtualPoint == null || 353 | ev.inputNode == null || 354 | ev.inputPort == null || 355 | ev.inputVirtualPoint == null) 356 | { 357 | validateConnectionsDatabase = true; 358 | continue; 359 | } 360 | 361 | if (ev.inputNode.id != selectedNode.id && ev.outputNode.id != selectedNode.id) continue; 362 | CalculateConnectionCurve( 363 | ev); //recalculate the connection curve to reflect the new values (the new WorldPosition) 364 | } 365 | } 366 | 367 | if (validatePointsDatabase) 368 | ValidatePointsDatabase(); 369 | if (validateConnectionsDatabase) 370 | ValidateConnectionsDatabase(); 371 | } 372 | 373 | private void ValidatePointsDatabase() 374 | { 375 | if (points == null) return; 376 | var invalidKeys = new List(); //temp keys list 377 | foreach (string key in points.Keys) 378 | { 379 | if (points[key] == null) 380 | { 381 | invalidKeys.Add(key); //null virtual points list -> remove key 382 | continue; 383 | } 384 | 385 | var vList = points[key]; 386 | var foundInvalidVirtualPoint = false; 387 | foreach (var virtualPoint in vList) 388 | { 389 | if (virtualPoint == null) 390 | { 391 | foundInvalidVirtualPoint = true; //null virtual point -> mark virtual point as invalid 392 | break; 393 | } 394 | 395 | if (virtualPoint.node == null) 396 | { 397 | foundInvalidVirtualPoint = 398 | true; //null virtual point parent Node -> mark virtual point as invalid 399 | break; 400 | } 401 | 402 | if (virtualPoint.port == null) 403 | { 404 | foundInvalidVirtualPoint = 405 | true; //null virtual point parent Socket -> mark virtual point as invalid 406 | break; 407 | } 408 | } 409 | 410 | if (foundInvalidVirtualPoint) 411 | invalidKeys.Add(key); //found an invalid virtual point in the virtual points list -> remove key 412 | } 413 | 414 | foreach (string invalidKey in invalidKeys) 415 | { 416 | points.Remove(invalidKey); //remove invalid keys 417 | } 418 | } 419 | 420 | private void ValidateConnectionsDatabase() 421 | { 422 | if (m_EdgeViews == null) return; 423 | var invalidKeys = new List(); //temp keys list 424 | foreach (var key in edgeViews.Keys) 425 | { 426 | if (edgeViews[key] == null) 427 | { 428 | invalidKeys.Add(key); //null virtual connection -> remove key 429 | continue; 430 | } 431 | 432 | var edgeView = edgeViews[key]; 433 | if (edgeView.outputNode == null) 434 | { 435 | invalidKeys.Add(key); //null output node -> remove key 436 | continue; 437 | } 438 | 439 | if (edgeView.inputNode == null) 440 | { 441 | invalidKeys.Add(key); //null input node -> remove key 442 | continue; 443 | } 444 | 445 | if (edgeView.outputPort == null) 446 | { 447 | invalidKeys.Add(key); //null output socket -> remove key 448 | continue; 449 | } 450 | 451 | if (edgeView.inputPort == null) invalidKeys.Add(key); //null input socket -> remove key 452 | } 453 | 454 | foreach (string invalidKey in invalidKeys) 455 | { 456 | edgeViews.Remove(invalidKey); //remove invalid keys 457 | } 458 | } 459 | 460 | private void ConstructGraphGUI() 461 | { 462 | if (m_Graph == null) return; 463 | if (m_NodeViews!=null && m_NodeViews.Count != m_Graph.values.Count) 464 | { 465 | nodeViews.Clear(); 466 | foreach (var item in m_Graph.values) 467 | { 468 | CreateNodeView(item); 469 | } 470 | } 471 | m_Points = null; 472 | m_Ports = null; 473 | m_EdgeViews = null; 474 | m_Points = points; 475 | m_Ports = ports; 476 | m_EdgeViews = edgeViews; 477 | //calculate all the connection points initial values 478 | CalculateAllPointRects(); 479 | //calculate all the connections initial values 480 | //we do this here because in normal operation we want to update only the connections that are referencing nodes that are being dragged 481 | CalculateAllConnectionCurves(); 482 | //update the visual state of all the connection points 483 | UpdateVirtualPointsIsOccupiedStates(); 484 | //check for errors 485 | CheckAllNodesForErrors(); 486 | } 487 | 488 | private void CalculateAllPointRects() 489 | { 490 | foreach (string key in points.Keys) 491 | foreach (VirtualPoint virtualPoint in points[key]) 492 | virtualPoint.CalculateRect(); 493 | } 494 | 495 | private void CalculateAllConnectionCurves() 496 | { 497 | foreach (EdgeView edgeView in m_EdgeViews.Values) 498 | { 499 | if (edgeView == null || 500 | edgeView.outputNode == null || 501 | edgeView.outputPort == null || 502 | edgeView.inputNode == null || 503 | edgeView.inputPort == null) 504 | continue; 505 | 506 | CalculateConnectionCurve(edgeView); 507 | } 508 | } 509 | 510 | private void CalculateConnectionCurve(EdgeView ev) 511 | { 512 | //get the lists of all the calculated virtual points for both Ports 513 | var outputVirtualPoints = points[ev.outputPort.id]; 514 | var inputVirtualPoints = points[ev.inputPort.id]; 515 | 516 | //get both OutputPort and InputPort rects converted to WorldSpace 517 | var outputPortWorldRect = GetPortWorldRect(ev.outputPort); 518 | var inputPortWorldRect = GetPortWorldRect(ev.inputPort); 519 | 520 | //get position values needed to determine the connection points and curve settings 521 | var outputPortCenter = outputPortWorldRect.center.x; 522 | var inputPortCenter = inputPortWorldRect.center.x; 523 | 524 | //get the closest virtual points for both Ports 525 | float minDistance = 100000; 526 | if (m_Graph.leftInRightOut) 527 | { 528 | ev.outputVirtualPoint = outputVirtualPoints[1]; 529 | ev.inputVirtualPoint = inputVirtualPoints[0]; 530 | minDistance = Vector2.Distance(ev.outputVirtualPoint.rect.position, ev.inputVirtualPoint.rect.position); 531 | } 532 | else 533 | { 534 | foreach (var outputVirtualPoint in outputVirtualPoints) 535 | { 536 | foreach (var inputVirtualPoint in inputVirtualPoints) 537 | { 538 | var currentDistance = Vector2.Distance(outputVirtualPoint.rect.position, 539 | inputVirtualPoint.rect.position); 540 | if (currentDistance > minDistance) continue; 541 | ev.outputVirtualPoint = outputVirtualPoint; 542 | ev.inputVirtualPoint = inputVirtualPoint; 543 | minDistance = currentDistance; 544 | } 545 | } 546 | } 547 | 548 | //set both the output and the input points as their respective tangents 549 | var zoomedPanOffset = m_Graph.currentPanOffset / currentZoom; 550 | 551 | var outputPoint = ev.outputVirtualPoint.rect.position - zoomedPanOffset; 552 | var inputPoint = ev.inputVirtualPoint.rect.position - zoomedPanOffset; 553 | var outputNodeWidth = ev.outputNode.GetWidth(); 554 | var inputNodeWidth = ev.inputNode.GetWidth(); 555 | var widthDifference = outputNodeWidth > inputNodeWidth 556 | ? outputNodeWidth - inputNodeWidth 557 | : inputNodeWidth - outputNodeWidth; 558 | 559 | ev.outputTangent = outputPoint + zoomedPanOffset; 560 | ev.inputTangent = inputPoint + zoomedPanOffset; 561 | 562 | //UP TO THIS POINT WE HAVE A STRAIGHT LINE 563 | //from here we start calculating the custom tangent values -> thus turning our connection line into a dynamic curve 564 | 565 | Vector2 outputTangentArcDirection; //output point tangent 566 | Vector2 inputTangentArcDirection; //input point tangent 567 | 568 | //OUTPUT RIGHT CONNECTION 569 | if (outputPortCenter < inputPortCenter && outputPortCenter <= inputPoint.x || 570 | outputPortCenter >= inputPortCenter && outputPoint.x >= inputPortCenter && 571 | outputPortCenter <= inputPoint.x) 572 | { 573 | if (outputPoint.x <= inputPortCenter + widthDifference / 2 && inputPortCenter > outputPoint.x) 574 | { 575 | outputTangentArcDirection = Vector2.right; 576 | inputTangentArcDirection = Vector2.left; 577 | } 578 | else 579 | { 580 | outputTangentArcDirection = Vector2.right; 581 | inputTangentArcDirection = Vector2.right; 582 | } 583 | } 584 | //OUTPUT LEFT CONNECTION 585 | else 586 | { 587 | if (outputPoint.x >= inputPortCenter) 588 | { 589 | outputTangentArcDirection = Vector2.left; 590 | inputTangentArcDirection = Vector2.right; 591 | } 592 | else 593 | { 594 | outputTangentArcDirection = Vector2.left; 595 | inputTangentArcDirection = Vector2.left; 596 | } 597 | } 598 | 599 | //set the curve strength (curvature) to be dynamic, by taking into account the distance between the connection points 600 | var outputCurveStrength = minDistance * (0.48f + ev.outputPort.curveModifier); 601 | var inputCurveStrength = minDistance * (0.48f + ev.inputPort.curveModifier); 602 | //update the tangents with the dynamic values 603 | ev.outputTangent += outputTangentArcDirection * outputCurveStrength; 604 | ev.inputTangent += inputTangentArcDirection * inputCurveStrength; 605 | } 606 | 607 | private Rect GetPortWorldRect(Port port) 608 | { 609 | if (port == null) return new Rect(); 610 | var parentNode = nodeViews[port.nodeId].node; 611 | if (parentNode == null) return new Rect(); 612 | var socketWorldRect = new Rect(parentNode.GetX(), 613 | parentNode.GetY() + port.GetY(), 614 | port.GetWidth(), 615 | port.GetHeight()); 616 | return socketWorldRect; 617 | } 618 | 619 | private void CheckAllNodesForErrors() 620 | { 621 | foreach (var nodeView in nodeViews.Values) 622 | { 623 | nodeView.node.CheckForErrors(); 624 | } 625 | 626 | Repaint(); 627 | } 628 | 629 | private enum GraphMode 630 | { 631 | None, 632 | Connect, 633 | Select, 634 | Drag, 635 | Pan, 636 | Delete 637 | } 638 | 639 | private enum GraphAction 640 | { 641 | Copy, 642 | Connect, 643 | CreateNode, 644 | DeleteNodes, 645 | DeselectAll, 646 | Disconnect, 647 | Paste, 648 | SelectAll, 649 | SelectNodes 650 | } 651 | 652 | private class SelectPoint 653 | { 654 | public readonly float x; 655 | public readonly float y; 656 | 657 | public SelectPoint(Vector2 position) 658 | { 659 | x = position.x; 660 | y = position.y; 661 | } 662 | } 663 | } 664 | 665 | 666 | public abstract partial class GraphWindow : GraphWindow where T : GraphBase 667 | { 668 | public T m_Graph => base.m_Graph as T; 669 | protected sealed override GraphBase CreateGraphBase() 670 | { 671 | return CreateGraph(); 672 | } 673 | 674 | protected abstract T CreateGraph(); 675 | 676 | protected sealed override GraphBase LoadGraphBase() 677 | { 678 | return LoadGraph(); 679 | } 680 | 681 | protected abstract T LoadGraph(); 682 | } 683 | } -------------------------------------------------------------------------------- /Editor/GraphWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8733c1abfab03248a66a813490370f2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphWindowDraw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | 8 | namespace DaGenGraph.Editor 9 | { 10 | public abstract partial class GraphWindow 11 | { 12 | #region GUIStyles 13 | 14 | private static GUIStyle s_DotStyle; 15 | private static GUIStyle s_ConnectionPointOverrideEmpty; 16 | private static GUIStyle s_ConnectionPointOverrideConnected; 17 | private static GUIStyle s_ConnectionPointMultipleEmpty; 18 | private static GUIStyle s_ConnectionPointMultipleConnected; 19 | private static GUIStyle s_ConnectionPointMinus; 20 | 21 | private static GUIStyle dotStyle 22 | { 23 | get { return s_DotStyle ?? (s_DotStyle = Styles.GetStyle("NodeDot")); } 24 | } 25 | 26 | private static GUIStyle edgePointOverrideEmpty 27 | { 28 | get 29 | { 30 | return s_ConnectionPointOverrideEmpty ?? 31 | (s_ConnectionPointOverrideEmpty = Styles.GetStyle("ConnectionPointOverrideEmpty")); 32 | } 33 | } 34 | 35 | private static GUIStyle edgePointOverrideConnected 36 | { 37 | get 38 | { 39 | return s_ConnectionPointOverrideConnected ?? (s_ConnectionPointOverrideConnected = 40 | Styles.GetStyle("ConnectionPointOverrideConnected")); 41 | } 42 | } 43 | 44 | private static GUIStyle edgePointMultipleEmpty 45 | { 46 | get 47 | { 48 | return s_ConnectionPointMultipleEmpty ?? 49 | (s_ConnectionPointMultipleEmpty = Styles.GetStyle("ConnectionPointMultipleEmpty")); 50 | } 51 | } 52 | 53 | private static GUIStyle edgePointMultipleConnected 54 | { 55 | get 56 | { 57 | return s_ConnectionPointMultipleConnected ?? (s_ConnectionPointMultipleConnected = 58 | Styles.GetStyle("ConnectionPointMultipleConnected")); 59 | } 60 | } 61 | 62 | private static GUIStyle edgePointMinus 63 | { 64 | get { return s_ConnectionPointMinus ?? (s_ConnectionPointMinus = Styles.GetStyle("ConnectionPointMinus")); } 65 | } 66 | 67 | #endregion 68 | 69 | #region Private Variables 70 | 71 | private delegate void DrawToolbarHandler(); 72 | 73 | private List m_DrawToolbarHandlers=new List(); 74 | private List m_DrawToolbarHandlersRight=new List(); 75 | private Color m_CreateEdgeLineColor = Color.white; 76 | private Color m_ConnectionBackgroundColor; 77 | private Color m_EdgeColor; 78 | private Color m_DotColor; 79 | private Color m_InputColor; 80 | private Color m_NormalColor; 81 | private Color m_OutputColor; 82 | private Vector3 m_DotPoint; 83 | private Vector3[] m_BezierPoints; 84 | private float m_ConnectionAlpha; 85 | private float m_DotSize; 86 | private int m_DotPointIndex; 87 | private int m_NumberOfPoints; 88 | 89 | 90 | #endregion 91 | 92 | #region DrawEdges 93 | 94 | private void DrawEdges() 95 | { 96 | if (currentZoom <= 0.2f) return; 97 | if (m_NodeViews == null) return; 98 | m_AniTime += m_Timer; 99 | if (m_AniTime >= 3) 100 | { 101 | m_AniTime = 0; 102 | } 103 | 104 | foreach (var edgeView in edgeViews.Values) 105 | { 106 | if (edgeView.outputNode == null || edgeView.inputNode == null) 107 | { 108 | continue; 109 | } 110 | 111 | //if both nodes are not visible -> do not draw the edge 112 | if (!m_NodeViews[edgeView.inputNode.id].isVisible && !m_NodeViews[edgeView.inputNode.id].isVisible) 113 | { 114 | continue; 115 | } 116 | 117 | if (edgeView.outputVirtualPoint == null || edgeView.inputVirtualPoint == null) 118 | { 119 | continue; 120 | } 121 | 122 | DrawEdgeCurve(edgeView); 123 | } 124 | } 125 | 126 | private void DrawEdgeCurve(EdgeView edge) 127 | { 128 | //connect 129 | m_ConnectionAlpha = 1f; 130 | if (m_Mode == GraphMode.Connect) m_ConnectionAlpha = 0.5f; 131 | 132 | m_NormalColor = UColor.GetColor().edgeNormalColor; 133 | m_OutputColor = UColor.GetColor().edgeOutputColor; 134 | m_InputColor = UColor.GetColor().edgeInputColor; 135 | m_NormalColor.a = m_ConnectionAlpha; 136 | m_OutputColor.a = m_ConnectionAlpha; 137 | m_InputColor.a = m_ConnectionAlpha; 138 | m_EdgeColor = m_NormalColor; 139 | m_AnimateInput = false; 140 | m_AnimateOutput = false; 141 | 142 | //A node is selected and the Alt Key is not pressed -> show the edge color depending on socket type of this node (if it is an output or an input one) 143 | if (m_SelectedNodes.Count == 1 && !altKeyPressed) 144 | { 145 | NodeBase selectedNode = m_SelectedNodes[0]; 146 | if (selectedNode == null) return; 147 | if (selectedNode.ContainsEdge(edge.edgeId)) 148 | { 149 | if (selectedNode == edge.outputNode) 150 | { 151 | //color for output edge 152 | m_EdgeColor = m_OutputColor; 153 | m_AnimateOutput = true; 154 | } 155 | 156 | if (selectedNode == edge.inputNode) 157 | { 158 | //color for input edge 159 | m_EdgeColor = m_InputColor; 160 | m_AnimateInput = true; 161 | } 162 | } 163 | } 164 | 165 | float currentCurveWidth = 3; 166 | if (EditorApplication.isPlaying) 167 | { 168 | if (m_Graph.GetEdge(edge.edgeId).ping) 169 | { 170 | m_EdgeColor = m_OutputColor; 171 | m_AnimateOutput = true; 172 | if (m_Graph.GetEdge(edge.edgeId).reSetTime) 173 | { 174 | m_AniTime = 0; 175 | m_Graph.GetEdge(edge.edgeId).reSetTime = false; 176 | } 177 | } 178 | else if (m_Graph.GetEdge(edge.edgeId).ping) 179 | { 180 | m_EdgeColor = m_InputColor; 181 | m_AnimateInput = true; 182 | if (m_Graph.GetEdge(edge.edgeId).reSetTime) 183 | { 184 | m_AniTime = 0; 185 | m_Graph.GetEdge(edge.edgeId).reSetTime = false; 186 | } 187 | } 188 | } 189 | else if (m_Graph.GetEdge(edge.edgeId).ping || 190 | m_Graph.GetEdge(edge.edgeId).ping) 191 | { 192 | m_Graph.GetEdge(edge.edgeId).ping = false; 193 | m_Graph.GetEdge(edge.edgeId).ping = false; 194 | } 195 | 196 | m_DotColor = m_EdgeColor; 197 | if (altKeyPressed) //delete mode is enabled -> check if we should color the edge to RED 198 | { 199 | //check this edge's points by testing if the mouse if hovering over one of this edge's virtual points 200 | bool colorTheConnectionRed = edge.inputVirtualPoint == m_CurrentHoveredVirtualPoint || 201 | edge.outputVirtualPoint == m_CurrentHoveredVirtualPoint; 202 | if (colorTheConnectionRed) 203 | { 204 | //set the edge color to RED -> as the developer might want to remove this edge 205 | m_EdgeColor = Color.red; 206 | //make the red curve just a tiny bit more thick to make it stand out even better 207 | currentCurveWidth += 1; 208 | } 209 | } 210 | 211 | m_ConnectionBackgroundColor = new Color(m_EdgeColor.r * 0.2f, 212 | m_EdgeColor.g * 0.2f, 213 | m_EdgeColor.b * 0.2f, 214 | m_ConnectionAlpha - 0.2f); 215 | 216 | //HandleUtility.handleMaterial.SetPass(0); 217 | Handles.DrawBezier(edge.outputVirtualPoint.rect.position, 218 | edge.inputVirtualPoint.rect.position, 219 | edge.outputTangent, 220 | edge.inputTangent, 221 | m_ConnectionBackgroundColor, 222 | null, 223 | currentCurveWidth + 2); 224 | Handles.DrawBezier(edge.outputVirtualPoint.rect.position, 225 | edge.inputVirtualPoint.rect.position, 226 | edge.outputTangent, 227 | edge.inputTangent, 228 | m_EdgeColor, 229 | null, 230 | currentCurveWidth); 231 | //if the window does not have focus -> return (DO NOT PLAY ANIMATION) 232 | //if (!m_HasFocus) return; 233 | //if the mouse is not inside the window -> return (DO NOT PLAY ANIMATION) 234 | //if (!MouseInsideWindow) return; 235 | if (!m_AnimateInput && !m_AnimateOutput) 236 | { 237 | //if the animation is not enabled for both points -> return (DO NOT PLAY ANIMATION) 238 | return; 239 | } 240 | 241 | //points multiplier - useful for a smooth dot travel - smaller means fewer travel point (makes the point 'jumpy') and higher means more travel points (make the point move smoothly) 242 | m_NumberOfPoints = 243 | (int)(Vector2.Distance(edge.outputVirtualPoint.rect.position, edge.inputVirtualPoint.rect.position) * 244 | 3); 245 | if (m_NumberOfPoints <= 0) return; 246 | m_BezierPoints = Handles.MakeBezierPoints(edge.outputVirtualPoint.rect.position, 247 | edge.inputVirtualPoint.rect.position, 248 | edge.outputTangent, 249 | edge.inputTangent, 250 | m_NumberOfPoints); 251 | m_DotPointIndex = 0; 252 | //we set the number of points as the bezierPoints length - 1 253 | m_NumberOfPoints--; 254 | if (m_AnimateInput) 255 | { 256 | m_DotPointIndex = (int)(m_AniTime * m_NumberOfPoints); 257 | } 258 | else if (m_AnimateOutput) 259 | { 260 | m_DotPointIndex = m_NumberOfPoints - (int)((1 - m_AniTime) * m_NumberOfPoints); 261 | } 262 | 263 | m_DotPointIndex = Mathf.Clamp(m_DotPointIndex, 0, m_NumberOfPoints); 264 | //reset edge's ping 265 | if (m_Graph.GetEdge(edge.edgeId).ping && m_DotPointIndex >= m_NumberOfPoints) 266 | { 267 | m_Graph.GetEdge(edge.edgeId).ping = false; 268 | } 269 | 270 | m_DotPoint = m_BezierPoints[m_DotPointIndex]; 271 | m_DotSize = currentCurveWidth * 2; 272 | //make the dot a bit brighter 273 | m_DotColor = new Color(m_DotColor.r * 1.2f, m_DotColor.g * 1.2f, m_DotColor.b * 1.2f, m_DotColor.a); 274 | 275 | GUI.color = m_DotColor; 276 | GUI.Box(new Rect(m_DotPoint.x - m_DotSize / 2, m_DotPoint.y - m_DotSize / 2, m_DotSize, m_DotSize), "", 277 | dotStyle); 278 | GUI.color = Color.white; 279 | } 280 | 281 | #endregion 282 | 283 | #region DrawNodes 284 | 285 | private void DrawNodes(Rect graphArea) 286 | { 287 | BeginWindows(); 288 | foreach (var nodeView in m_NodeViews.Values) 289 | { 290 | nodeView.zoomedBeyondPortDrawThreshold = currentZoom <= 0.4f; 291 | nodeView.DrawNodeGUI(graphArea, m_Graph.currentPanOffset, currentZoom); 292 | } 293 | 294 | EndWindows(); 295 | } 296 | 297 | #endregion 298 | 299 | #region DrawPortsEdgePoints 300 | 301 | private void DrawPortsEdgePoints() 302 | { 303 | if (currentZoom <= 0.4f) return; 304 | foreach (var port in ports.Values) 305 | { 306 | DrawPortEdgePoints(port); //draw the edge points 307 | } 308 | } 309 | 310 | private void DrawPortEdgePoints(Port port) 311 | { 312 | foreach (var virtualPoint in points[port.id]) 313 | { 314 | var mouseIsOverThisPoint = virtualPoint == m_CurrentHoveredVirtualPoint; 315 | if (m_AltKeyPressedAnimBool.faded > 0.5f && virtualPoint.isConnected) 316 | { 317 | //set the virtualPoint delete color to RED 318 | //set the virtualPoint style to show to the dev that he can disconnect the socket (it's a minus sign) 319 | DrawEdgePoint(virtualPoint, mouseIsOverThisPoint, Styles.GetStyle("ConnectionPointMinus"), 320 | Color.red); 321 | continue; 322 | } 323 | 324 | var pointColor = port.IsInput() ? UColor.GetColor().portInputColor : UColor.GetColor().portOutputColor; 325 | GUIStyle pointStyle; 326 | switch (port.GetConnectionMode()) 327 | { 328 | case EdgeMode.Override: 329 | pointStyle = virtualPoint.isConnected ? edgePointOverrideConnected : edgePointOverrideEmpty; 330 | break; 331 | case EdgeMode.Multiple: 332 | pointStyle = virtualPoint.isConnected ? edgePointMultipleConnected : edgePointMultipleEmpty; 333 | break; 334 | default: 335 | throw new ArgumentOutOfRangeException(); 336 | } 337 | 338 | DrawEdgePoint(virtualPoint, mouseIsOverThisPoint, pointStyle, pointColor); 339 | } 340 | } 341 | 342 | private void DrawEdgePoint(VirtualPoint virtualPoint, bool mouseIsOverThisPoint, GUIStyle pointStyle, 343 | Color pointColor) 344 | { 345 | pointColor.a = virtualPoint.isConnected || mouseIsOverThisPoint ? 1f : 0.8f; 346 | //this makes an unoccupied connector a bit smaller than an occupied one (looks nicer) 347 | var occupiedRatioChange = virtualPoint.isConnected ? 1f : 0.8f; 348 | var pointWidth = 16f * occupiedRatioChange * (mouseIsOverThisPoint ? 1.2f : 1f); 349 | var pointHeight = 16f * occupiedRatioChange * (mouseIsOverThisPoint ? 1.2f : 1f); 350 | var pointRect = new Rect(virtualPoint.rect.position.x - pointWidth / 2, 351 | virtualPoint.rect.position.y - pointHeight / 2, 352 | pointWidth, 353 | pointHeight); 354 | GUI.color = pointColor; 355 | GUI.Box(pointRect, GUIContent.none, pointStyle); 356 | GUI.color = Color.white; 357 | } 358 | 359 | #endregion 360 | 361 | #region DrawLineFromPortToPosition 362 | 363 | private void DrawLineFromPortToPosition(Port activePort, Vector2 worldPosition) 364 | { 365 | if (m_Mode != GraphMode.Connect) return; 366 | if (currentZoom <= 0.4f) return; 367 | var from = GetClosestEdgePointWorldPositionFromPortToMousePosition(activePort, 368 | worldPosition / currentZoom); 369 | var to = worldPosition; 370 | float edgeLineWidth = 3; 371 | var edgeBackgroundColor = new Color(m_CreateEdgeLineColor.r * 0.2f, 372 | m_CreateEdgeLineColor.g * 0.2f, m_CreateEdgeLineColor.b * 0.2f, 0.8f); 373 | Handles.DrawBezier(from, to, to, from, edgeBackgroundColor, null, edgeLineWidth + 2); 374 | Handles.DrawBezier(from, to, to, from, m_CreateEdgeLineColor, null, edgeLineWidth); 375 | var dotSize = edgeLineWidth * 3; 376 | GUI.color = new Color(m_CreateEdgeLineColor.r * 1.2f, m_CreateEdgeLineColor.g * 1.2f, 377 | m_CreateEdgeLineColor.b * 1.2f, 1f); 378 | GUI.Box(new Rect(to.x - dotSize / 2, to.y - dotSize / 2, dotSize, dotSize), "", dotStyle); 379 | GUI.color = Color.white; 380 | HandleUtility.Repaint(); 381 | Repaint(); 382 | } 383 | 384 | private Vector2 GetClosestEdgePointWorldPositionFromPortToMousePosition(Port port, Vector2 mousePosition) 385 | { 386 | var parentNode = nodeViews[port.nodeId].node; 387 | if (parentNode == null) return Vector2.zero; 388 | var pointsInWorldSpace = GetPortEdgePointsInWorldSpace(port, parentNode); 389 | float minDistance = 100000; 390 | var worldPosition = parentNode.GetPosition(); 391 | foreach (Vector2 edgePointWorldPosition in pointsInWorldSpace) 392 | { 393 | float currentDistance = Vector2.Distance(edgePointWorldPosition, mousePosition); 394 | if (currentDistance > minDistance) continue; 395 | worldPosition = edgePointWorldPosition; 396 | minDistance = currentDistance; 397 | } 398 | 399 | return worldPosition; 400 | } 401 | 402 | private IEnumerable GetPortEdgePointsInWorldSpace(Port port, NodeBase parentNode) 403 | { 404 | var pointsInWorldSpace = new List(); 405 | if (port == null) return pointsInWorldSpace; 406 | if (parentNode == null) return pointsInWorldSpace; 407 | foreach (Vector2 edgePoint in port.GetEdgePoints()) 408 | { 409 | var socketWorldRect = new Rect(parentNode.GetX(), 410 | parentNode.GetY() + port.GetY(), 411 | port.GetWidth(), 412 | port.GetHeight()); 413 | 414 | socketWorldRect.position += 415 | m_Graph.currentPanOffset / currentZoom; //this is the calculated socketGridRect 416 | pointsInWorldSpace.Add(new Vector2(socketWorldRect.x + edgePoint.x + 8, 417 | socketWorldRect.y + edgePoint.y + 8)); 418 | } 419 | 420 | return pointsInWorldSpace; 421 | } 422 | 423 | #endregion 424 | 425 | #region DrawSelectionBox 426 | 427 | private void DrawSelectionBox() 428 | { 429 | if (m_Mode != GraphMode.Select) return; 430 | Color initialColor = GUI.color; 431 | GUI.color = (EditorGUIUtility.isProSkin ? new Color(0f, 0f, 0f, 0.3f) : new Color(1, 1, 1, 0.3f)); 432 | var sty = Styles.GetStyle("BackgroundSquare"); 433 | GUI.Label(m_SelectionRect, string.Empty, sty); 434 | GUI.color = initialColor; 435 | } 436 | 437 | #endregion 438 | 439 | #region DrawToolbar 440 | 441 | protected virtual void AddButton(GUIContent content, Action callback,bool left = true, 442 | params GUILayoutOption[] options) 443 | { 444 | if (left) 445 | { 446 | m_DrawToolbarHandlers.Add(() => 447 | { 448 | if (GUILayout.Button(content, options)) 449 | { 450 | callback.Invoke(); 451 | } 452 | }); 453 | } 454 | else 455 | { 456 | m_DrawToolbarHandlersRight.Add(() => 457 | { 458 | if (GUILayout.Button(content, options)) 459 | { 460 | callback.Invoke(); 461 | } 462 | }); 463 | } 464 | } 465 | 466 | private void DrawToolbar() 467 | { 468 | GUILayout.BeginHorizontal(EditorStyles.toolbar); 469 | foreach (var drawToolbarHandler in m_DrawToolbarHandlers) 470 | { 471 | drawToolbarHandler.Invoke(); 472 | } 473 | 474 | GUILayout.FlexibleSpace(); 475 | foreach (var drawToolbarHandler in m_DrawToolbarHandlersRight) 476 | { 477 | drawToolbarHandler.Invoke(); 478 | } 479 | GUILayout.EndHorizontal(); 480 | } 481 | 482 | #endregion 483 | 484 | #region DrawInspector 485 | 486 | private Vector2 nodeScrollPos; 487 | private Vector2 graphScrollPos; 488 | private bool foldGraph; 489 | private Dictionary foldNode = new Dictionary(); 490 | private void DrawInspector(float start,float width) 491 | { 492 | bool showNodeView = m_Graph!=null && m_SelectedNodes!=null && m_SelectedNodes.Count>0; 493 | var inspectorArea = new Rect(start, 20, width, position.height-20); 494 | GUILayout.BeginArea(inspectorArea); 495 | foldGraph = EditorGUILayout.BeginFoldoutHeaderGroup(foldGraph, m_Graph.name); 496 | if (foldGraph) 497 | { 498 | graphScrollPos = EditorGUILayout.BeginScrollView(graphScrollPos, GUILayout.Width(inspectorArea.width), GUILayout.Height(showNodeView?200:inspectorArea.height-20)); 499 | DrawGraphInspector(); 500 | EditorGUILayout.EndScrollView(); 501 | } 502 | EditorGUILayout.EndFoldoutHeaderGroup(); 503 | if (showNodeView) 504 | { 505 | nodeScrollPos = EditorGUILayout.BeginScrollView(nodeScrollPos, GUILayout.Width(inspectorArea.width), GUILayout.Height(inspectorArea.height-(foldGraph?225:25))); 506 | for (int i = 0; i < m_SelectedNodes.Count; i++) 507 | { 508 | var node = m_SelectedNodes[i]; 509 | if (node == null) continue; 510 | if(!nodeViews.TryGetValue(node.id,out var view)) continue; 511 | if (!foldNode.TryGetValue(node.id, out var fold)) 512 | { 513 | fold = false; 514 | foldNode[m_SelectedNodes[i].id] = fold; 515 | } 516 | fold = EditorGUILayout.BeginFoldoutHeaderGroup(fold, $"{node.name}({node.id})"); 517 | if (fold) 518 | { 519 | EditorGUILayout.Space(10); 520 | //nodeView自己决定展示 521 | view.DrawInspector(true); 522 | } 523 | foldNode[m_SelectedNodes[i].id] = fold; 524 | EditorGUILayout.EndFoldoutHeaderGroup(); 525 | } 526 | EditorGUILayout.EndScrollView(); 527 | } 528 | GUILayout.EndArea(); 529 | } 530 | 531 | protected virtual void DrawGraphInspector() 532 | { 533 | DrawObjectInspector(m_Graph, true); 534 | } 535 | #endregion 536 | } 537 | } -------------------------------------------------------------------------------- /Editor/GraphWindowDraw.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f2a082a15c94cba9c7f7b1119fd643f 3 | timeCreated: 1623033172 -------------------------------------------------------------------------------- /Editor/GroupInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace DaGenGraph.Editor 6 | { 7 | public interface ISort 8 | { 9 | public float MinSort { get; } 10 | } 11 | public class GroupItem:ISort 12 | { 13 | public float MinSort { get; set; } 14 | public string GroupId; 15 | public List Members = new (); 16 | } 17 | 18 | public class MemberItem:ISort 19 | { 20 | public float MinSort{ get; set; } 21 | public MemberInfo Member; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /Editor/GroupInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c59bfa784a3d48f1bd30966a15085581 3 | timeCreated: 1737624988 -------------------------------------------------------------------------------- /Editor/NodeView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace DaGenGraph.Editor 8 | { 9 | public class NodeView : DrawBase 10 | { 11 | #region Private Variables 12 | 13 | private NodeBase m_Node; 14 | private GraphWindow m_graphWindow; 15 | private int m_WindowId; 16 | private GraphBase m_Graph; 17 | private Vector2 m_DeleteButtonSize; 18 | private Vector2 m_Offset; 19 | private Rect m_DrawRect; 20 | public bool isVisible = true; 21 | public bool zoomedBeyondPortDrawThreshold = false; 22 | public bool isSelected; 23 | private Rect m_GlowRect; 24 | private Rect m_HeaderRect; 25 | private Rect m_HeaderHoverRect; 26 | private Rect m_HeaderIconRect; 27 | private Rect m_HeaderTitleRect; 28 | private Rect m_BodyRect; 29 | private Rect m_FooterRect; 30 | private Rect m_NodeOutlineRect; 31 | private Color m_NodeGlowColor; 32 | private Color m_NodeHeaderAndFooterBackgroundColor; 33 | private Color m_RootNodeHeaderAndFooterBackgroundColor; 34 | private Color m_NodeBodyColor; 35 | private Color m_NodeOutlineColor; 36 | private Color m_HeaderTextAndIconColor; 37 | 38 | private HashSet foldoutState = new HashSet(); 39 | 40 | #endregion 41 | 42 | #region Properties 43 | 44 | public int windowId => m_WindowId; 45 | public NodeBase node => m_Node; 46 | public GraphBase graph => m_Graph; 47 | public float x => m_Node.GetX(); 48 | public float y => m_Node.GetY(); 49 | public float width => m_Node.GetWidth(); 50 | public float height => m_Node.GetHeight(); 51 | public Vector2 position => m_Node.GetPosition(); 52 | public Vector2 size => m_Node.GetSize(); 53 | public Rect rect => m_Node.GetRect(); 54 | public Rect drawRect => m_DrawRect; 55 | protected float dynamicHeight { get; set; } 56 | 57 | public GraphWindow graphWindow => m_graphWindow; 58 | #endregion 59 | 60 | #region GUIStyles 61 | 62 | private static GUIStyle s_NodeArea; 63 | private static GUIStyle nodeArea => s_NodeArea ??= Styles.GetStyle("NodeArea"); 64 | private static GUIStyle s_NodeBody; 65 | protected static GUIStyle nodeBody => s_NodeBody ??= Styles.GetStyle("NodeBody"); 66 | private static GUIStyle s_NodeOutline; 67 | protected static GUIStyle nodeOutline => s_NodeOutline ??= Styles.GetStyle("NodeOutline"); 68 | private static GUIStyle s_NodeGlow; 69 | protected static GUIStyle nodeGlowStyle => s_NodeGlow ??= Styles.GetStyle("NodeGlow"); 70 | private static GUIStyle s_Dot; 71 | private static GUIStyle nodeDot => s_Dot ??= Styles.GetStyle("NodeDot"); 72 | private static GUIStyle s_NodeHeader; 73 | private static GUIStyle nodeHeader => s_NodeHeader ??= Styles.GetStyle("NodeHeader"); 74 | private static GUIStyle s_NodeFooter; 75 | private static GUIStyle nodeFooter => s_NodeFooter ??= Styles.GetStyle("NodeFooter"); 76 | private static GUIStyle s_NodeHorizontalDivider; 77 | 78 | private static GUIStyle nodeHorizontalDivider => 79 | s_NodeHorizontalDivider ??= Styles.GetStyle("NodeHorizontalDivider"); 80 | 81 | #endregion 82 | 83 | #region Static Variables 84 | 85 | private static readonly float s_HeaderHeight = 32; 86 | private static readonly float s_HeaderIconSize = 20; 87 | private static float headerIconPadding => (s_HeaderHeight - s_HeaderIconSize) / 2; 88 | 89 | #endregion 90 | 91 | #region Virtual Methods 92 | 93 | public virtual void Init(int windowId, NodeBase node, GraphBase graph, GraphWindow graphWindow) 94 | { 95 | m_WindowId = windowId; 96 | m_Node = node; 97 | m_Graph = graph; 98 | m_graphWindow = graphWindow; 99 | m_Node.onDeletePort += OnDeletePort; 100 | } 101 | 102 | public virtual void OnDoubleClick(EditorWindow window) 103 | { 104 | } 105 | 106 | public virtual void OnUnFocus(EditorWindow window) 107 | { 108 | GUI.FocusControl(null); 109 | } 110 | 111 | protected virtual void OnNodeGUI() 112 | { 113 | DrawNodeBody(); 114 | DrawNodePorts(); 115 | } 116 | 117 | protected virtual GUIStyle GetIconStyle() 118 | { 119 | return nodeDot; 120 | } 121 | 122 | protected virtual Rect DrawPort(Port port) 123 | { 124 | //set Port to the left side of the node 125 | port.SetX(0); 126 | //set the y to the current draw height 127 | port.SetY(dynamicHeight); 128 | //set the Port width as the node width 129 | port.SetWidth(node.GetWidth()); 130 | port.SetHeight(24f); 131 | if (zoomedBeyondPortDrawThreshold) return port.GetRect(); 132 | 133 | //set the Port color to white or black - depending on the current skin - (we assume it's not connected) 134 | var portColor = Color.gray; 135 | var dividerColor = Color.gray; 136 | 137 | //check if the Port is connected in order to color the divider to the input or output color 138 | if (port.IsConnected()) 139 | { 140 | portColor = port.IsInput() ? UColor.GetColor().portInputColor : UColor.GetColor().portOutputColor; 141 | dividerColor = UColor.GetColor().nodeDividerColor; 142 | } 143 | 144 | //in order not to overpower the design with bold colors -> we make the color fade out a bit in order to make the graph easier on the eyes 145 | var opacity = 0.3f; 146 | portColor.a = opacity; 147 | dividerColor.a = opacity * 0.8f; 148 | 149 | //check if we are in delete mode -> if true -> set the socket color to red (ONLY if the socket can be deleted) 150 | if (m_graphWindow.altKeyPressed) 151 | { 152 | //since we're in delete mode and this socket can be deConnect -> set its color to red 153 | if (port.IsConnected()) 154 | { 155 | portColor = Color.red; 156 | dividerColor = Color.red; 157 | } 158 | 159 | //since we're in delete mode -> make the socket color a bit stronger (regardless if it can be deleted or not) -> this is a design choice 160 | portColor.a = opacity * 1.2f; 161 | dividerColor.a = opacity * 1.2f; 162 | } 163 | 164 | //calculate the top divider rect position and size -> this is the thin line at the bottom of every Port (design choice) 165 | var topDividerRect = new Rect(port.GetRect().x + 6, port.GetRect().y + 1f, port.GetRect().width - 12, 1); 166 | 167 | //color the gui to the defined Port color 168 | GUI.color = dividerColor; 169 | //DRAW the horizontal divider at the top of the Port 170 | GUI.Box(topDividerRect, GUIContent.none, nodeHorizontalDivider); 171 | //reset the gui color 172 | GUI.color = Color.white; 173 | 174 | //calculate the bottom divider rect position and size -> this is the thin line at the bottom of every Port (design choice) 175 | var bottomDividerRect = new Rect(port.GetRect().x + 6, port.GetRect().y + port.GetRect().height - 1, 176 | port.GetRect().width - 12, 1); 177 | 178 | //color the gui to the defined Port color 179 | GUI.color = dividerColor; 180 | //DRAW the horizontal divider at the bottom of the Port 181 | GUI.Box(bottomDividerRect, GUIContent.none, nodeHorizontalDivider); 182 | //reset the gui color 183 | GUI.color = Color.white; 184 | var label = port.portName; 185 | var areaRect = new Rect(port.GetX() + 24, port.GetY(), port.GetWidth() - 48, port.GetHeight()); 186 | GUILayout.BeginArea(areaRect); 187 | { 188 | GUILayout.BeginHorizontal(); 189 | { 190 | var labelStyle = Styles.GetStyle("NodePortText"); 191 | var content = new GUIContent(label); 192 | var contentSize = labelStyle.CalcSize(content); 193 | GUILayout.BeginVertical(GUILayout.Width(contentSize.x), GUILayout.Height(port.GetHeight())); 194 | { 195 | GUILayout.Space((port.GetHeight() - contentSize.y) / 2); 196 | GUILayout.Label(content, labelStyle, GUILayout.Width(contentSize.x)); 197 | } 198 | GUILayout.EndVertical(); 199 | } 200 | GUILayout.EndHorizontal(); 201 | } 202 | GUILayout.EndArea(); 203 | //calculate the Port hover rect -> this is the 'selection' box that appears when the mouse is over the Port 204 | port.UpdateHoverRect(); 205 | if (port.showHover.faded > 0.01f) 206 | { 207 | var animatedRect = new Rect(port.hoverRect.x, 208 | port.hoverRect.y + port.hoverRect.height * (1 - port.showHover.faded), 209 | port.hoverRect.width, 210 | port.hoverRect.height * port.showHover.faded); 211 | 212 | if (port.IsConnected()) 213 | { 214 | switch (port.GetDirection()) 215 | { 216 | case PortDirection.Input: 217 | GUI.color = UColor.GetColor().portInputColor.WithAlpha(0.1f); 218 | break; 219 | case PortDirection.Output: 220 | GUI.color = UColor.GetColor().portInputColor.WithAlpha(0.1f); 221 | break; 222 | default: throw new ArgumentOutOfRangeException(); 223 | } 224 | } 225 | 226 | //color the gui to the defined Port color 227 | GUI.color = portColor; 228 | //DRAW the animated overlay when the mouse is hovering over this Port 229 | GUI.Box(animatedRect, new GUIContent(label), nodeHorizontalDivider); 230 | GUI.color = Color.white; //reset the gui color 231 | } 232 | 233 | return port.GetRect(); 234 | } 235 | 236 | #endregion 237 | 238 | #region Protected Methods 239 | 240 | protected void DrawNodeBody() 241 | { 242 | var initialColor = GUI.color; 243 | dynamicHeight = 0; 244 | m_DrawRect = new Rect(0, 0, width, height); //get node draw rect 245 | 246 | var leftX = m_DrawRect.x + 6; 247 | var bodyWidth = m_DrawRect.width - 12; 248 | 249 | m_GlowRect = new Rect(m_DrawRect.x, m_DrawRect.y, m_DrawRect.width, m_DrawRect.height - 2); 250 | dynamicHeight += 6; 251 | m_HeaderRect = new Rect(leftX, dynamicHeight, bodyWidth, s_HeaderHeight); 252 | m_HeaderIconRect = new Rect(m_HeaderRect.x + headerIconPadding * 2f, m_HeaderRect.y + headerIconPadding + 1, 253 | s_HeaderIconSize, s_HeaderIconSize); 254 | m_HeaderTitleRect = new Rect(m_HeaderIconRect.xMax + headerIconPadding * 1.5f, m_HeaderIconRect.y, 255 | m_HeaderRect.width - (s_HeaderIconSize + headerIconPadding * 5), m_HeaderIconRect.height); 256 | dynamicHeight += m_HeaderRect.height; 257 | var footerHeight = 10f; 258 | var bodyHeight = m_DrawRect.height - 32f - 2f - footerHeight - 12; 259 | m_BodyRect = new Rect(leftX, dynamicHeight, bodyWidth, bodyHeight); 260 | m_FooterRect = new Rect(leftX, m_DrawRect.height - footerHeight - 8, bodyWidth, footerHeight); 261 | m_NodeOutlineRect = new Rect(m_DrawRect.x, m_DrawRect.y, m_DrawRect.width, m_DrawRect.height - 2); 262 | 263 | GUI.color = m_NodeGlowColor; 264 | GUI.Box(m_GlowRect, GUIContent.none, nodeGlowStyle); //node glow 265 | 266 | GUI.color = m_Graph.startNodeId == node.id ? m_RootNodeHeaderAndFooterBackgroundColor:m_NodeHeaderAndFooterBackgroundColor; 267 | GUI.Box(m_HeaderRect, GUIContent.none, nodeHeader); //header background 268 | 269 | GUI.color = m_HeaderTextAndIconColor; 270 | GUI.Box(m_HeaderIconRect, GUIContent.none, GetIconStyle()); //header icon 271 | 272 | GUI.color = initialColor; 273 | GUIStyle titleStyle = Styles.GetStyle("NodeHeaderText"); 274 | GUI.Label(m_HeaderTitleRect, node.name, titleStyle /*titleStyle8*/); //header title 275 | 276 | GUI.color = m_NodeBodyColor; 277 | GUI.Box(m_BodyRect, GUIContent.none, nodeBody); //body background 278 | 279 | GUI.color = m_Graph.startNodeId == node.id ? m_RootNodeHeaderAndFooterBackgroundColor:m_NodeHeaderAndFooterBackgroundColor; 280 | GUI.Box(m_FooterRect, GUIContent.none, nodeFooter); //footer background 281 | 282 | GUI.color = m_NodeOutlineColor; 283 | GUI.Box(m_NodeOutlineRect, GUIContent.none, nodeOutline); //node outline 284 | 285 | GUI.color = initialColor; //reset colors 286 | } 287 | 288 | protected void DrawNodePorts() 289 | { 290 | DrawPortsList(node.inputPorts); 291 | var inspectorArea = new Rect(20, dynamicHeight + 5, width - 40, height); 292 | GUILayout.BeginArea(inspectorArea); 293 | dynamicHeight += DrawInspector(); 294 | GUILayout.EndArea(); 295 | dynamicHeight += 5; 296 | DrawPortsList(node.outputPorts); 297 | } 298 | 299 | protected void DrawPortsList(List ports) 300 | { 301 | if (ports == null) return; 302 | foreach (Port port in ports) 303 | { 304 | //Update HEIGHT 305 | dynamicHeight += DrawPort(port).height; 306 | } 307 | } 308 | 309 | protected void UpdateNodeWidth(float width) 310 | { 311 | m_Node.SetWidth(width); 312 | } 313 | 314 | protected void UpdateNodeHeight(float height) 315 | { 316 | m_Node.SetHeight(height); 317 | } 318 | 319 | protected void UpdateNodePosition(Vector2 position) 320 | { 321 | m_Node.SetPosition(position); 322 | } 323 | 324 | #endregion 325 | 326 | #region Public Methods 327 | 328 | public void DrawNodeGUI(Rect graphArea, Vector2 panOffset, float zoomLevel) 329 | { 330 | m_Offset = panOffset; 331 | Vector2 windowToGridPosition = m_Node.GetPosition() + m_Offset / zoomLevel; 332 | var clientRect = new Rect(windowToGridPosition, m_Node.GetSize()); 333 | GUI.Window(m_WindowId, clientRect, DrawNode, string.Empty, nodeArea); 334 | } 335 | 336 | public virtual float DrawInspector(bool isDetails = false) 337 | { 338 | return DrawObjectInspector(node, isDetails); 339 | } 340 | 341 | #endregion 342 | 343 | #region Private Methods 344 | 345 | private void UpdateColors() 346 | { 347 | m_NodeGlowColor = UColor.GetColor().nodeGlowColor; 348 | m_NodeBodyColor = UColor.GetColor().nodeBodyColor; 349 | 350 | m_HeaderTextAndIconColor = UColor.GetColor().nodeHeaderIconColor; 351 | if (node.GetHasErrors()) 352 | { 353 | m_HeaderTextAndIconColor = Color.red; 354 | } 355 | 356 | m_NodeOutlineColor = UColor.GetColor().nodeOutlineColor; 357 | m_NodeOutlineColor.a = GUI.color.a * (isSelected ? 1 : node.isHovered ? 0.4f : 0); 358 | m_NodeHeaderAndFooterBackgroundColor = UColor.GetColor().nodeHeaderAndFooterBackgroundColor; 359 | m_RootNodeHeaderAndFooterBackgroundColor = UColor.GetColor().nodeRootHeaderAndFooterBackgroundColor; 360 | //NODE SELECETD COLOR 361 | if (EditorApplication.isPlaying) 362 | { 363 | if (node.ping) 364 | { 365 | m_NodeOutlineColor = UColor.GetColor().nodePlayingOutlineColor; 366 | } 367 | } 368 | else if (node.ping) 369 | { 370 | node.ping = false; 371 | } 372 | } 373 | 374 | private void DrawNode(int id) 375 | { 376 | var color = GUI.color; 377 | UpdateColors(); 378 | OnNodeGUI(); 379 | GUI.color = color; 380 | dynamicHeight += m_FooterRect.height + 6 + 2; 381 | UpdateNodeHeight(dynamicHeight); 382 | } 383 | 384 | private void OnDeletePort(Port port) 385 | { 386 | m_graphWindow.DisconnectPort(port); 387 | } 388 | 389 | #endregion 390 | 391 | } 392 | 393 | public abstract class NodeView : NodeView where T : NodeBase 394 | { 395 | public T node => base.node as T; 396 | } 397 | } -------------------------------------------------------------------------------- /Editor/NodeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8fdb86a6483146188a515b76b2df8054 3 | timeCreated: 1623033482 -------------------------------------------------------------------------------- /Editor/Tool.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b06523df268d46c89eeb8b0f23024dac 3 | timeCreated: 1623034539 -------------------------------------------------------------------------------- /Editor/Tool/ColorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.InteropServices; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace DaGenGraph.Editor 9 | { 10 | public static class ColorExtensions 11 | { 12 | public static Color WithAlpha(this Color color, float alpha) 13 | { 14 | return new Color(color.r, color.g, color.b, alpha); 15 | } 16 | public static Color ColorFrom256(this Color color, float r, float g, float b, float a = 255) 17 | { 18 | return new Color(r / 255f, g / 255f, b / 255f, a / 255f); 19 | } 20 | public static Color Lighter(this Color color) 21 | { 22 | return new Color(color.r + 0.0625f,color.g + 0.0625f,color.b + 0.0625f,color.a); 23 | } 24 | public static Color Darker(this Color color) 25 | { 26 | return new Color(color.r - 0.0625f,color.g - 0.0625f,color.b - 0.0625f,color.a); 27 | } 28 | public static Color FromHex(this Color color, string hexValue, float alpha = 1) 29 | { 30 | if (string.IsNullOrEmpty(hexValue)) return Color.clear; 31 | 32 | if (hexValue[0] == '#') hexValue = hexValue.TrimStart('#'); 33 | if (hexValue.Length > 6) hexValue = hexValue.Remove(6, hexValue.Length - 6); 34 | 35 | var value = int.Parse(hexValue, (System.Globalization.NumberStyles) NumberStyles.HexNumber); 36 | var r = value >> 16 & 255; 37 | var g = value >> 8 & 255; 38 | var b = value & 255; 39 | var a = 255 * alpha; 40 | return new Color().ColorFrom256(r, g, b, a); 41 | } 42 | [Flags] 43 | [ComVisible(true)] 44 | [Serializable] 45 | public enum NumberStyles 46 | { 47 | None = 0, 48 | AllowLeadingWhite = 1, 49 | AllowTrailingWhite = 2, 50 | AllowLeadingSign = 4, 51 | AllowTrailingSign = 8, 52 | AllowParentheses = 16, // 0x00000010 53 | AllowDecimalPoint = 32, // 0x00000020 54 | AllowThousands = 64, // 0x00000040 55 | AllowExponent = 128, // 0x00000080 56 | AllowCurrencySymbol = 256, // 0x00000100 57 | AllowHexSpecifier = 512, // 0x00000200 58 | Integer = AllowLeadingSign | AllowTrailingWhite | AllowLeadingWhite, // 0x00000007 59 | HexNumber = AllowHexSpecifier | AllowTrailingWhite | AllowLeadingWhite, // 0x00000203 60 | Number = Integer | AllowThousands | AllowDecimalPoint | AllowTrailingSign, // 0x0000006F 61 | Float = Integer | AllowExponent | AllowDecimalPoint, // 0x000000A7 62 | Currency = Number | AllowCurrencySymbol | AllowParentheses, // 0x0000017F 63 | Any = Currency | AllowExponent, // 0x000001FF 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /Editor/Tool/ColorExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1138513f102c2b247a9fdec283c60539 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Tool/Styles.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace DaGenGraph.Editor 6 | { 7 | public class Styles 8 | { 9 | private static readonly string DarkSkinPath = "Packages/com.lifang.dagen/Style/DarkSkin.guiskin"; 10 | 11 | private static GUISkin s_darkSkin; 12 | 13 | private static GUISkin DarkSkin => 14 | s_darkSkin == null ? 15 | (s_darkSkin = AssetDatabase.LoadAssetAtPath(DarkSkinPath)) 16 | : s_darkSkin; 17 | 18 | 19 | private static Dictionary s_darkStyles; 20 | 21 | private static Dictionary DarkStyles 22 | { 23 | get { return s_darkStyles ?? (s_darkStyles = new Dictionary()); } 24 | } 25 | 26 | public static GUIStyle GetStyle(string styleName) 27 | { 28 | if (DarkStyles.ContainsKey(styleName)) return DarkStyles[styleName]; 29 | var newDarkStyle = DarkSkin.GetStyle(styleName); 30 | if (newDarkStyle != null) DarkStyles.Add(styleName, newDarkStyle); 31 | return new GUIStyle(newDarkStyle); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Editor/Tool/Styles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9db978ce4acd47b6bd5e8d8f08593045 3 | timeCreated: 1621936952 -------------------------------------------------------------------------------- /Editor/Tool/UIColor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace DaGenGraph.Editor 5 | { 6 | [CreateAssetMenu(fileName = "UIColor", menuName = "DaGenGraph/UIColor", order = 0)] 7 | public class UIColor : ScriptableObject 8 | { 9 | [Tooltip("Node的边缘光颜色")] public Color nodeGlowColor; 10 | [Tooltip("Node的页眉和页脚背景颜色")] public Color nodeHeaderAndFooterBackgroundColor; 11 | [Tooltip("起始Node的页眉和页脚背景颜色")] public Color nodeRootHeaderAndFooterBackgroundColor; 12 | [Tooltip("Node的主体颜色")] public Color nodeBodyColor; 13 | [Tooltip("Node的选中框颜色")] public Color nodeOutlineColor; 14 | [Tooltip("Node的运行状态下选中框的颜色")] public Color nodePlayingOutlineColor; 15 | [Tooltip("Node的Icon颜色")] public Color nodeHeaderIconColor; 16 | [Tooltip("Node的分割线颜色")] public Color nodeDividerColor; 17 | [Tooltip("InputPort的颜色")] public Color portInputColor; 18 | [Tooltip("OutputPort的颜色")] public Color portOutputColor; 19 | [Tooltip("InputEdge被选中的颜色")] public Color edgeInputColor; 20 | [Tooltip("OutputEdge被选中的颜色")] public Color edgeOutputColor; 21 | [Tooltip("Edge正常的颜色")] public Color edgeNormalColor; 22 | } 23 | 24 | public class UColor 25 | { 26 | private static UIColor s_UIColor; 27 | 28 | private static UIColor uiColor 29 | { 30 | get 31 | { 32 | if (s_UIColor == null) 33 | { 34 | s_UIColor = AssetDatabase.LoadAssetAtPath("Packages/com.lifang.dagen/Style/UIColor.asset"); 35 | } 36 | 37 | return s_UIColor; 38 | } 39 | } 40 | 41 | public static UIColor GetColor() 42 | { 43 | return uiColor; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Editor/Tool/UIColor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d62153adfe14b47838b7e9be2b9ab2b 3 | timeCreated: 1625450541 -------------------------------------------------------------------------------- /Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb37d781f8ea4539b09e4e14de4ab4a4 3 | timeCreated: 1736996880 -------------------------------------------------------------------------------- /Example/DaGenGraph.Example.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DaGenGraph.Example", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:82c60e129e644f1a875828179b3e9c80", 6 | "GUID:b637e77054d21444096d4d4e5637ed30" 7 | ], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /Example/DaGenGraph.Example.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2fbbf606bcf587849ba86e94fdf333e4 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example/ExampleGraph.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace DaGenGraph.Example 4 | { 5 | public class ExampleGraph: GraphBase 6 | { 7 | 8 | } 9 | } -------------------------------------------------------------------------------- /Example/ExampleGraph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d68e754e6a434fc0b8d21577b44e01ac 3 | timeCreated: 1736998217 -------------------------------------------------------------------------------- /Example/ExampleGraphWindow.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using DaGenGraph.Editor; 4 | using UnityEditor; 5 | using UnityEditor.Callbacks; 6 | using UnityEngine; 7 | 8 | namespace DaGenGraph.Example 9 | { 10 | public class ExampleGraphWindow: GraphWindow 11 | { 12 | private string path; 13 | internal static ExampleGraphWindow instance 14 | { 15 | get 16 | { 17 | if (s_Instance != null) return s_Instance; 18 | var windows = Resources.FindObjectsOfTypeAll(); 19 | s_Instance = windows.Length > 0 ? windows[0] : null; 20 | if (s_Instance != null) return s_Instance; 21 | s_Instance = CreateWindow(); 22 | return s_Instance; 23 | } 24 | } 25 | 26 | private static ExampleGraphWindow s_Instance; 27 | 28 | [MenuItem("DaGenGraph/ExampleGraphWindow")] 29 | public static void GetWindow() 30 | { 31 | instance.titleContent = new GUIContent("ExampleGraphWindow"); 32 | instance.Show(); 33 | instance.InitGraph(); 34 | } 35 | [OnOpenAsset(0)] 36 | public static bool OnBaseDataOpened(int instanceID, int line) 37 | { 38 | var data = EditorUtility.InstanceIDToObject(instanceID) as ExampleGraph; 39 | if (data != null) 40 | { 41 | var path = AssetDatabase.GetAssetPath(data); 42 | instance.Show(); 43 | instance.path = path; 44 | instance.SetGraph(data); 45 | } 46 | return data != null; 47 | } 48 | protected override void InitGraph() 49 | { 50 | path = null; 51 | base.InitGraph(); 52 | } 53 | 54 | protected override ExampleGraph CreateGraph() 55 | { 56 | return CreateInstance(); 57 | } 58 | 59 | protected override ExampleGraph LoadGraph() 60 | { 61 | string searchPath = EditorUtility.OpenFilePanel($"新建{nameof(ExampleGraph)}配置文件", "Assets", "asset"); 62 | if (!string.IsNullOrEmpty(searchPath)) 63 | { 64 | searchPath = "Assets/"+searchPath.Split("/Assets/")[1]; 65 | var obj = AssetDatabase.LoadAssetAtPath(searchPath); 66 | if (obj == null) return null; 67 | path = searchPath; 68 | return obj; 69 | } 70 | return null; 71 | } 72 | 73 | protected override void SaveGraph() 74 | { 75 | if (string.IsNullOrEmpty(path)) 76 | { 77 | string searchPath = EditorUtility.SaveFilePanel($"新建{nameof(ExampleGraph)}配置文件", "Assets", 78 | nameof(ExampleGraph), "asset"); 79 | if (string.IsNullOrEmpty(searchPath)) return; 80 | 81 | path = "Assets/"+searchPath.Split("/Assets/")[1]; 82 | AssetDatabase.CreateAsset(m_Graph,path); 83 | } 84 | else 85 | { 86 | EditorUtility.SetDirty(m_Graph); 87 | } 88 | AssetDatabase.SaveAssets(); 89 | AssetDatabase.Refresh(); 90 | } 91 | 92 | protected override void AddGraphMenuItems(GenericMenu menu) 93 | { 94 | var current = Event.current; 95 | base.AddGraphMenuItems(menu); 96 | menu.AddItem(new GUIContent("New/Node"), false, () => 97 | { 98 | if (m_Graph == null) 99 | { 100 | InitGraph(); 101 | } 102 | if (string.IsNullOrEmpty(path)) 103 | { 104 | string searchPath = EditorUtility.SaveFilePanel($"新建{nameof(ExampleGraph)}配置文件", "Assets", 105 | nameof(ExampleGraph), "asset"); 106 | if (string.IsNullOrEmpty(searchPath)) return ; 107 | 108 | path = "Assets/"+searchPath.Split("/Assets/")[1]; 109 | AssetDatabase.CreateAsset(m_Graph,path); 110 | AssetDatabase.SaveAssets(); 111 | AssetDatabase.Refresh(); 112 | } 113 | CreateNodeView(m_Graph.CreateNode(current.mousePosition)); 114 | }); 115 | } 116 | 117 | protected override void AddNodeMenuItems(GenericMenu menu, NodeBase nodeBase) 118 | { 119 | base.AddNodeMenuItems(menu, nodeBase); 120 | menu.AddItem(new GUIContent("AddInputPort"), false, 121 | () => { nodeBase.AddInputPort("InputName", EdgeMode.Multiple, true, true); }); 122 | menu.AddItem(new GUIContent("AddOutputPort"), false, 123 | () => { nodeBase.AddOutputPort("OutputName", EdgeMode.Multiple, true, true); }); 124 | } 125 | 126 | protected override void AddPortMenuItems(GenericMenu menu, Port port, bool isLine = false) 127 | { 128 | base.AddPortMenuItems(menu, port, isLine); 129 | if(!isLine) 130 | menu.AddItem(new GUIContent("Delete"), false, () => { RemovePort(port); }); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Example/ExampleGraphWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 752f5a2d02c24b7f90837f158fb38a93 3 | timeCreated: 1736996916 -------------------------------------------------------------------------------- /Example/ExampleNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | #if ODIN_INSPECTOR 5 | using Sirenix.OdinInspector; 6 | #endif 7 | using UnityEngine; 8 | 9 | namespace DaGenGraph.Example 10 | { 11 | [Serializable] 12 | public class TestClass 13 | { 14 | public string TestClassText; 15 | } 16 | [NodeViewType(typeof(ExampleNodeView))] 17 | public class ExampleNode: NodeBase 18 | { 19 | public string Text; 20 | [Min(10)] 21 | public int Number; 22 | 23 | [Min(10)][ValueDropdown("@Error(123)")] 24 | public int NumberValueDropdown; 25 | [DrawIgnore(Ignore.NodeView)] 26 | public Vector4 Vector4; 27 | 28 | [ReadOnly] 29 | public Ignore Ignore; 30 | 31 | [Range(-20,20)] 32 | public float Range; 33 | 34 | [Tooltip("测试Tooltip")] 35 | public Color Color; 36 | 37 | [ReadOnly] 38 | public TestClass TestClass; 39 | 40 | public int[] IntArray; 41 | public List RectList; 42 | public List TestClasses; 43 | 44 | //详情面板选择有bug 45 | [NonSerialized][OnValueChanged(nameof(SetPath))][BoxGroup("Group")] 46 | public GameObject GameObject; 47 | 48 | public void SetPath() 49 | { 50 | if (GameObject == null) Path = null; 51 | var path = AssetDatabase.GetAssetPath(GameObject); 52 | if (path.StartsWith("Assets/AssetsPackage/")) 53 | { 54 | Path = path.Replace("Assets/AssetsPackage/",""); 55 | } 56 | else 57 | { 58 | Path = null; 59 | } 60 | } 61 | [BoxGroup("Group")][Button("ButtonTest")] 62 | public void Preview() 63 | { 64 | if (string.IsNullOrEmpty(Path)) return; 65 | if (!Path.StartsWith("Assets/AssetsPackage/")) 66 | GameObject = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/AssetsPackage/" +Path); 67 | else 68 | GameObject = UnityEditor.AssetDatabase.LoadAssetAtPath(Path); 69 | 70 | } 71 | [ReadOnly] [BoxGroup("Group")] 72 | public string Path; 73 | 74 | [NonSerialized] 75 | public Sprite Sprite; 76 | 77 | public AnimationCurve AnimationCurve; 78 | [Space(15)][PropertyOrder] 79 | public Rect Rect; 80 | [NotAssets][Header("Header")][InfoBox("注意:除数不能为0")] 81 | public NodeBase NodeBase; 82 | 83 | public Dictionary TestClassDic; 84 | public override void AddDefaultPorts() 85 | { 86 | AddOutputPort("DefaultOutputName", EdgeMode.Multiple, true, true); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Example/ExampleNode.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89cbec8b868f400ea8556d2253b0ebd9 3 | timeCreated: 1737095529 -------------------------------------------------------------------------------- /Example/ExampleNodeView.cs: -------------------------------------------------------------------------------- 1 | using DaGenGraph.Editor; 2 | 3 | namespace DaGenGraph.Example 4 | { 5 | public class ExampleNodeView : NodeView 6 | { 7 | public override float DrawInspector(bool isDetails = false) 8 | { 9 | return base.DrawInspector(isDetails); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Example/ExampleNodeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ad4f30b38bb4d988cfadd0398bf3bd4 3 | timeCreated: 1737101823 -------------------------------------------------------------------------------- /GraphBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | namespace DaGenGraph 7 | { 8 | [Serializable] 9 | public abstract class GraphBase: ScriptableObject 10 | { 11 | [HideInInspector] 12 | public Vector2 currentPanOffset = Vector2.zero; 13 | [HideInInspector] 14 | public float currentZoom = 1f; 15 | [HideInInspector] 16 | public int windowID; 17 | [HideInInspector] 18 | public string startNodeId; 19 | [HideInInspector] 20 | public bool leftInRightOut; 21 | [HideInInspector] 22 | public List values = new(); 23 | [HideInInspector] 24 | public List edges = new(); 25 | protected virtual T CreateNodeBase() where T: NodeBase 26 | { 27 | var node = CreateInstance() ; 28 | node.name = "Node"; 29 | #if UNITY_EDITOR 30 | try 31 | { 32 | UnityEditor.AssetDatabase.AddObjectToAsset(node, this); 33 | } 34 | catch (Exception ex) 35 | { 36 | Debug.LogError(ex); 37 | return null; 38 | } 39 | #endif 40 | return node; 41 | } 42 | 43 | protected virtual void DeleteNodeBase(T nodeBase) where T: NodeBase 44 | { 45 | DestroyImmediate(nodeBase,true); 46 | } 47 | 48 | public NodeBase GetStartNode() 49 | { 50 | return FindNode(startNodeId); 51 | } 52 | 53 | public NodeBase FindNode(string nodeId) 54 | { 55 | if (!string.IsNullOrEmpty(nodeId)) 56 | { 57 | for (int i = 0; i < values.Count; i++) 58 | { 59 | if (values[i].id == nodeId) 60 | { 61 | return values[i]; 62 | } 63 | } 64 | } 65 | 66 | return null; 67 | } 68 | 69 | public T CreateNode(Vector2 pos, string nodeName = "Node", bool isRoot = false) where T: NodeBase 70 | { 71 | var node = CreateNodeBase(); 72 | node.InitNode(WorldToGridPosition(pos), nodeName); 73 | values.Add(node); 74 | if ((isRoot || string.IsNullOrEmpty(startNodeId)) && values.Count>0) 75 | { 76 | startNodeId = values.First().id; 77 | } 78 | node.AddDefaultPorts(); 79 | return node; 80 | } 81 | 82 | public void RemoveNode(string nodeId) 83 | { 84 | if (!string.IsNullOrEmpty(nodeId)) 85 | { 86 | for (int i = 0; i < values.Count; i++) 87 | { 88 | if (values[i].id == nodeId) 89 | { 90 | DeleteNodeBase(values[i]); 91 | values.RemoveAt(i); 92 | break; 93 | } 94 | } 95 | } 96 | } 97 | 98 | public Vector2 WorldToGridPosition(Vector2 worldPosition) 99 | { 100 | return (worldPosition - currentPanOffset) / currentZoom; 101 | } 102 | 103 | public Edge GetEdge(string edgeId) 104 | { 105 | for (int i = 0; i < edges.Count; i++) 106 | { 107 | if (edges[i].id == edgeId) 108 | { 109 | return edges[i]; 110 | } 111 | } 112 | return null; 113 | } 114 | 115 | public Edge CreateEdge(Port outputPort, Port inputPort) 116 | { 117 | var edge = CreateEdgeBase(); 118 | edge.Init(outputPort, inputPort); 119 | edges.Add(edge); 120 | outputPort.edges.Add(edge.id); 121 | inputPort.edges.Add(edge.id); 122 | return edge; 123 | } 124 | 125 | public void RemoveEdge(string edgeId) 126 | { 127 | if (!string.IsNullOrEmpty(edgeId)) 128 | { 129 | for (int i = 0; i < edges.Count; i++) 130 | { 131 | if (edges[i].id == edgeId) 132 | { 133 | var edge = edges[i]; 134 | edges.RemoveAt(i); 135 | DestroyImmediate(edge, true); 136 | break; 137 | } 138 | } 139 | } 140 | 141 | } 142 | 143 | protected virtual Edge CreateEdgeBase() 144 | { 145 | var edge = CreateInstance() ; 146 | edge.name = "Edge"; 147 | #if UNITY_EDITOR 148 | try 149 | { 150 | UnityEditor.AssetDatabase.AddObjectToAsset(edge, this); 151 | } 152 | catch (Exception ex) 153 | { 154 | Debug.LogError(ex); 155 | return null; 156 | } 157 | #endif 158 | return edge; 159 | } 160 | 161 | protected virtual void RemoveEdgeBase(Edge edge) 162 | { 163 | DestroyImmediate(edge,true); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /GraphBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f68572d430994f109868d8323a74d065 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /JsonGraphBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DaGenGraph 4 | { 5 | public abstract class JsonGraphBase: GraphBase 6 | { 7 | protected override T CreateNodeBase() 8 | { 9 | var node = Activator.CreateInstance() ; 10 | node.name = "Node"; 11 | return node; 12 | } 13 | 14 | protected override void DeleteNodeBase(T nodeBase) 15 | { 16 | 17 | } 18 | 19 | protected override Edge CreateEdgeBase() 20 | { 21 | var edge = Activator.CreateInstance() ; 22 | edge.name = "Edge"; 23 | return edge; 24 | } 25 | 26 | protected override void RemoveEdgeBase(Edge edge) 27 | { 28 | 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /JsonGraphBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a017f59f3d24e86849d851b82e8eea5 3 | timeCreated: 1737339544 -------------------------------------------------------------------------------- /JsonNodeBase.cs: -------------------------------------------------------------------------------- 1 | namespace DaGenGraph 2 | { 3 | public abstract class JsonNodeBase:NodeBase 4 | { 5 | protected override Port CreatePortBase() 6 | { 7 | var node = CreateInstance(); 8 | node.name = "Port"; 9 | return node; 10 | } 11 | 12 | protected override void DeletePortBase(Port port) 13 | { 14 | 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /JsonNodeBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72cb48469c7c4c3a81b4288b0390b6c3 3 | timeCreated: 1737339449 -------------------------------------------------------------------------------- /NodeBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | namespace DaGenGraph 7 | { 8 | [Serializable] 9 | public abstract class NodeBase: ScriptableObject 10 | { 11 | #region public Variables 12 | 13 | [DrawIgnore] public List inputPorts; 14 | [DrawIgnore] public List outputPorts; 15 | [DrawIgnore] public bool allowDuplicateNodeName; 16 | [DrawIgnore] public bool allowEmptyNodeName; 17 | [DrawIgnore] public bool canBeDeleted; 18 | [DrawIgnore] public float height; 19 | [DrawIgnore] public float width; 20 | [DrawIgnore] public float x; 21 | [DrawIgnore] public float y; 22 | [DrawIgnore] public int minimumInputPortsCount; 23 | [DrawIgnore] public int minimumOutputPortsCount; 24 | [DrawIgnore] public string id; 25 | [DrawIgnore] public bool isHovered; 26 | [DrawIgnore] public bool errorNodeNameIsEmpty; 27 | [DrawIgnore] public bool errorDuplicateNameFoundInGraph; 28 | 29 | /// Trigger a visual cue for this node, in the Editor, at runtime. Mostly used when this node has been activated 30 | [DrawIgnore] public bool ping; 31 | 32 | public event DeletePortDelegate onDeletePort; 33 | 34 | public delegate void DeletePortDelegate(Port port); 35 | 36 | #endregion 37 | 38 | #region Editor 39 | 40 | public virtual bool GetHasErrors() => errorNodeNameIsEmpty || errorDuplicateNameFoundInGraph; 41 | 42 | 43 | /// Returns the first input port. If there isn't one, it returns null 44 | public Port GetFirstInputPort() => inputPorts.Count > 0 ? inputPorts[0] : null; 45 | 46 | /// Returns the first output port. If there isn't one, it returns null 47 | public Port GetFirstOutputPort() => outputPorts.Count > 0 ? outputPorts[0] : null; 48 | 49 | 50 | private void CheckThatNodeNameIsNotEmpty() 51 | { 52 | #if UNITY_EDITOR 53 | errorNodeNameIsEmpty = false; 54 | if (allowEmptyNodeName) return; 55 | errorNodeNameIsEmpty = string.IsNullOrEmpty(name.Trim()); 56 | #endif 57 | } 58 | 59 | /// 60 | /// Checks if this node has any errors. Because each type of node can have different errors, this method is used to define said custom errors and reflect that in the NodeGraph (for the NodeGUI) and in the Inspector (for 61 | /// the NodeEditor) 62 | /// 63 | public virtual void CheckForErrors() 64 | { 65 | #if UNITY_EDITOR 66 | CheckThatNodeNameIsNotEmpty(); 67 | #endif 68 | } 69 | 70 | #endregion 71 | 72 | #region Protected Methods 73 | 74 | 75 | /// Set to allow this node to have an empty node name 76 | /// Disable error for empty node name 77 | protected void SetAllowEmptyNodeName(bool value) 78 | { 79 | allowEmptyNodeName = value; 80 | } 81 | 82 | /// Set to allow this node to have a duplicate node name 83 | /// Disable error for duplicate node name 84 | protected void SetAllowDuplicateNodeName(bool value) 85 | { 86 | allowDuplicateNodeName = value; 87 | } 88 | 89 | #endregion 90 | 91 | #region Public Methods 92 | 93 | /// Returns the x coordinate of this node 94 | public float GetX() 95 | { 96 | return x; 97 | } 98 | 99 | /// Returns the y coordinate of this node 100 | public float GetY() 101 | { 102 | return y; 103 | } 104 | 105 | /// Returns the width of this node 106 | public float GetWidth() 107 | { 108 | return width; 109 | } 110 | 111 | /// Returns the height of this node 112 | public float GetHeight() 113 | { 114 | return height; 115 | } 116 | 117 | /// Returns the position of this node 118 | public Vector2 GetPosition() 119 | { 120 | return new Vector2(x, y); 121 | } 122 | 123 | /// Returns the size of this node (x is width, y is height) 124 | public Vector2 GetSize() 125 | { 126 | return new Vector2(GetWidth(), height); 127 | } 128 | 129 | /// Returns the Rect of this node 130 | public Rect GetRect() 131 | { 132 | return new Rect(x, y, GetWidth(), height); 133 | } 134 | 135 | public Rect GetFooterRect() 136 | { 137 | return new Rect(GetX() + 6, GetY() - 6 + GetHeight() - 10, GetWidth() - 12, 10); 138 | } 139 | 140 | /// Returns the Rect of this node's header 141 | public Rect GetHeaderRect() 142 | { 143 | return new Rect(GetX() + 6, GetY() + 6, GetWidth() - 12, 32); 144 | } 145 | 146 | /// Set the name for this node 147 | /// The new node name value 148 | public void SetName(string value) 149 | { 150 | name = value; 151 | } 152 | 153 | /// Set the position of this node's Rect 154 | /// The new position value 155 | public void SetPosition(Vector2 position) 156 | { 157 | x = position.x; 158 | y = position.y; 159 | } 160 | 161 | /// Set the position of this node's Rect 162 | /// The new x coordinate value 163 | /// The new y coordinate value 164 | public void SetPosition(float x, float y) 165 | { 166 | this.x = x; 167 | this.y = y; 168 | } 169 | 170 | /// Set the Rect values for this node 171 | /// The new rect values 172 | public void SetRect(Rect rect) 173 | { 174 | x = rect.x; 175 | y = rect.y; 176 | width = rect.width; 177 | height = rect.height; 178 | } 179 | 180 | /// Set the Rect values for this node 181 | /// The new position value 182 | /// The new size value 183 | public void SetRect(Vector2 position, Vector2 size) 184 | { 185 | x = position.x; 186 | y = position.y; 187 | width = size.x; 188 | height = size.y; 189 | } 190 | 191 | /// Set the Rect values for this node 192 | /// The new x coordinate value 193 | /// The new y coordinate value 194 | /// The new width value 195 | /// The new height value 196 | public void SetRect(float x, float y, float width, float height) 197 | { 198 | this.x = x; 199 | this.x = y; 200 | this.width = width; 201 | this.height = height; 202 | } 203 | 204 | /// Set the size of this node's Rect 205 | /// The new node size (x is width, y is height) 206 | public void SetSize(Vector2 size) 207 | { 208 | width = size.x; 209 | height = size.y; 210 | } 211 | 212 | /// Set the size of this node's Rect 213 | /// The new width value 214 | /// The new height value 215 | public void SetSize(float width, float height) 216 | { 217 | this.width = width; 218 | this.height = height; 219 | } 220 | 221 | /// Set the width of this node's Rect 222 | /// The new width value 223 | public void SetWidth(float value) 224 | { 225 | width = value; 226 | } 227 | 228 | /// Set the height of this node's Rect 229 | /// The new height value 230 | public void SetHeight(float value) 231 | { 232 | height = value; 233 | } 234 | 235 | /// Set the x coordinate of this node's Rect 236 | /// The new x value 237 | public void SetX(float value) 238 | { 239 | x = value; 240 | } 241 | 242 | /// Set the y coordinate of this node's Rect 243 | /// The new y value 244 | public void SetY(float value) 245 | { 246 | y = value; 247 | } 248 | /// Convenience method to add a new input port to this node 249 | /// The name of the port (if null or empty, it will be auto-generated) 250 | /// The port edge mode (Multiple/Override) 251 | /// The port edge points locations (if null or empty, it will automatically add two edge points to the left of and the right of the port) 252 | /// Determines if this port is a special port that cannot be deleted 253 | /// Determines if this port is a special port that cannot be reordered 254 | public Port AddInputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, EdgeType edgeType, 255 | bool canBeReordered = true) where T: Port 256 | { 257 | return AddPort(portName, PortDirection.Input, edgeMode, canBeDeleted, canBeReordered, edgeType); 258 | } 259 | /// Convenience method to add a new input port to this node 260 | /// The name of the port (if null or empty, it will be auto-generated) 261 | /// The port edge mode (Multiple/Override) 262 | /// The port edge points locations (if null or empty, it will automatically add two edge points to the left of and the right of the port) 263 | /// Determines if this port is a special port that cannot be deleted 264 | /// Determines if this port is a special port that cannot be reordered 265 | public Port AddInputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, EdgeType edgeType, 266 | bool canBeReordered = true) 267 | { 268 | return AddPort(portName, PortDirection.Input, edgeMode, canBeDeleted, canBeReordered, edgeType); 269 | } 270 | 271 | /// Convenience method to add a new input port to this node. This port will have two edge points automatically added to it and they will be to the left of and the right the port 272 | /// The name of the port (if null or empty, it will be auto-generated) 273 | /// The port edge mode (Multiple/Override) 274 | /// Determines if this port is a special port that cannot be deleted 275 | /// Determines if this port is a special port that cannot be reordered 276 | public Port AddInputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, bool canBeReordered) 277 | { 278 | return AddPort(portName, PortDirection.Input, edgeMode, canBeDeleted, 279 | canBeReordered); 280 | } 281 | 282 | /// Convenience method to add a new input port to this node. This port will have two edge points automatically added to it and they will be to the left of and the right the port 283 | /// The port edge mode (Multiple/Override) 284 | /// Determines if this port is a special port that cannot be deleted 285 | /// Determines if this port is a special port that cannot be reordered 286 | public Port AddInputPort(EdgeMode edgeMode, bool canBeDeleted, bool canBeReordered) 287 | { 288 | return AddPort("", PortDirection.Input, edgeMode, canBeDeleted, 289 | canBeReordered); 290 | } 291 | /// Convenience method to add a new output port to this node 292 | /// The name of the port (if null or empty, it will be auto-generated) 293 | /// The port edge mode (Multiple/Override) 294 | /// The port edge points locations (if null or empty, it will automatically add two edge points to the left of and the right of the port) 295 | /// Determines if this port is a special port that cannot be deleted 296 | /// Determines if this port is a special port that cannot be reordered 297 | public Port AddOutputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, EdgeType edgeType , 298 | bool canBeReordered) where T: Port 299 | { 300 | return AddPort(portName, PortDirection.Output, edgeMode, canBeDeleted, canBeReordered,edgeType); 301 | } 302 | /// Convenience method to add a new output port to this node 303 | /// The name of the port (if null or empty, it will be auto-generated) 304 | /// The port edge mode (Multiple/Override) 305 | /// The port edge points locations (if null or empty, it will automatically add two edge points to the left of and the right of the port) 306 | /// Determines if this port is a special port that cannot be deleted 307 | /// Determines if this port is a special port that cannot be reordered 308 | public Port AddOutputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, EdgeType edgeType , 309 | bool canBeReordered) 310 | { 311 | return AddPort(portName, PortDirection.Output, edgeMode, canBeDeleted, canBeReordered,edgeType); 312 | } 313 | 314 | /// Convenience method to add a new output port to this node. This port will have two edge points automatically added to it and they will be to the left of and the right the port 315 | /// The name of the port (if null or empty, it will be auto-generated) 316 | /// The port edge mode (Multiple/Override) 317 | /// Determines if this port is a special port that cannot be deleted 318 | /// Determines if this port is a special port that cannot be reordered 319 | public Port AddOutputPort(string portName, EdgeMode edgeMode, bool canBeDeleted, bool canBeReordered) 320 | { 321 | return AddPort(portName, PortDirection.Output, edgeMode, canBeDeleted, canBeReordered); 322 | } 323 | 324 | /// Convenience method to add a new output port to this node. This port will have two edge points automatically added to it and they will be to the left of and the right the port 325 | /// The port edge mode (Multiple/Override) 326 | /// Determines if this port is a special port that cannot be deleted 327 | /// Determines if this port is a special port that cannot be reordered 328 | public Port AddOutputPort(EdgeMode edgeMode, bool canBeDeleted, bool canBeReordered) 329 | { 330 | return AddPort("", PortDirection.Output, edgeMode, canBeDeleted, canBeReordered); 331 | } 332 | 333 | /// Returns TRUE if the target port can be deleted, after checking is it is marked as 'deletable' and that by deleting it the node minimum ports count does not go below the set threshold 334 | /// Target port 335 | public bool CanDeletePort(Port port) 336 | { 337 | //if port is market as cannot be deleted -> return false -> do not allow the dev to delete this port 338 | if (!port.canBeDeleted) return false; 339 | //if port is input -> make sure the node has a minimum input ports count before allowing deletion 340 | if (port.IsInput()) return inputPorts.Count > minimumInputPortsCount; 341 | //if port is output -> make sure the node has a minimum output ports count before allowing deletion 342 | if (port.IsOutput()) return outputPorts.Count > minimumOutputPortsCount; 343 | //event though the port can be deleted -> the node needs to hold a minimum number of ports and will not allow to delete this port 344 | return false; 345 | } 346 | 347 | /// Returns TRUE if a edge with the given id can be found on one of this node's ports 348 | /// Target edge id 349 | public bool ContainsEdge(string edgeId) 350 | { 351 | foreach (var port in inputPorts) 352 | { 353 | if (port.edges.Contains(edgeId)) return true; 354 | } 355 | 356 | foreach (var port in outputPorts) 357 | { 358 | if (port.edges.Contains(edgeId)) return true; 359 | } 360 | return false; 361 | } 362 | 363 | /// 364 | /// 365 | /// 366 | /// 367 | public void DeletePort(Port port) 368 | { 369 | if (port.IsInput()) inputPorts.Remove(port); 370 | if (port.IsOutput()) outputPorts.Remove(port); 371 | onDeletePort?.Invoke(port); 372 | DeletePortBase(port); 373 | } 374 | #endregion 375 | 376 | #region Private Methods 377 | 378 | /// Adds a port to this node 379 | /// The name of the port (if null or empty, it will be auto-generated) 380 | /// The port direction (Input/Output) 381 | /// The port edge mode (Multiple/Override) 382 | /// The port edge points locations (if null or empty, it will automatically add two edge points to the left of and the right of the port) 383 | /// Determines if this port is a special port that cannot be deleted 384 | /// Determines if this port is a special port that cannot be reordered 385 | private Port AddPort(string portName, PortDirection direction, EdgeMode edgeMode, 386 | bool canBeDeleted, bool canBeReordered , EdgeType edgeType = EdgeType.Both)where T:Port 387 | { 388 | string baseName = portName; 389 | var portNames = new List(); 390 | int counter = 1; 391 | switch (direction) 392 | { 393 | case PortDirection.Input: 394 | foreach (Port port in inputPorts) 395 | portNames.Add(port.portName); 396 | if (string.IsNullOrEmpty(baseName)) 397 | { 398 | baseName = "InputPort_"; 399 | portName = baseName + counter++; 400 | } 401 | 402 | while (portNames.Contains(portName)) 403 | { 404 | portName = baseName + counter++; 405 | } 406 | 407 | var inputPort = CreatePortBase(); 408 | inputPort.Init(this, portName, direction, edgeMode, edgeType, canBeDeleted, canBeReordered); 409 | inputPorts.Add(inputPort); 410 | return inputPort; 411 | case PortDirection.Output: 412 | foreach (Port port in outputPorts) 413 | portNames.Add(port.portName); 414 | if (string.IsNullOrEmpty(baseName)) 415 | { 416 | baseName = "OutputPort_"; 417 | portName = baseName + counter++; 418 | } 419 | 420 | while (portNames.Contains(portName)) 421 | { 422 | portName = baseName + counter++; 423 | } 424 | var outputPort = CreatePortBase(); 425 | outputPort.Init(this, portName, direction, edgeMode, edgeType, canBeDeleted, canBeReordered); 426 | outputPorts.Add(outputPort); 427 | return outputPort; 428 | default: 429 | throw new ArgumentOutOfRangeException(nameof(direction), direction, null); 430 | } 431 | } 432 | 433 | /// Generates a new unique node id for this node and returns the newly generated id value 434 | private void GenerateNewId() 435 | { 436 | id = Guid.NewGuid().ToString(); 437 | } 438 | 439 | #endregion 440 | 441 | #region Public virtual Methods 442 | 443 | protected virtual Port CreatePortBase() where T:Port 444 | { 445 | var port = CreateInstance(); 446 | port.name = "Port"; 447 | #if UNITY_EDITOR 448 | try 449 | { 450 | UnityEditor.AssetDatabase.AddObjectToAsset(port, this); 451 | } 452 | catch (Exception ex) 453 | { 454 | Debug.LogError(ex); 455 | return null; 456 | } 457 | #endif 458 | return port; 459 | } 460 | 461 | protected virtual void DeletePortBase(Port port) 462 | { 463 | DestroyImmediate(port,true); 464 | } 465 | 466 | /// OnEnterNode is called on the frame when this node becomes active just before any of the node's Update methods are called for the first time 467 | /// The node that was active before this one 468 | /// The edge that activated this node 469 | public virtual void OnEnter(NodeBase previousActiveNode, Edge edge) 470 | { 471 | ping = true; 472 | } 473 | 474 | /// OnExitNode is called just before this node becomes inactive 475 | /// The node that will become active next 476 | /// The edge that activates the next node 477 | public virtual void OnExit(NodeBase nextActiveNode, Edge edge) 478 | { 479 | ping = false; 480 | if (edge != null) 481 | { 482 | edge.ping = true; 483 | edge.reSetTime = true; 484 | } 485 | } 486 | 487 | public virtual void InitNode(Vector2 pos, string nodeName, int minInputPortsCount = 0, int minOutputPortsCount = 0) 488 | { 489 | name = nodeName; 490 | GenerateNewId(); 491 | inputPorts = new List(); 492 | outputPorts = new List(); 493 | canBeDeleted = true; 494 | this.minimumInputPortsCount = minInputPortsCount; 495 | this.minimumOutputPortsCount = minOutputPortsCount; 496 | x = pos.x; 497 | y = pos.y; 498 | width = 260f; 499 | height = 200f; 500 | } 501 | 502 | public abstract void AddDefaultPorts(); 503 | 504 | #endregion 505 | } 506 | } -------------------------------------------------------------------------------- /NodeBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 625d46cb5a0c45ae94f424854f1741a0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Port.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | namespace DaGenGraph 7 | { 8 | public class Port: ScriptableObject 9 | { 10 | 11 | #region public Variables 12 | 13 | #if UNITY_EDITOR 14 | [NonSerialized] public UnityEditor.AnimatedValues.AnimBool showHover = new (false); 15 | #endif 16 | [NonSerialized] public Rect hoverRect; 17 | [NonSerialized] private List edgePoints; 18 | 19 | public EdgeType edgeType; 20 | public List edges; 21 | public PortDirection direction; 22 | public EdgeMode edgeMode; 23 | public bool canBeDeleted; 24 | public bool canBeReordered; 25 | public float curveModifier; 26 | public float height; 27 | public float width; 28 | public float x; 29 | public float y; 30 | public string id; 31 | public string nodeId; 32 | public string portName; 33 | 34 | #endregion 35 | 36 | #region public Methods 37 | 38 | public void Init(NodeBase node, string portName, PortDirection direction, EdgeMode edgeMode, EdgeType edgeType, bool canBeDeleted, bool canBeReordered) 39 | { 40 | GenerateNewId(); 41 | nodeId = node.id; 42 | this.portName = portName; 43 | this.direction = direction; 44 | this.edgeMode = edgeMode; 45 | this.edgeType = edgeType; 46 | this.canBeDeleted = canBeDeleted; 47 | this.canBeReordered = canBeReordered; 48 | edges = new List(); 49 | curveModifier = 0; 50 | } 51 | 52 | public List GetEdgePoints() 53 | { 54 | if (edgePoints == null) 55 | { 56 | if (edgeType == EdgeType.Both) 57 | { 58 | edgePoints = GetLeftAndRightEdgePoints(); 59 | } 60 | else if (edgeType == EdgeType.Left) 61 | { 62 | edgePoints = new List(); 63 | edgePoints.Add(GetLeftEdgePointPosition()); 64 | } 65 | else if (edgeType == EdgeType.Right) 66 | { 67 | edgePoints = new List(); 68 | edgePoints.Add(GetRightEdgePointPosition()); 69 | } 70 | } 71 | 72 | return edgePoints; 73 | } 74 | /// Returns TRUE if this port has at least one edge (it checks the Connections count) 75 | public bool IsConnected() => edges.Count > 0; 76 | 77 | /// Returns TRUE if this is an Input port 78 | public bool IsInput() => direction == PortDirection.Input; 79 | 80 | /// Returns TRUE if this is an Output port 81 | public bool IsOutput() => direction == PortDirection.Output; 82 | 83 | /// Returns TRUE if this port can establish only ONE edge 84 | public bool OverrideConnection() => edgeMode == EdgeMode.Override; 85 | /// Returns TRUE if this port can establish multiple edges 86 | public bool GetAcceptsMultipleConnections() => edgeMode == EdgeMode.Multiple; 87 | /// [Editor Only] Returns the height of this port 88 | public float GetHeight() 89 | { 90 | return height; 91 | } 92 | /// [Editor Only] Returns the position of this port 93 | public Vector2 GetPosition() 94 | { 95 | return new Vector2(x, y); 96 | } 97 | /// [Editor Only] Returns the Rect of this port 98 | public Rect GetRect() 99 | { 100 | return new Rect(x, y, width, height); 101 | } 102 | /// [Editor Only] Returns the size of this port (x is width, y is height) 103 | public Vector2 GetSize() 104 | { 105 | return new Vector2(width, height); 106 | } 107 | /// [Editor Only] Returns the width of this port 108 | public float GetWidth() 109 | { 110 | return width; 111 | } 112 | /// [Editor Only] Returns the x coordinate of this port 113 | public float GetX() 114 | { 115 | return x; 116 | } 117 | /// [Editor Only] Returns the y coordinate of this port 118 | public float GetY() 119 | { 120 | return y; 121 | } 122 | /// 123 | /// Returns the edge mode this port has (Multiple/Override) 124 | /// 125 | /// The edge mode determines if this port can establish multiple edge or just one 126 | /// 127 | public EdgeMode GetConnectionMode() 128 | { 129 | return edgeMode; 130 | } 131 | /// Returns the direction this port has (Input/Output) 132 | public PortDirection GetDirection() 133 | { 134 | return direction; 135 | } 136 | 137 | /// Returns a IEnumerable of all the Edge ids of this Port 138 | public IEnumerable GetEdgeIds() 139 | { 140 | return edges.ToList(); 141 | } 142 | 143 | /// [Editor Only] Sets the height of this port's Rect 144 | /// The new height value 145 | public void SetHeight(float value) 146 | { 147 | height = value; 148 | } 149 | /// Set the name for this port 150 | /// The new port name value 151 | public void SetName(string value) 152 | { 153 | portName = value; 154 | } 155 | /// [Editor Only] Sets the position of this port's Rect 156 | /// The new position value 157 | public void SetPosition(Vector2 position) 158 | { 159 | x = position.x; 160 | y = position.y; 161 | } 162 | /// [Editor Only] Sets the position of this port's Rect 163 | /// The new x coordinate value 164 | /// The new y coordinate value 165 | public void SetPosition(float x, float y) 166 | { 167 | this.x = x; 168 | this.y = y; 169 | } 170 | /// [Editor Only] Sets the Rect value for this port 171 | /// The new rect values 172 | public void SetRect(Rect rect) 173 | { 174 | x = rect.x; 175 | y = rect.y; 176 | width = rect.width; 177 | height = rect.height; 178 | RefreshPoints(); 179 | } 180 | /// [Editor Only] Sets the Rect values for this port 181 | /// The new position value 182 | /// The new size value 183 | public void SetRect(Vector2 position, Vector2 size) 184 | { 185 | x = position.x; 186 | y = position.y; 187 | width = size.x; 188 | height = size.y; 189 | RefreshPoints(); 190 | } 191 | /// [Editor Only] Sets the Rect values for this port 192 | /// The new x coordinate value 193 | /// The new y coordinate value 194 | /// The new width value 195 | /// The new height value 196 | public void SetRect(float x, float y, float width, float height) 197 | { 198 | this.x = x; 199 | this.x = y; 200 | this.width = width; 201 | this.height = height; 202 | RefreshPoints(); 203 | } 204 | /// [Editor Only] Sets the size of this port's Rect 205 | /// The new port size (x is width, y is height) 206 | public void SetSize(Vector2 size) 207 | { 208 | width = size.x; 209 | height = size.y; 210 | RefreshPoints(); 211 | } 212 | /// [Editor Only] Sets the size of this port's Rect 213 | /// The new width value 214 | /// The new height value 215 | public void SetSize(float width, float height) 216 | { 217 | this.width = width; 218 | this.height = height; 219 | RefreshPoints(); 220 | } 221 | /// [Editor Only] Sets the width of this port's Rect 222 | /// The new width value 223 | public void SetWidth(float value) 224 | { 225 | width = value; 226 | RefreshPoints(); 227 | } 228 | /// [Editor Only] Sets the x coordinate of this port's Rect 229 | /// The new x value 230 | public void SetX(float value) 231 | { 232 | x = value; 233 | } 234 | /// [Editor Only] Sets the y coordinate of this port's Rect 235 | /// The new y value 236 | public void SetY(float value) 237 | { 238 | y = value; 239 | } 240 | /// [Editor Only] Updates the port hover Rect. This is the 'selection' box that appears when the mouse is over the port 241 | public void UpdateHoverRect() 242 | { 243 | hoverRect = new Rect(GetRect().x + 6, 244 | GetRect().y + 2, 245 | GetRect().width - 12, 246 | GetRect().height - 3); 247 | } 248 | /// Returns TRUE if this port can connect to another port 249 | /// The other port we are trying to determine if this port can connect to 250 | /// If true, this check will not make sure that the sockets valueTypes match 251 | public virtual bool CanConnect(Port other,GraphBase graphBase, bool ignoreValueType = false) 252 | { 253 | if (other == null) return false; //check that the other port is not null 254 | if (IsConnectedToPort(other.id,graphBase))return false; //check that this port is not already connected to the other port 255 | if (id == other.id) return false; //make sure we're not trying to connect the same port 256 | if (nodeId == other.nodeId) return false; //check that we are not connecting sockets on the same baseNode 257 | if (IsInput() && other.IsInput()) return false; //check that the sockets are not both input sockets 258 | if (IsOutput() && other.IsOutput()) return false; //check that the sockets are not both output sockets 259 | if (!ignoreValueType) 260 | { 261 | var attributes1 = GetType().GetCustomAttributes(typeof(PortGroupAttribute), true); 262 | var attributes2 = other.GetType().GetCustomAttributes(typeof(PortGroupAttribute), true); 263 | if (attributes1.Length > 0 || attributes2.Length > 0) 264 | { 265 | HashSet temp = new HashSet(); 266 | foreach (PortGroupAttribute item in attributes1) 267 | { 268 | temp.Add(item.Group); 269 | } 270 | foreach (PortGroupAttribute item in attributes2) 271 | { 272 | if (temp.Contains(item.Group)) 273 | { 274 | return true; 275 | } 276 | } 277 | return false; 278 | } 279 | } 280 | return true; 281 | } 282 | 283 | /// Removes a edge with the given edge id from this Port 284 | /// The edge id we want removed from this Port 285 | public void RemoveEdge(string edgeId) 286 | { 287 | //if the connections list does not contain this connection id -> return; 288 | if (!ContainsEdge(edgeId)) return; 289 | //iterate through all the connections list 290 | for (var i = edges.Count - 1; i >= 0; i--) 291 | { 292 | //if a connection has the given connection id -> remove connection 293 | if (edges[i] == edgeId) 294 | { 295 | edges.RemoveAt(i); 296 | } 297 | } 298 | } 299 | 300 | /// Returns TRUE if this port contains a edge with the given edge id 301 | /// The edge id to search for 302 | public bool ContainsEdge(string edgeId) 303 | { 304 | return edges.Any(edge => edge == edgeId); 305 | } 306 | 307 | /// [Editor Only] Returns the closest own Edge point to the closest Edge point on the other Port 308 | public Vector2 GetClosestEdgePointToPort(Port other) 309 | { 310 | if (edgeType == EdgeType.Left) 311 | { 312 | return GetLeftEdgePointPosition(); 313 | } 314 | if (edgeType == EdgeType.Right) 315 | { 316 | return GetRightEdgePointPosition(); 317 | } 318 | 319 | var edgePoints = GetLeftAndRightEdgePoints(); 320 | //arbitrary value that will surely be greater than any other possible distance 321 | float minDistance = 100000; 322 | //set the closest point as the first connection point 323 | var closestPoint = edgePoints[0]; 324 | //iterate through this port's own connection points list 325 | foreach (var ownPoint in edgePoints) 326 | { 327 | foreach (var distance in other.GetEdgePoints().Select(otherPoint => Vector2.Distance(ownPoint, otherPoint)).Where(distance => !(distance > minDistance))) 328 | { 329 | //the distance is smaller than the current minimum distance -> update the selected connection point 330 | closestPoint =ownPoint; 331 | //update the current minimum distance 332 | minDistance = distance; 333 | } 334 | } 335 | return closestPoint; //return the closest Edge point 336 | } 337 | 338 | /// Remove ALL the Edges this Port has, by clearing the Edges list 339 | public void Disconnect() 340 | { 341 | edges.Clear(); 342 | } 343 | 344 | /// Disconnect this port from the given node id 345 | /// The node id we want this port to disconnect from 346 | public void DisconnectFromNode(string nodeId, GraphBase graphBase) 347 | { 348 | if (!IsConnected()) return; 349 | for (int i = edges.Count - 1; i >= 0; i--) 350 | { 351 | var edge = graphBase.GetEdge(edges[i]); 352 | if (IsInput() && edge.outputNodeId == nodeId) edges.RemoveAt(i); 353 | if (IsOutput() && edge.inputNodeId == nodeId) edges.RemoveAt(i); 354 | } 355 | } 356 | 357 | #endregion 358 | 359 | #region private Methods 360 | 361 | /// Returns TRUE if this port is connected to the given port id 362 | /// The port id to search for and determine if this port is connected to or not 363 | private bool IsConnectedToPort(string portId, GraphBase graphBase) 364 | { 365 | foreach (var edgeId in edges) //iterate through all the connections list 366 | { 367 | var edge = graphBase.GetEdge(edgeId); 368 | if (IsInput() && edge.outputPortId == portId)return true; //if this is an input port -> look for the port id at the output port of the connection 369 | if (IsOutput() && edge.inputPortId == portId)return true; //if this is an output port -> look for the port id at the input port of the connection 370 | } 371 | return false; 372 | } 373 | 374 | /// Generates a new unique port id for this port and returns the newly generated id value 375 | private string GenerateNewId() 376 | { 377 | id = Guid.NewGuid().ToString(); 378 | return id; 379 | } 380 | 381 | /// Returns a list of two Edge points positions to the left of and the right of the Port 382 | private List GetLeftAndRightEdgePoints() 383 | { 384 | return new List { GetLeftEdgePointPosition(), GetRightEdgePointPosition() }; 385 | } 386 | 387 | /// Returns the default left edge point position for a Port 388 | private Vector2 GetLeftEdgePointPosition() 389 | { 390 | return new Vector2(-2f, 24f / 2 - 16f / 2); 391 | } 392 | 393 | /// Returns the default right edge point position for a Port 394 | private Vector2 GetRightEdgePointPosition() 395 | { 396 | return new Vector2(GetWidth() + 2f - 16f, 24f / 2 - 16f / 2); 397 | } 398 | 399 | private void RefreshPoints() 400 | { 401 | if (edgeType == EdgeType.Right || edgeType == EdgeType.Both) 402 | { 403 | edgePoints = null; 404 | } 405 | } 406 | 407 | #endregion 408 | } 409 | public enum PortDirection 410 | { 411 | /// 412 | /// An input Socket can only connect to an output Socket 413 | /// 414 | Input, 415 | 416 | /// 417 | /// An output Socket can only connect to an input Socket 418 | /// 419 | Output 420 | } 421 | public enum EdgeMode 422 | { 423 | /// 424 | /// Socket can have only one Connection at a time (overriding any existing edge upon establishing a new edge) 425 | /// 426 | Override, 427 | 428 | /// 429 | /// Socket can have multiple edges 430 | /// 431 | Multiple 432 | } 433 | 434 | public enum EdgeType 435 | { 436 | Both, 437 | Left, 438 | Right, 439 | } 440 | } -------------------------------------------------------------------------------- /Port.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f45fe4a9053241e882561ab9bdb8808d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Style.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de0c4ae6c7c56f14ebe9a93cff8c0e6b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Style/DarkSkin.guiskin.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a18d7875d2eeed046a71750d5f627c02 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Style/UIColor.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 8d62153adfe14b47838b7e9be2b9ab2b, type: 3} 13 | m_Name: UIColor 14 | m_EditorClassIdentifier: 15 | nodeGlowColor: {r: 1, g: 1, b: 1, a: 1} 16 | nodeHeaderAndFooterBackgroundColor: {r: 0.745283, g: 0.745283, b: 0.745283, a: 1} 17 | nodeRootHeaderAndFooterBackgroundColor: {r: 0.3207547, g: 0.3207547, b: 0.3207547, a: 1} 18 | nodeBodyColor: {r: 0, g: 0.6603774, b: 0.6130958, a: 1} 19 | nodeOutlineColor: {r: 1, g: 0, b: 0.51282024, a: 1} 20 | nodePlayingOutlineColor: {r: 0, g: 1, b: 0.017543793, a: 1} 21 | nodeHeaderIconColor: {r: 1, g: 1, b: 1, a: 1} 22 | nodeDividerColor: {r: 0, g: 1, b: 0.3212328, a: 1} 23 | portInputColor: {r: 0, g: 1, b: 0.025779486, a: 1} 24 | portOutputColor: {r: 1, g: 0.058691405, b: 0, a: 1} 25 | edgeInputColor: {r: 0.25207186, g: 0, b: 1, a: 1} 26 | edgeOutputColor: {r: 1, g: 0, b: 0, a: 1} 27 | edgeNormalColor: {r: 1, g: 1, b: 1, a: 1} 28 | -------------------------------------------------------------------------------- /Style/UIColor.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db078a4c96d3fe54dbe436c8e7963fac 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Texture.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2516abda0ad71bf4ab4a561090c12637 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Texture/BackgroundRoundDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/BackgroundRoundDark.png -------------------------------------------------------------------------------- /Texture/BackgroundRoundDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0c7f8a268cfaeb45a576684ce3edaa4 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/BackgroundSquareDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/BackgroundSquareDark.png -------------------------------------------------------------------------------- /Texture/BackgroundSquareDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2a41e5dfd241744788de35afe042c13 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/ConnectionPointMinusNormalDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/ConnectionPointMinusNormalDark.png -------------------------------------------------------------------------------- /Texture/ConnectionPointMinusNormalDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce385a70de9ce4d46acde9230be7aefb 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/ConnectionPointMultipleConnectedNormalDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/ConnectionPointMultipleConnectedNormalDark.png -------------------------------------------------------------------------------- /Texture/ConnectionPointMultipleConnectedNormalDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 958dcd11d63b3e9499a5710a5d79b3d2 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/ConnectionPointMultipleEmptyNormalDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/ConnectionPointMultipleEmptyNormalDark.png -------------------------------------------------------------------------------- /Texture/ConnectionPointMultipleEmptyNormalDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6432d91a530b9fc44bb5efe4a9b9d677 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/ConnectionPointOverrideConnectedNormalDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/ConnectionPointOverrideConnectedNormalDark.png -------------------------------------------------------------------------------- /Texture/ConnectionPointOverrideConnectedNormalDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23d40362666faa3429adcc2f4da7352a 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/ConnectionPointOverrideEmptyNormalDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/ConnectionPointOverrideEmptyNormalDark.png -------------------------------------------------------------------------------- /Texture/ConnectionPointOverrideEmptyNormalDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a86dcb6588d244c45a9d133ed3aff02f 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeBodyDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeBodyDark.png -------------------------------------------------------------------------------- /Texture/NodeBodyDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02094ede464c3cb4ba9fdcee94d3ffd6 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeDotDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeDotDark.png -------------------------------------------------------------------------------- /Texture/NodeDotDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a2c2695b73307594b8d3238ae8f22b19 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeFooterDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeFooterDark.png -------------------------------------------------------------------------------- /Texture/NodeFooterDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b20417cd8c9477248949ac0e1b247203 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeGlowDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeGlowDark.png -------------------------------------------------------------------------------- /Texture/NodeGlowDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fde6953e0ea02fc43a180aea33806755 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeHeaderDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeHeaderDark.png -------------------------------------------------------------------------------- /Texture/NodeHeaderDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a789fa4c8d4b1d04ca1bb22147703bda 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /Texture/NodeOutlineDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiFang7/DaGenGraph/ee17db390decfb8b5769e8b80f034d9f97871247/Texture/NodeOutlineDark.png -------------------------------------------------------------------------------- /Texture/NodeOutlineDark.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe3572699d3d15f40b25795ea68a0cfe 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | - serializedVersion: 3 75 | buildTarget: Standalone 76 | maxTextureSize: 2048 77 | resizeAlgorithm: 0 78 | textureFormat: -1 79 | textureCompression: 1 80 | compressionQuality: 50 81 | crunchedCompression: 0 82 | allowsAlphaSplitting: 0 83 | overridden: 0 84 | androidETC2FallbackOverride: 0 85 | forceMaximumCompressionQuality_BC6H_BC7: 0 86 | - serializedVersion: 3 87 | buildTarget: iPhone 88 | maxTextureSize: 2048 89 | resizeAlgorithm: 0 90 | textureFormat: -1 91 | textureCompression: 1 92 | compressionQuality: 50 93 | crunchedCompression: 0 94 | allowsAlphaSplitting: 0 95 | overridden: 0 96 | androidETC2FallbackOverride: 0 97 | forceMaximumCompressionQuality_BC6H_BC7: 0 98 | - serializedVersion: 3 99 | buildTarget: Android 100 | maxTextureSize: 2048 101 | resizeAlgorithm: 0 102 | textureFormat: -1 103 | textureCompression: 1 104 | compressionQuality: 50 105 | crunchedCompression: 0 106 | allowsAlphaSplitting: 0 107 | overridden: 0 108 | androidETC2FallbackOverride: 0 109 | forceMaximumCompressionQuality_BC6H_BC7: 0 110 | spriteSheet: 111 | serializedVersion: 2 112 | sprites: [] 113 | outline: [] 114 | physicsShape: [] 115 | bones: [] 116 | spriteID: 117 | internalID: 0 118 | vertices: [] 119 | indices: 120 | edges: [] 121 | weights: [] 122 | secondaryTextures: [] 123 | spritePackingTag: 124 | pSDRemoveMatte: 0 125 | pSDShowRemoveMatteOption: 0 126 | userData: 127 | assetBundleName: 128 | assetBundleVariant: 129 | -------------------------------------------------------------------------------- /TypeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | #if ODIN_INSPECTOR 5 | using Sirenix.OdinInspector; 6 | #endif 7 | namespace DaGenGraph 8 | { 9 | public static class TypeHelper 10 | { 11 | /// 12 | /// Cached Models 13 | /// 14 | private static readonly Dictionary TypeCodes = new Dictionary(30) 15 | { 16 | {typeof(byte).FullName, typeof(byte)}, 17 | {typeof(sbyte).FullName, typeof(sbyte)}, 18 | {typeof(short).FullName, typeof(short)}, 19 | {typeof(ushort).FullName, typeof(ushort)}, 20 | {typeof(int).FullName, typeof(int)}, 21 | {typeof(uint).FullName, typeof(uint)}, 22 | {typeof(long).FullName, typeof(long)}, 23 | {typeof(ulong).FullName, typeof(ulong)}, 24 | {typeof(float).FullName, typeof(float)}, 25 | {typeof(double).FullName, typeof(double)}, 26 | {typeof(decimal).FullName, typeof(decimal)}, 27 | {typeof(char).FullName, typeof(char)}, 28 | {typeof(bool).FullName, typeof(bool)}, 29 | {typeof(string).FullName, typeof(string)}, 30 | {typeof(DateTime).FullName, typeof(DateTime)} 31 | }; 32 | private static Dictionary> subTypes = new Dictionary>(); 33 | private static Dictionary fullNames = new Dictionary(); 34 | private static Dictionary tempType = new Dictionary(); 35 | public static List GetSubClassList(FieldInfo fieldInfo, Type type, out string[] names) 36 | { 37 | if (type == null) 38 | { 39 | names = null; 40 | return null; 41 | } 42 | fullNames.TryGetValue(type, out names); 43 | if (subTypes.TryGetValue(type, out var res)) return res; 44 | res = new List(); 45 | if (!type.IsAbstract) 46 | { 47 | res.Add(type); 48 | } 49 | var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 50 | for (int i = 0; i < assemblies.Length; i++) 51 | { 52 | var types = assemblies[i].GetTypes(); 53 | foreach (var item in types) 54 | { 55 | if (item.IsClass && !item.IsAbstract && type.IsAssignableFrom(item)) 56 | { 57 | res.Add(item); 58 | } 59 | } 60 | } 61 | 62 | names = new string[res.Count]; 63 | for (int i = 0; i < names.Length; i++) 64 | { 65 | if (res[i].GetCustomAttribute(typeof(LabelTextAttribute)) is LabelTextAttribute labelTextAttribute) 66 | { 67 | names[i] = labelTextAttribute.Text; 68 | } 69 | else 70 | { 71 | names[i] = res[i].FullName; 72 | } 73 | } 74 | fullNames.Add(type, names); 75 | subTypes.Add(type,res); 76 | return res; 77 | } 78 | public static Type FindType(string name) 79 | { 80 | if(TypeCodes.TryGetValue(name,out var type)) 81 | { 82 | return type; 83 | } 84 | if (tempType.TryGetValue(name, out type)) 85 | { 86 | return type; 87 | } 88 | var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 89 | for (int i = 0; i < assemblies.Length; i++) 90 | { 91 | var types = assemblies[i].GetTypes(); 92 | foreach (var item in types) 93 | { 94 | if (item.IsClass) 95 | { 96 | if (item.FullName == name) 97 | { 98 | tempType.Add(name,item); 99 | return item; 100 | } 101 | if (item.Name == name) 102 | { 103 | type = item; 104 | } 105 | } 106 | } 107 | } 108 | 109 | if (type != null) 110 | { 111 | tempType.Add(name,type); 112 | } 113 | return type; 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /TypeHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5b9d16a7d9fb4a458493dd1721764cec 3 | timeCreated: 1737198597 -------------------------------------------------------------------------------- /ValueDropdownItem.cs: -------------------------------------------------------------------------------- 1 | #if !ODIN_INSPECTOR 2 | namespace DaGenGraph 3 | { 4 | /// 5 | /// 6 | /// 7 | public interface IValueDropdownItem 8 | { 9 | /// Gets the label for the dropdown item. 10 | /// The label text for the item. 11 | string GetText(); 12 | 13 | /// Gets the value of the dropdown item. 14 | /// The value for the item. 15 | object GetValue(); 16 | } 17 | public struct ValueDropdownItem: IValueDropdownItem 18 | { 19 | /// The name of the item. 20 | public string Text; 21 | /// The value of the item. 22 | public object Value; 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The text to display for the dropdown item. 28 | /// The value for the dropdown item. 29 | public ValueDropdownItem(string text, object value) 30 | { 31 | this.Text = text; 32 | this.Value = value; 33 | } 34 | 35 | /// The name of this item. 36 | public override string ToString() => this.Text ?? this.Value?.ToString() ?? ""; 37 | 38 | /// Gets the text. 39 | string IValueDropdownItem.GetText() => this.Text; 40 | 41 | /// Gets the value. 42 | object IValueDropdownItem.GetValue() => this.Value; 43 | } 44 | } 45 | 46 | #endif -------------------------------------------------------------------------------- /ValueDropdownItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39bb0b44b3774837b0f208c239946f0f 3 | timeCreated: 1737617720 -------------------------------------------------------------------------------- /VirtualPoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace DaGenGraph 5 | { 6 | public class VirtualPoint 7 | { 8 | /// The Node this connection point belongs to 9 | public NodeBase node; 10 | 11 | /// The Port this connection point belongs top 12 | public Port port; 13 | 14 | /// The Point position in Node Space (not World Space) 15 | public Vector2 pointPosition; 16 | 17 | /// The Point position in Port Space (not Node or World Space). This is the value found in the Port.ConnectionPoints list 18 | public Vector2 localPointPosition; 19 | 20 | /// 21 | ///The Rect of this connection point in World Space. 22 | /// 23 | ///Note that CalculateRect() needs to be called before using this rect. 24 | /// 25 | ///CalculateRect() is done automatically when building the Database or when the Database is updated. 26 | /// 27 | ///The Database update is executed automatically when (Event.current.type == EventType.MouseDrag) is performed on the parent Node. 28 | /// 29 | public Rect rect; 30 | 31 | /// 32 | /// Remembers if this point is occupied or not. 33 | /// 34 | /// A point is deemed occupied when in the ConnectionsDatabase there is at least one VirtualConnection that uses this PointPosition (for the parent Port, for the parent Node) 35 | /// 36 | public bool isConnected; 37 | 38 | 39 | /// Construct a Virtual Point 40 | /// The node this virtual point belongs to 41 | /// 42 | /// The position - in node space - this point is located at 43 | /// The position - in socket space - this point is located at 44 | public VirtualPoint(NodeBase node, Port port, Vector2 pointPosition, Vector2 localPointPosition) 45 | { 46 | this.node = node; 47 | this.port = port; 48 | this.pointPosition = pointPosition; 49 | this.localPointPosition = localPointPosition; 50 | isConnected = false; 51 | CalculateRect(); //calculate the Rect by converting the position from NodeSpace to WorldSpace and setting up correct values 52 | } 53 | 54 | /// 55 | /// Calculate this virtual point's rect by converting it's point position node space position into a world position. 56 | /// 57 | /// It uses the default connector width and height (found in Settings.GUI) in order to create the rect. 58 | /// 59 | public void CalculateRect() 60 | { 61 | rect = new Rect(); 62 | if (node == null) 63 | { 64 | Debug.Log("Cannot calculate the connection point Rect because the parent Node is null."); 65 | return; 66 | } 67 | 68 | if (port == null) 69 | { 70 | Debug.Log("Cannot calculate the connection point Rect because the parent Port is null."); 71 | return; 72 | } 73 | 74 | var worldRect = new Rect(node.GetX(), 75 | node.GetY() + port.GetY(), 76 | port.GetWidth(), 77 | port.GetHeight()); 78 | 79 | rect = new Rect(worldRect.x + pointPosition.x + m_ConnectionPointWidth / 2, 80 | worldRect.y + pointPosition.y + m_ConnectionPointWidth / 2, 81 | m_ConnectionPointWidth, 82 | m_ConnectionPointHeight); 83 | } 84 | 85 | private float m_ConnectionPointWidth = 16f; 86 | private float m_ConnectionPointHeight = 16f; 87 | } 88 | } -------------------------------------------------------------------------------- /VirtualPoint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 481da3fe5c4240889229c5374b6d25d4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.lifang.dagen", 3 | "displayName": "DaGenGraph", 4 | "version": "1.1.0", 5 | "unity": "2020.4", 6 | "description": " used by lifang", 7 | "keywords": [ 8 | "tools", 9 | "unity" 10 | ], 11 | "category": "LiFang", 12 | "dependencies": { 13 | 14 | }, 15 | "type": "tool" 16 | } 17 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 779bfd226d94102479466849603a8d9d 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------