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;