chore: little work around on Blackboard drag node

main
taoria 3 years ago
parent f6d5632a0b
commit 6bacdb9eb4
  1. 3
      TNode/Attribute/Ports/BatchOutputAttribute.cs
  2. 3
      TNode/Attribute/Ports/InputAttribute.cs
  3. 5
      TNode/Attribute/Ports/OutputAttribute.cs
  4. 18
      TNode/Attribute/Ports/PortAttribute.cs
  5. 72
      TNode/Editor/Cache/NodeEditorExtensions.cs
  6. 1
      TNode/Editor/Inspector/InspectorItem.cs
  7. 3
      TNode/Editor/NodeViews.meta
  8. 0
      TNode/Editor/NodeViews/DefaultNodeView.cs
  9. 0
      TNode/Editor/NodeViews/DefaultNodeView.cs.meta
  10. 15
      TNode/Editor/NodeViews/DragNodeView.cs
  11. 3
      TNode/Editor/NodeViews/DragNodeView.cs.meta
  12. 43
      TNode/Editor/NodeViews/NodeView.cs
  13. 0
      TNode/Editor/NodeViews/NodeView.cs.meta
  14. 4
      TNode/Models/BlackboardDragNodeData.cs
  15. 5
      TNode/RuntimeCache/RuntimeCache.cs

@ -7,6 +7,7 @@ namespace TNode.Attribute.Ports{
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class BatchOutputAttribute:PortAttribute{
public BatchOutputAttribute(string name="") : base(name){
}
}
}

@ -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){
}
}
}

@ -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){
}
}
}

@ -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;
}
}
}

@ -9,14 +9,37 @@ using TNode.Editor.Inspector;
using TNode.Models;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.TestTools.Utils;
namespace TNode.Cache{
/// <summary>
/// Internal singleton class for caching TNode reflection Data.
/// </summary>
internal class NodeEditorTypeDictionary:Dictionary<Type, Type>{
//Custom camparator for sorting the dictionary by key.
private class NodeEditorTypeDictionaryComparer : IEqualityComparer<Type>
{
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<Type,Type> FromGenericToSpecific = new Dictionary<Type, Type>();
public readonly Dictionary<Type,Type> FromGenericToSpecific = new NodeEditorTypeDictionary();
public readonly Dictionary<Type, List<Type>> GraphDataUsage = new Dictionary<Type, List<Type>>();
public Dictionary<Type, Type> 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<NodeData>));
@ -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<Camera> is pulled
//Get BlackboardDragNodeData<T> as generic type
var genericTypeDefinition = t.GetGenericTypeDefinition();
//What you want is a NodeView<BlackboardDragNodeData<T>> 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();
}

@ -88,7 +88,6 @@ namespace TNode.Editor.Inspector{
Bindable.value = Value;
Bindable.label = BindingPath;
}
Debug.Log(Value.GetType());
}
private void OnNodeDataValueChanged(NodeDataWrapper wrapper){

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ea202e63fe8e4d3b9b7759488419dde7
timeCreated: 1657197080

@ -0,0 +1,15 @@
using TNode.Attribute;
using TNode.Editor.BaseViews;
using TNode.Models;
namespace TNode.Editor.NodeViews{
[NodeComponent]
public class DragNodeView<T>:NodeView<BlackboardDragNodeData<T>>{
public DragNodeView() : base(){
//Make capsule like style
this.titleContainer.visible = false;
this.titleContainer.RemoveFromHierarchy();
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 899b964a5f674c2fbf1db20cf40ff5e7
timeCreated: 1657197096

@ -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();
}
}
/// <summary>
/// of course you can override this method to build your own port builder
/// </summary>
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;
}
}
}

@ -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<T>:NodeData{
[JsonIgnore]
private string _blackDragData;
[JsonIgnore]
private BlackboardData _blackboardData;
[Output]
[Output("",PortNameHandling.MemberType)]
public T Value => _blackboardData.GetValue<T>(_blackDragData);
public BlackboardDragNodeData(){

@ -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;

Loading…
Cancel
Save