From 6bacdb9eb45f94700637f32b316da97566080c04 Mon Sep 17 00:00:00 2001 From: taoria <445625470@qq.com> Date: Thu, 7 Jul 2022 23:45:01 +0800 Subject: [PATCH] chore: little work around on Blackboard drag node --- TNode/Attribute/Ports/BatchOutputAttribute.cs | 3 +- TNode/Attribute/Ports/InputAttribute.cs | 3 +- TNode/Attribute/Ports/OutputAttribute.cs | 5 +- TNode/Attribute/Ports/PortAttribute.cs | 18 ++++- TNode/Editor/Cache/NodeEditorExtensions.cs | 72 +++++++++++++++++-- TNode/Editor/Inspector/InspectorItem.cs | 1 - TNode/Editor/NodeViews.meta | 3 + .../Editor/{ => NodeViews}/DefaultNodeView.cs | 0 .../{ => NodeViews}/DefaultNodeView.cs.meta | 0 TNode/Editor/NodeViews/DragNodeView.cs | 15 ++++ TNode/Editor/NodeViews/DragNodeView.cs.meta | 3 + .../{BaseViews => NodeViews}/NodeView.cs | 43 ++++++++--- .../{BaseViews => NodeViews}/NodeView.cs.meta | 0 TNode/Models/BlackboardDragNodeData.cs | 4 +- TNode/RuntimeCache/RuntimeCache.cs | 5 ++ 15 files changed, 151 insertions(+), 24 deletions(-) create mode 100644 TNode/Editor/NodeViews.meta rename TNode/Editor/{ => NodeViews}/DefaultNodeView.cs (100%) rename TNode/Editor/{ => NodeViews}/DefaultNodeView.cs.meta (100%) create mode 100644 TNode/Editor/NodeViews/DragNodeView.cs create mode 100644 TNode/Editor/NodeViews/DragNodeView.cs.meta rename TNode/Editor/{BaseViews => NodeViews}/NodeView.cs (72%) rename TNode/Editor/{BaseViews => NodeViews}/NodeView.cs.meta (100%) diff --git a/TNode/Attribute/Ports/BatchOutputAttribute.cs b/TNode/Attribute/Ports/BatchOutputAttribute.cs index 9e96754..71a20c3 100644 --- a/TNode/Attribute/Ports/BatchOutputAttribute.cs +++ b/TNode/Attribute/Ports/BatchOutputAttribute.cs @@ -7,6 +7,7 @@ namespace TNode.Attribute.Ports{ /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class BatchOutputAttribute:PortAttribute{ - + public BatchOutputAttribute(string name="") : base(name){ + } } } \ No newline at end of file diff --git a/TNode/Attribute/Ports/InputAttribute.cs b/TNode/Attribute/Ports/InputAttribute.cs index 1312c34..dd4b855 100644 --- a/TNode/Attribute/Ports/InputAttribute.cs +++ b/TNode/Attribute/Ports/InputAttribute.cs @@ -7,6 +7,7 @@ namespace TNode.Attribute{ [MeansImplicitUse] [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class InputAttribute : PortAttribute{ - + public InputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto) : base(name, nameHandling){ + } } } \ No newline at end of file diff --git a/TNode/Attribute/Ports/OutputAttribute.cs b/TNode/Attribute/Ports/OutputAttribute.cs index 675d731..a0c3908 100644 --- a/TNode/Attribute/Ports/OutputAttribute.cs +++ b/TNode/Attribute/Ports/OutputAttribute.cs @@ -1,5 +1,6 @@ namespace TNode.Attribute.Ports{ - public class OutputAttribute:System.Attribute{ - + public class OutputAttribute:PortAttribute{ + public OutputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto) : base(name, nameHandling){ + } } } \ No newline at end of file diff --git a/TNode/Attribute/Ports/PortAttribute.cs b/TNode/Attribute/Ports/PortAttribute.cs index 72fb46e..24feda5 100644 --- a/TNode/Attribute/Ports/PortAttribute.cs +++ b/TNode/Attribute/Ports/PortAttribute.cs @@ -3,10 +3,24 @@ using JetBrains.Annotations; using UnityEditor.Experimental.GraphView; namespace TNode.Attribute{ + + public enum PortNameHandling{ + Auto, + MemberName, + Manual, + Format, + MemberType + + } [MeansImplicitUse] [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] - public class PortAttribute:System.Attribute{ - + public readonly string Name; + public readonly PortNameHandling NameHandling; + + public PortAttribute(string name,PortNameHandling nameHandling=PortNameHandling.Auto){ + this.Name = name; + this.NameHandling = nameHandling; + } } } \ No newline at end of file diff --git a/TNode/Editor/Cache/NodeEditorExtensions.cs b/TNode/Editor/Cache/NodeEditorExtensions.cs index f238eb8..d21c96c 100644 --- a/TNode/Editor/Cache/NodeEditorExtensions.cs +++ b/TNode/Editor/Cache/NodeEditorExtensions.cs @@ -9,14 +9,37 @@ using TNode.Editor.Inspector; using TNode.Models; using UnityEditor.Experimental.GraphView; using UnityEngine; +using UnityEngine.TestTools.Utils; namespace TNode.Cache{ /// /// Internal singleton class for caching TNode reflection Data. /// + internal class NodeEditorTypeDictionary:Dictionary{ + //Custom camparator for sorting the dictionary by key. + + + + private class NodeEditorTypeDictionaryComparer : IEqualityComparer + { + public bool Equals(Type x, Type y){ + return x?.ToString() == y?.ToString(); + } + + public int GetHashCode(Type obj){ + return obj.ToString().GetHashCode(); + } + } + + public NodeEditorTypeDictionary():base(new NodeEditorTypeDictionaryComparer()){ + + } + + } + internal class NodeEditorSingleton{ private static NodeEditorSingleton _instance; - public readonly Dictionary FromGenericToSpecific = new Dictionary(); + public readonly Dictionary FromGenericToSpecific = new NodeEditorTypeDictionary(); public readonly Dictionary> GraphDataUsage = new Dictionary>(); public Dictionary GraphBlackboard = new(); public static NodeEditorSingleton Instance{ @@ -75,15 +98,22 @@ namespace TNode.Cache{ } } } - private readonly Type[] _acceptedTypesForGenericToSpecific = new Type[]{typeof(NodeView<>),typeof(DataGraphView<>),typeof(InspectorItem<>)}; + private readonly Type[] _acceptedTypesForGenericToSpecific = new Type[]{typeof(NodeView<>),typeof(DataGraphView<>),typeof(InspectorItem<>),typeof(NodeView<>)}; private void SetNodeComponentAttribute(Type type){ foreach (var attribute in type.GetCustomAttributes(typeof(NodeComponentAttribute), false)){ //fetch this type 's parent class var parent = type.BaseType; - //Check if this type is a generic type and is a generic type of NodeView or DataGraphView - if (parent is{IsGenericType: true} && _acceptedTypesForGenericToSpecific.Contains(parent.GetGenericTypeDefinition())){ + //Check if this type is a generic type and is a generic type of NodeView or DataGraphView, + //Two level generic definition is now supported by TNode + //Deeper nested generic definition is not supported by TNode + if (parent is{IsGenericType: true} && + (_acceptedTypesForGenericToSpecific.Contains(parent.GetGenericTypeDefinition()) || + (parent.GetGenericTypeDefinition().IsGenericType && _acceptedTypesForGenericToSpecific.Contains(parent.GetGenericTypeDefinition().GetGenericTypeDefinition())) + ) + ){ //Get the generic type of this type //Add this type to the dictionary + Debug.Log($"type {type} is a registered as node component for {parent}"); FromGenericToSpecific.Add(parent, type); } //TODO Note that a node component only applied to a specific type of editor,so ,same GraphView could behave differently in different editor.it's a todo feature. @@ -103,7 +133,6 @@ namespace TNode.Cache{ var instance = Activator.CreateInstance(implementedType); return instance; } - Debug.Log($"No given type found {t}"); //check if t is a generic type node view if (t is{IsGenericType: true} && t.GetGenericTypeDefinition() == typeof(NodeView<>)){ var instance = Activator.CreateInstance(typeof(NodeView)); @@ -146,13 +175,46 @@ namespace TNode.Cache{ } public static object CreateNodeViewFromNodeType(Type t){ //Check the generic type of NodeView by t + + if (t.IsGenericType){ + Debug.Log($"A generic type {t} is detected"); + //AKA if BlackboardDragNodeData is pulled + //Get BlackboardDragNodeData as generic type + + + var genericTypeDefinition = t.GetGenericTypeDefinition(); + + //What you want is a NodeView> to be created + var genericViewType = typeof(NodeView<>).MakeGenericType(genericTypeDefinition); + Debug.Log($"The generic view type is {genericViewType}"); + + //search for the specific type of genericViewType in the dictionary + if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(genericViewType)){ + + var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[genericViewType]; + //The implementedType is still a generic type ,so we make it a specific type by using MakeGenericType + Debug.Log($"{implementedType}"); + //Get argument type of t + var argumentType = t.GetGenericArguments()[0]; + var instance = Activator.CreateInstance(implementedType.MakeGenericType(argumentType)); + + return instance; + + } + else{ + return new DefaultNodeView(); + } + + } var type = typeof(NodeView<>).MakeGenericType(t); if (NodeEditorSingleton.Instance.FromGenericToSpecific.ContainsKey(type)){ + var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[type]; var instance = Activator.CreateInstance(implementedType); return instance; } else{ + return new DefaultNodeView(); } diff --git a/TNode/Editor/Inspector/InspectorItem.cs b/TNode/Editor/Inspector/InspectorItem.cs index 278e215..8802bb5 100644 --- a/TNode/Editor/Inspector/InspectorItem.cs +++ b/TNode/Editor/Inspector/InspectorItem.cs @@ -88,7 +88,6 @@ namespace TNode.Editor.Inspector{ Bindable.value = Value; Bindable.label = BindingPath; } - Debug.Log(Value.GetType()); } private void OnNodeDataValueChanged(NodeDataWrapper wrapper){ diff --git a/TNode/Editor/NodeViews.meta b/TNode/Editor/NodeViews.meta new file mode 100644 index 0000000..8da3bd3 --- /dev/null +++ b/TNode/Editor/NodeViews.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ea202e63fe8e4d3b9b7759488419dde7 +timeCreated: 1657197080 \ No newline at end of file diff --git a/TNode/Editor/DefaultNodeView.cs b/TNode/Editor/NodeViews/DefaultNodeView.cs similarity index 100% rename from TNode/Editor/DefaultNodeView.cs rename to TNode/Editor/NodeViews/DefaultNodeView.cs diff --git a/TNode/Editor/DefaultNodeView.cs.meta b/TNode/Editor/NodeViews/DefaultNodeView.cs.meta similarity index 100% rename from TNode/Editor/DefaultNodeView.cs.meta rename to TNode/Editor/NodeViews/DefaultNodeView.cs.meta diff --git a/TNode/Editor/NodeViews/DragNodeView.cs b/TNode/Editor/NodeViews/DragNodeView.cs new file mode 100644 index 0000000..8ce31c7 --- /dev/null +++ b/TNode/Editor/NodeViews/DragNodeView.cs @@ -0,0 +1,15 @@ +using TNode.Attribute; +using TNode.Editor.BaseViews; +using TNode.Models; + +namespace TNode.Editor.NodeViews{ + [NodeComponent] + public class DragNodeView:NodeView>{ + public DragNodeView() : base(){ + //Make capsule like style + + this.titleContainer.visible = false; + this.titleContainer.RemoveFromHierarchy(); + } + } +} \ No newline at end of file diff --git a/TNode/Editor/NodeViews/DragNodeView.cs.meta b/TNode/Editor/NodeViews/DragNodeView.cs.meta new file mode 100644 index 0000000..97c8950 --- /dev/null +++ b/TNode/Editor/NodeViews/DragNodeView.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 899b964a5f674c2fbf1db20cf40ff5e7 +timeCreated: 1657197096 \ No newline at end of file diff --git a/TNode/Editor/BaseViews/NodeView.cs b/TNode/Editor/NodeViews/NodeView.cs similarity index 72% rename from TNode/Editor/BaseViews/NodeView.cs rename to TNode/Editor/NodeViews/NodeView.cs index bcf74b8..0079cb6 100644 --- a/TNode/Editor/BaseViews/NodeView.cs +++ b/TNode/Editor/NodeViews/NodeView.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Reflection; using TNode.Attribute; using TNode.Attribute.Ports; using TNode.Editor.Inspector; @@ -63,25 +65,46 @@ namespace TNode.Editor.BaseViews{ this.RefreshExpandedState(); } - private void BuildInputAndOutputPort(){ + protected virtual string BuildPortName(PortAttribute portAttribute,PropertyInfo propertyInfo,params object[] args){ + switch (portAttribute.NameHandling){ + case PortNameHandling.Auto: + return portAttribute.Name.Trim(' ').Length>0?portAttribute.Name:propertyInfo.Name; + break; + case PortNameHandling.Manual: + return portAttribute.Name; + break; + case PortNameHandling.MemberName: + return propertyInfo.Name; + case PortNameHandling.Format: + return String.Format(propertyInfo.Name, args); + case PortNameHandling.MemberType: + return propertyInfo.PropertyType.Name; + default: + throw new ArgumentOutOfRangeException(); + } + } + /// + /// of course you can override this method to build your own port builder + /// + protected virtual void BuildInputAndOutputPort(){ var propertyInfos = _data.GetType().GetProperties(); foreach (var propertyInfo in propertyInfos){ - var attribute = propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true); - if (attribute.Length > 0){ + if (propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true).FirstOrDefault() is OutputAttribute attribute){ Port port = InstantiatePort(Orientation.Horizontal, Direction.Output,Port.Capacity.Multi,propertyInfo.PropertyType); this.outputContainer.Add(port); - port.portName = propertyInfo.Name; - port.name = propertyInfo.Name; + var portName = BuildPortName(attribute,propertyInfo); + port.portName = portName; + port.name = portName; } } foreach (var propertyInfo in propertyInfos){ - var attribute = propertyInfo.GetCustomAttributes(typeof(InputAttribute),true); - if (attribute.Length > 0){ - Port port = InstantiatePort(Orientation.Horizontal, Direction.Input,Port.Capacity.Multi,propertyInfo.PropertyType); + if(propertyInfo.GetCustomAttributes(typeof(InputAttribute),true).FirstOrDefault() is InputAttribute attribute){ + Port port = InstantiatePort(Orientation.Horizontal, Direction.Input,Port.Capacity.Single,propertyInfo.PropertyType); this.inputContainer.Add(port); - port.portName = propertyInfo.Name; - port.name = propertyInfo.Name; + var portName = BuildPortName(attribute,propertyInfo); + port.portName = portName; + port.name = portName; } } } diff --git a/TNode/Editor/BaseViews/NodeView.cs.meta b/TNode/Editor/NodeViews/NodeView.cs.meta similarity index 100% rename from TNode/Editor/BaseViews/NodeView.cs.meta rename to TNode/Editor/NodeViews/NodeView.cs.meta diff --git a/TNode/Models/BlackboardDragNodeData.cs b/TNode/Models/BlackboardDragNodeData.cs index 5119283..dc587ad 100644 --- a/TNode/Models/BlackboardDragNodeData.cs +++ b/TNode/Models/BlackboardDragNodeData.cs @@ -1,16 +1,16 @@ using System.Runtime.InteropServices; using Newtonsoft.Json; +using TNode.Attribute; using TNode.Attribute.Ports; using TNode.RuntimeCache; namespace TNode.Models{ public class BlackboardDragNodeData:NodeData{ - [JsonIgnore] private string _blackDragData; [JsonIgnore] private BlackboardData _blackboardData; - [Output] + [Output("",PortNameHandling.MemberType)] public T Value => _blackboardData.GetValue(_blackDragData); public BlackboardDragNodeData(){ diff --git a/TNode/RuntimeCache/RuntimeCache.cs b/TNode/RuntimeCache/RuntimeCache.cs index c63aea1..4310a3e 100644 --- a/TNode/RuntimeCache/RuntimeCache.cs +++ b/TNode/RuntimeCache/RuntimeCache.cs @@ -62,6 +62,11 @@ namespace TNode.RuntimeCache{ var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[blackboardData.GetType()][path]; return (T) method.Invoke(blackboardData); } + + public static object GetValue(this BlackboardData blackboardData, string path){ + var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[blackboardData.GetType()][path]; + return method.Invoke(blackboardData); + } public static RuntimeCache.GetValueDelegate GetValueDelegate(this BlackboardData blackboardData,string path){ var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[blackboardData.GetType()][path]; return method;