diff --git a/TNodeCore/Attribute/GraphUsageAttribute.cs b/TNodeCore/Attribute/GraphUsageAttribute.cs index af08872..4eb9151 100644 --- a/TNodeCore/Attribute/GraphUsageAttribute.cs +++ b/TNodeCore/Attribute/GraphUsageAttribute.cs @@ -16,15 +16,14 @@ namespace TNodeCore.Attribute{ public class GraphUsageAttribute:System.Attribute{ public readonly Type GraphDataType; public string Category; - public GraphUsageAttribute(Type t,string category = null){ + public GraphUsageAttribute(Type t,string category = "default"){ //check if the type t is graph if(!typeof(GraphData).IsAssignableFrom(t)){ throw new Exception("The type used on Graph Usage must be a graph"); } GraphDataType = t; - if (category != null){ - Category = category; - } + Category = category; + } } diff --git a/TNodeCore/DataWrapper.cs b/TNodeCore/DataWrapper.cs index 64e96ea..92ba218 100644 --- a/TNodeCore/DataWrapper.cs +++ b/TNodeCore/DataWrapper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using UnityEditor; using UnityEngine; namespace TNodeCore{ @@ -34,6 +35,7 @@ namespace TNodeCore{ var fieldInfo = data.GetType().GetField(path); return fieldInfo.GetValue(data); } + public virtual TData GetData(){ return data; } diff --git a/TNodeCore/Models/BlackboardDragNodeData.cs b/TNodeCore/Models/BlackboardDragNodeData.cs index 0f1622f..120fd77 100644 --- a/TNodeCore/Models/BlackboardDragNodeData.cs +++ b/TNodeCore/Models/BlackboardDragNodeData.cs @@ -7,17 +7,25 @@ using UnityEngine; namespace TNodeCore.Models{ [Serializable] [InternalModel] - public class BlackboardDragNodeData:NodeData{ + public class BlackboardDragNodeData:RuntimeNodeData{ public string blackDragData; - [SerializeReference] - public BlackboardData blackboardData; - - [Output("",PortNameHandling.MemberType,TypeHandling.Implemented)] - public object Value => blackboardData.GetValue(blackDragData); + + /// + /// it's very hacky way to get blackboard data ,even when the value is null,type info is not null! + /// + /// TODO : The type handling in a safer way in the future + [Output("",PortNameHandling.MemberType,TypeHandling.Implemented)] + public object Value => BlackboardData.GetValue(blackDragData); public BlackboardDragNodeData(){ } } + [Serializable] + public class RuntimeNodeData:NodeData{ + + public BlackboardData BlackboardData{ get; set; } + + } } \ No newline at end of file diff --git a/TNodeCore/Runtime/RuntimeGraph.cs b/TNodeCore/Runtime/RuntimeGraph.cs index 235f792..11dd5c8 100644 --- a/TNodeCore/Runtime/RuntimeGraph.cs +++ b/TNodeCore/Runtime/RuntimeGraph.cs @@ -16,6 +16,9 @@ namespace TNodeCore.Runtime{ [NonSerialized] public readonly List TopologicalOrder = new List(); public readonly List EntryNodes = new List(); + /// + /// elements are read only ,do not modify them + /// public readonly Dictionary RuntimeNodes; public void DependencyTraversal(RuntimeNode runtimeNode){ var links = runtimeNode.InputLink; @@ -26,7 +29,7 @@ namespace TNodeCore.Runtime{ } runtimeNode.NodeData.Process(); } - + public void HandlingLink(NodeLink nodeLink){ var inNode = RuntimeNodes[nodeLink.inPort.nodeDataId]; var outNode = RuntimeNodes[nodeLink.outPort.nodeDataId]; @@ -125,6 +128,12 @@ namespace TNodeCore.Runtime{ RuntimeNodes[inNode.id].InputLink.Add(linkData); } + public List GetRuntimeNodesOfType(){ + return RuntimeNodes.Values.Where(x => x.NodeType == typeof(T)).ToList(); + } + public List GetRuntimeNodesOfType(Type type){ + return RuntimeNodes.Values.Where(x => x.NodeType == type).ToList(); + } private void ModifyOrCreateOutNode(NodeLink linkData){ var outNodeId = linkData.outPort.nodeDataId; var outNode = graphData.NodeDictionary[outNodeId]; diff --git a/TNodeCore/Runtime/RuntimeNode.cs b/TNodeCore/Runtime/RuntimeNode.cs index 515f840..e4b435a 100644 --- a/TNodeCore/Runtime/RuntimeNode.cs +++ b/TNodeCore/Runtime/RuntimeNode.cs @@ -15,7 +15,7 @@ namespace TNodeCore.Runtime{ public List OutputLink = new List(); //Cache node data type for fast access private readonly Type _type; - + public Type NodeType => _type; public void SetInput(string portName,object value){ _portAccessors[portName].SetValue(this.NodeData,value); diff --git a/TNodeCore/RuntimeCache/RuntimeCache.cs b/TNodeCore/RuntimeCache/RuntimeCache.cs index 5eb6068..932890b 100644 --- a/TNodeCore/RuntimeCache/RuntimeCache.cs +++ b/TNodeCore/RuntimeCache/RuntimeCache.cs @@ -80,10 +80,7 @@ namespace TNodeCore.RuntimeCache{ } } } - - } - private void AddTypeToCache(Type type,System.Attribute attribute){ //Check if the type is a blackboard data type if(typeof(BlackboardData).IsAssignableFrom(type)){ diff --git a/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs b/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs index 5d55934..fcdcb48 100644 --- a/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs +++ b/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs @@ -18,8 +18,7 @@ namespace TNodeGraphViewImpl.Editor.Cache{ /// Internal singleton class for caching TNode reflection Data. /// internal class NodeEditorTypeDictionary:Dictionary{ - private class NodeEditorTypeDictionaryComparer : IEqualityComparer - { + private class NodeEditorTypeDictionaryComparer : IEqualityComparer{ public bool Equals(Type x, Type y){ return x?.ToString() == y?.ToString(); } @@ -28,11 +27,9 @@ namespace TNodeGraphViewImpl.Editor.Cache{ return obj.ToString().GetHashCode(); } } - public NodeEditorTypeDictionary():base(new NodeEditorTypeDictionaryComparer()){ } - } internal class NodeEditorSingleton{ @@ -132,6 +129,10 @@ namespace TNodeGraphViewImpl.Editor.Cache{ var instance = (T)Activator.CreateInstance(implementedType); return instance; } + public static string GetTypeCategory(Type type){ + var category = type.GetCustomAttribute(); + return category?.Category ?? ""; + } /// /// by given a generic type t,return the implementation instance of the generic type @@ -190,6 +191,13 @@ namespace TNodeGraphViewImpl.Editor.Cache{ } return new List(); } + + public static List GetGraphCategories(Type t){ + var list = NodeEditorSingleton.Instance.GraphDataUsage[t]; + //Merge same category + var res = list.Select(x=>x.GetCustomAttribute().Category).Distinct().ToList(); + return res; + } public static BlackboardData GetAppropriateBlackboardData(Type t){ if (NodeEditorSingleton.Instance.GraphBlackboard.ContainsKey(t)){ return (BlackboardData)Activator.CreateInstance(NodeEditorSingleton.Instance.GraphBlackboard[t]); diff --git a/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardField.cs b/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardField.cs index 93470ef..e37882f 100644 --- a/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardField.cs +++ b/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardField.cs @@ -1,9 +1,9 @@ using UnityEditor.Experimental.GraphView; namespace TNodeGraphViewImpl.Editor.GraphBlackboard{ - public class BlackboardPropertyField:BlackboardField{ + public class BlackboardField:UnityEditor.Experimental.GraphView.BlackboardField{ public BlackboardProperty.BlackboardProperty BlackboardProperty; - public BlackboardPropertyField(BlackboardProperty.BlackboardProperty blackboardProperty):base(null,blackboardProperty.PropertyName,null){ + public BlackboardField(BlackboardProperty.BlackboardProperty blackboardProperty):base(null,blackboardProperty.PropertyName,null){ BlackboardProperty = blackboardProperty; } diff --git a/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs b/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs index 129d9ea..499bc5c 100644 --- a/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs +++ b/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs @@ -30,7 +30,7 @@ namespace TNodeGraphViewImpl.Editor.GraphBlackboard{ //skip if the field is a list or Ilist if (!typeof(IList).IsAssignableFrom(field.FieldType)){ VisualElement visualElement = new VisualElement(); - var propertyField = new BlackboardPropertyField(new BlackboardProperty.BlackboardProperty(field.Name,field.FieldType)); + var propertyField = new BlackboardField(new BlackboardProperty.BlackboardProperty(field.Name,field.FieldType)); var foldoutData = new Foldout{ text = field.Name }; diff --git a/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs b/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs index 216cb24..fcab94f 100644 --- a/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs +++ b/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using TNode.Editor.Inspector; using TNode.Editor.Search; using TNodeCore.Editor.Blackboard; @@ -12,13 +13,12 @@ using TNodeCore.Runtime; using TNodeGraphViewImpl.Editor.Cache; using TNodeGraphViewImpl.Editor.GraphBlackboard; using TNodeGraphViewImpl.Editor.NodeViews; +using TNodeGraphViewImpl.Editor.Search; using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; - - - +using BlackboardField = TNodeGraphViewImpl.Editor.GraphBlackboard.BlackboardField; using Edge = UnityEditor.Experimental.GraphView.Edge; namespace TNodeGraphViewImpl.Editor.NodeGraphView{ @@ -216,12 +216,12 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{ private void OnDragPerform(DragPerformEvent evt){ if (DragAndDrop.GetGenericData("DragSelection") is List{Count: > 0} data){ - var blackboardFields = data.OfType(); + var blackboardFields = data.OfType(); foreach (var selectable in blackboardFields){ if(selectable is { } field) { //Make a constructor of BlackboardDragNodeData by reflection var dragNodeData = NodeCreator.InstantiateNodeData(); - dragNodeData.blackboardData = GetBlackboardData(); + dragNodeData.BlackboardData = GetBlackboardData(); dragNodeData.blackDragData = field.BlackboardProperty.PropertyName; AddTNode(dragNodeData,new Rect(evt.mousePosition,new Vector2(200,200))); } @@ -231,17 +231,11 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{ } private void OnDragUpdated(DragUpdatedEvent evt){ - //check if the drag data is BlackboardField - if (DragAndDrop.GetGenericData("DragSelection") is List{Count: > 0} data){ DragAndDrop.visualMode = DragAndDropVisualMode.Move; - } - - } - #endregion @@ -263,10 +257,12 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{ //Get the node type var nodeType = dataNode.GetType(); //Get the derived type of NodeAttribute View from the node type - + if (dataNode is RuntimeNodeData runtimeNodeData){ + runtimeNodeData.BlackboardData = GetBlackboardData(); + } var nodePos = Owner.graphEditorData.graphElementsData. FirstOrDefault(x => x.guid == dataNode.id)?.pos??new Rect(0,0,200,200); - + AddTNode(dataNode,nodePos); } @@ -403,10 +399,20 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{ _data.blackboardData = NodeEditorExtensions.GetAppropriateBlackboardData(_data.GetType()); } } - - + //TODO:Handling implicit conversion when two port types are different but compatible + private static bool HasImplicitConversion(Type baseType, Type targetType) + { + return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) + .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) + .Any(mi => { + ParameterInfo pi = mi.GetParameters().FirstOrDefault(); + return pi != null && pi.ParameterType == baseType; + }); + } public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){ - return ports.Where(x => x.portType == startPort.portType || x.portType.IsAssignableFrom(startPort.portType)).ToList(); + + return ports.Where(x => startPort!=x && (x.portType == startPort.portType || x.portType.IsAssignableFrom(startPort.portType))).ToList(); + } public virtual void OnGraphViewCreate(){ diff --git a/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs b/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs index 8bce179..35ca0b0 100644 --- a/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs +++ b/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs @@ -1,6 +1,13 @@ using TNodeCore.Attribute; +using TNodeCore.Editor.Serialization; using TNodeCore.Models; using TNodeGraphViewImpl.Editor.NodeViews; +using UnityEditor; +using UnityEditor.Experimental.GraphView; +using UnityEditor.Graphs; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; namespace TNode.Editor.NodeViews{ [ViewComponent] @@ -8,6 +15,26 @@ namespace TNode.Editor.NodeViews{ public DragBaseNodeView() : base(){ this.titleContainer.visible = false; this.titleContainer.RemoveFromHierarchy(); + this.OnDataChanged += OnDataChangedHandler; + } + + private void OnDataChangedHandler(BlackboardDragNodeData obj){ + var port = this.Q(); + var label = port.Q