From 82a78b84da4ebed7fd86ddcec6d618326107fb83 Mon Sep 17 00:00:00 2001
From: taoria <445625470@qq.com>
Date: Mon, 18 Jul 2022 14:19:48 +0800
Subject: [PATCH] feat:test support
---
README.md | 24 ++++-
.../NodeGraphView/IBaseDataGraphView.cs | 10 ++
.../Editor/Resources/GraphViewBackground.uss | 8 ++
TNodeCore/Runtime/RuntimeGraph.cs | 13 +--
TNodeCore/Runtime/RuntimeNode.cs | 33 +++++-
TNodeCore/RuntimeCache/RuntimeCache.cs | 101 +++++++++++++-----
.../Editor/Inspector/NodeInspectorInNode.cs | 39 +++++--
.../Editor/NodeGraphView/DataGraphView.cs | 46 +++++++-
.../Editor/NodeViews/NodeView.cs | 10 +-
9 files changed, 227 insertions(+), 57 deletions(-)
diff --git a/README.md b/README.md
index 3723cb4..83ce936 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,24 @@
# T-Node
-Simple wrapper for unity experimental graphview
+Simple wrapper for unity experimental graphview and if possible latter,GTF.
+the main goal of the repo is to make graph creation easier and more intuitive.
-The main goal is to make graph script easy and clean
+Note **it's not usable and productive on current stage** and need a better
+development .
+and it's mainly for my own use now.
+
+# Install
+
+currently under development
+
+# Features
+
+1. Create graph script by the creator tool
+2. Node creation based on specified type of graph
+3. Easy port creation via attribute
+4. Runtime graph
+5. Blackboard for runtime graph as exposed parameters
+6. Runtime graph execution
+7. Test Mode (Runtime graph only)
+
+# Usage
-Note it's not fully usable on current stage and need a better development
diff --git a/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs b/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs
index 14e0ae3..7e04299 100644
--- a/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs
+++ b/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs
@@ -1,4 +1,5 @@
using TNodeCore.Models;
+using TNodeCore.Runtime;
using UnityEngine;
namespace TNodeCore.Editor.NodeGraphView{
@@ -6,11 +7,20 @@ namespace TNodeCore.Editor.NodeGraphView{
public void AddTNode(NodeData nodeData, Rect rect);
public void RemoveTNode(NodeData nodeData);
+
+ public bool TestMode{ get; set; }
public void CreateBlackboard();
public GraphData GetGraphData();
public BlackboardData GetBlackboardData();
+
+
public bool IsRuntimeGraph{ get; set; }
+ ///
+ /// Null if it is not a runtime graph
+ ///
+ ///
+ public RuntimeGraph GetRuntimeGraph();
public void SetGraphData(GraphData graph);
diff --git a/TNodeCore/Editor/Resources/GraphViewBackground.uss b/TNodeCore/Editor/Resources/GraphViewBackground.uss
index e9d3385..6c9fbfc 100644
--- a/TNodeCore/Editor/Resources/GraphViewBackground.uss
+++ b/TNodeCore/Editor/Resources/GraphViewBackground.uss
@@ -12,4 +12,12 @@ GridBackground{
font-size: 14;
+}
+#TopMenu{
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 24px;
+ background-color: #171717;
}
\ No newline at end of file
diff --git a/TNodeCore/Runtime/RuntimeGraph.cs b/TNodeCore/Runtime/RuntimeGraph.cs
index 06cae28..771be99 100644
--- a/TNodeCore/Runtime/RuntimeGraph.cs
+++ b/TNodeCore/Runtime/RuntimeGraph.cs
@@ -108,16 +108,11 @@ namespace TNodeCore.Runtime{
return null;
}
//DFS search for resolving dependency
- public void StartDependencyTraversal(NodeData startNode,NodeData currentNode,int level=0){
- if (!_build)
- Build();
- if(_graphTool==null)
- return;
+ public bool ResolveDependency(NodeData startNode){
+ if (_graphTool == null)
+ return false;
_graphTool.DependencyTraversal(Get(startNode));
- var inputNodesId = Get(currentNode).GetInputNodesId();
- foreach (var s in inputNodesId){
- var runtimeNode = Get(s);
- }
+ return true;
}
private void ModifyOrCreateInNode(NodeLink linkData){
var inNodeId = linkData.inPort.nodeDataId;
diff --git a/TNodeCore/Runtime/RuntimeNode.cs b/TNodeCore/Runtime/RuntimeNode.cs
index b83e15a..34181fc 100644
--- a/TNodeCore/Runtime/RuntimeNode.cs
+++ b/TNodeCore/Runtime/RuntimeNode.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Codice.Client.Common.TreeGrouper;
+using TNodeCore.Attribute.Ports;
using TNodeCore.Models;
using TNodeCore.RuntimeCache;
@@ -11,7 +12,8 @@ namespace TNodeCore.Runtime{
public List InputLink;
//the link connect to node's out port
public List OutputLink;
- public Type type;
+ //Cache node data type for fast access
+ private readonly Type _type;
public void SetInput(string portName,object value){
@@ -20,11 +22,36 @@ namespace TNodeCore.Runtime{
public object GetOutput(string portName){
return NodeData.GetValue(portName);
}
-
+
+
+
+ private Dictionary _inputPorts = new();
+ private Dictionary _outputPorts = new();
+
+
+ private void CachingPorts(){
+ var properties = _type.GetProperties();
+ foreach (var propertyInfo in properties){
+ //Check if the property is a port
+ var attribute = propertyInfo.GetCustomAttributes(typeof(InputAttribute),true);
+ if (attribute.Length > 0){
+
+ _inputPorts.Add(propertyInfo.Name,NodeData.CacheSetProperty(propertyInfo.Name));
+ }
+
+ attribute = propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true);
+ if (attribute.Length > 0){
+ _outputPorts.Add(propertyInfo.Name,NodeData.CacheGetProperty(propertyInfo.Name));
+ }
+ }
+ }
public RuntimeNode(NodeData nodeData){
NodeData = nodeData;
//Caching the type of the node
- type = nodeData.GetType();
+ _type = nodeData.GetType();
+ var info = nodeData.GetType().GetProperties();
+
+ CachingPorts();
}
public List GetInputNodesId(){
List dependencies = new List();
diff --git a/TNodeCore/RuntimeCache/RuntimeCache.cs b/TNodeCore/RuntimeCache/RuntimeCache.cs
index d3a1a79..dfd88e8 100644
--- a/TNodeCore/RuntimeCache/RuntimeCache.cs
+++ b/TNodeCore/RuntimeCache/RuntimeCache.cs
@@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using PlasticPipe.PlasticProtocol.Messages;
using TNodeCore.Attribute;
using TNodeCore.Models;
+using UnityEngine;
namespace TNodeCore.RuntimeCache{
public class RuntimeCache{
@@ -14,12 +16,19 @@ namespace TNodeCore.RuntimeCache{
}
//delegate return a value from a nodedata
public delegate object GetValueDelegate(IModel nodeData);
- public delegate void SetValueDelegate(object nodeData,object value);
+ public delegate void SetValueDelegate(IModel nodeData,object value);
+
+ public delegate object GetPropertyValueDelegate();
+ public delegate void SetPropertyValueDelegate(object value);
public readonly Dictionary> CachedDelegatesForGettingValue =
new ();
public readonly Dictionary> CachedDelegatesForSettingValue =
new ();
+ public readonly Dictionary> CachedDelegatesForGettingPropertyValue =
+ new ();
+ public readonly Dictionary> CachedDelegatesForSettingPropertyValue =
+ new ();
private readonly Dictionary _graphBlackboardDictionary = new Dictionary();
@@ -84,16 +93,16 @@ namespace TNodeCore.RuntimeCache{
CachedDelegatesForGettingValue.Add(type, new Dictionary());
CachedDelegatesForSettingValue.Add(type,new Dictionary());
- var properties = type.GetProperties();
- foreach(var property in properties){
- //if the property only has a setter ,skip
-
- var getValueDelegate = GetValueDelegateForProperty(property);
- CachedDelegatesForGettingValue[type].Add(property.Name,getValueDelegate);
-
- var setValueDelegate = SetValueDelegateForProperty(property);
- CachedDelegatesForSettingValue[type].Add(property.Name,setValueDelegate);
- }
+ // var properties = type.GetProperties();
+ // foreach(var property in properties){
+ // //if the property only has a setter ,skip
+ //
+ // var getValueDelegate = GetValueDelegateForProperty(property);
+ // CachedDelegatesForGettingValue[type].Add(property.Name,getValueDelegate);
+ //
+ // var setValueDelegate = SetValueDelegateForProperty(property);
+ // CachedDelegatesForSettingValue[type].Add(property.Name,setValueDelegate);
+ // }
//register the fields
var fields = type.GetFields();
foreach(var field in fields){
@@ -111,19 +120,21 @@ namespace TNodeCore.RuntimeCache{
if(!CachedDelegatesForGettingValue.ContainsKey(type)){
CachedDelegatesForGettingValue.Add(type, new Dictionary());
CachedDelegatesForSettingValue.Add(type,new Dictionary());
+
+
var properties = type.GetProperties();
foreach(var property in properties){
//if the property only has a setter ,skip
- if(property.SetMethod != null){
- var setValueDelegate = SetValueDelegateForProperty(property);
- CachedDelegatesForSettingValue[type].Add(property.Name,setValueDelegate);
- }
- if(property.GetMethod != null){
- var getValueDelegate = GetValueDelegateForProperty(property);
- CachedDelegatesForGettingValue[type].Add(property.Name,getValueDelegate);
- }
-
+ // if(property.GetSetMethod(false) != null){
+ // var setValueDelegate = SetValueDelegateForProperty(property);
+ // CachedDelegatesForSettingPropertyValue[type].Add(property.Name,setValueDelegate);
+ // }
+ // if(property.GetMethod != null){
+ // var getValueDelegate = GetValueDelegateForProperty(property);
+ // CachedDelegatesForGettingPropertyValue[type].Add(property.Name,getValueDelegate);
+ // }
+
}
@@ -142,17 +153,21 @@ namespace TNodeCore.RuntimeCache{
}
}
private GetValueDelegate GetValueDelegateForField(FieldInfo field){
+
return field.GetValue;
}
private SetValueDelegate SetValueDelegateForField(FieldInfo field){
+
return field.SetValue;
}
- private GetValueDelegate GetValueDelegateForProperty(PropertyInfo property){
- var getValueDelegate = (GetValueDelegate)Delegate.CreateDelegate(typeof(GetValueDelegate), property.GetGetMethod());
+ private GetPropertyValueDelegate GetValueDelegateForProperty(PropertyInfo property){
+ var getValueDelegate = (GetPropertyValueDelegate)Delegate.CreateDelegate(typeof(GetPropertyValueDelegate), property.GetGetMethod());
return getValueDelegate;
}
- private SetValueDelegate SetValueDelegateForProperty(PropertyInfo property){
- var setValueDelegate = (SetValueDelegate)Delegate.CreateDelegate(typeof(SetValueDelegate), property.GetSetMethod());
+ private SetPropertyValueDelegate SetValueDelegateForProperty(PropertyInfo property){
+ Debug.Log(property.GetSetMethod());
+
+ var setValueDelegate = (SetPropertyValueDelegate)Delegate.CreateDelegate(typeof(SetPropertyValueDelegate), property.GetSetMethod());
return setValueDelegate;
}
@@ -177,12 +192,46 @@ namespace TNodeCore.RuntimeCache{
var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path];
method.Invoke(data,value);
}
+
public static RuntimeCache.GetValueDelegate GetValueDelegate(this IModel blackboardData,string path){
var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[blackboardData.GetType()][path];
return method;
}
+ ///
+ /// it generate a delegate that can get the value fast,but it won't cache in runtime cache system,you should put it in somewhere you need
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static RuntimeCache.GetPropertyValueDelegate CacheGetProperty(this IModel data,string path){
+ var type = data.GetType();
+ var property = type.GetProperty(path);
+ if (property == null) throw new PropertyNotFoundException(path);
+ var instance = Delegate.CreateDelegate(typeof(RuntimeCache.GetPropertyValueDelegate), data,
+ property.GetGetMethod());
+ return instance as RuntimeCache.GetPropertyValueDelegate;
+ }
+ ///
+ /// it generate a delegate that can get the value fast,but it won't cache in runtime cache system,you should put it in somewhere you need
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static RuntimeCache.SetPropertyValueDelegate CacheSetProperty(this IModel data,string path){
+ var type = data.GetType();
+ var property = type.GetProperty(path);
+ if (property == null) throw new PropertyNotFoundException(path);
+ var instance = Delegate.CreateDelegate(typeof(RuntimeCache.SetPropertyValueDelegate), data,
+ property.GetSetMethod());
+ return instance as RuntimeCache.SetPropertyValueDelegate;
+ }
+ }
-
-
+ public class PropertyNotFoundException : Exception{
+ public PropertyNotFoundException(string path):base("Property not found :"+path){
+
+ }
}
}
\ No newline at end of file
diff --git a/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs b/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
index 8d44a8c..702151d 100644
--- a/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
+++ b/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
@@ -1,7 +1,9 @@
using System.Reflection;
using TNodeCore.Attribute;
+using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Editor.Serialization;
using TNodeCore.Models;
+using TNodeGraphViewImpl.Editor.NodeViews;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
@@ -36,9 +38,7 @@ namespace TNode.Editor.Inspector{
RefreshPropertyDrawer();
}
- private void CreateTestButton(){
-
- }
+
private void RefreshPropertyDrawer(){
//Check if the data's type is a generic type of BlackboardDragNodeData<>
if (_data.GetType().IsSubclassOf(typeof(BlackboardDragNodeData))){
@@ -57,16 +57,33 @@ namespace TNode.Editor.Inspector{
}
- if (_data.isTest){
+ var globalTest = GetFirstAncestorOfType()?.BaseDataGraphView?.TestMode;
+ if(globalTest??false){
+ CreateTestButton();
+ }
+ else if (_data.isTest){
//Add a test button for the node
- var testButton = new Button(()=>{
- Debug.Log("Test button clicked");
- });
- testButton.text = "Test";
- _data.OnTest();
- Add(testButton);
+ CreateTestButton();
}
}
-
+
+ private void CreateTestButton(){
+ var testButton = new Button(() => {
+ var test = GetFirstAncestorOfType();
+ if (test != null){
+ if(!test.IsRuntimeGraph) return;
+ var runtimeGraph = test.GetRuntimeGraph();
+ if (runtimeGraph != null){
+ runtimeGraph.ResolveDependency(_data);
+ }
+ _data.OnTest();
+ }
+ }){
+ text = "Test"
+ };
+
+ Add(testButton);
+
+ }
}
}
\ No newline at end of file
diff --git a/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs b/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
index e23b499..f07e68c 100644
--- a/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
+++ b/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
@@ -12,13 +12,13 @@ using TNodeCore.Runtime;
using TNodeGraphViewImpl.Editor.Cache;
using TNodeGraphViewImpl.Editor.GraphBlackboard;
using TNodeGraphViewImpl.Editor.NodeViews;
-
using UnityEditor;
using UnityEditor.Experimental.GraphView;
-using UnityEditor.VersionControl;
using UnityEngine;
using UnityEngine.UIElements;
+
+
using Edge = UnityEditor.Experimental.GraphView.Edge;
namespace TNodeGraphViewImpl.Editor.NodeGraphView{
@@ -65,7 +65,7 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale);
RegisterDragEvent();
OnInit();
- CheckAfterInit();
+
}
///
/// Probably reusable in later GTFs version
@@ -144,7 +144,7 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
}
};
}
- private void CheckAfterInit(){
+ private void CheckDataAfterInit(){
if(Data == null){
WaitingForAGraph();
}
@@ -173,7 +173,39 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
private void OnInit(){
ConstructDefaultBehaviour();
OnGraphViewCreate();
+ CheckDataAfterInit();
}
+
+ protected void CreateMenu(){
+ var visualElement = new VisualElement{
+ name = "TopMenu"
+ };
+ visualElement.style.position = Position.Absolute;
+ visualElement.style.top = 0;
+ visualElement.style.backgroundColor = new StyleColor(new Color(0.1f, 0.1f, 0.1f, 1));
+ Add(visualElement);
+ visualElement.style.flexDirection = FlexDirection.Row;
+
+
+ //Add a toggle button to toggle test mode
+ var testModeToggle = new Toggle{
+ name = "TestModeToggle",
+ label = "Test Mode",
+ value = false
+ };
+ testModeToggle.RegisterValueChangedCallback(evt => {
+ if (evt.newValue){
+ TestMode = true;
+ }
+ else{
+ TestMode = false;
+ }
+ });
+ visualElement.Add(testModeToggle);
+
+
+ }
+
public void RegisterDragEvent(){
RegisterCallback(OnDragUpdated);
RegisterCallback(OnDragPerform);
@@ -437,6 +469,8 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
Owner.graphEditorData.graphElementsData.RemoveAll(x => x.guid == nodeData.id);
}
+ public bool TestMode{ get; set; }
+
public void CreateBlackboard(){
_blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T));
_blackboard.Setup(this,Owner);
@@ -463,6 +497,10 @@ namespace TNodeGraphViewImpl.Editor.NodeGraphView{
public bool IsRuntimeGraph{ get; set; }
+ public RuntimeGraph GetRuntimeGraph(){
+ return _runtimeGraph;
+ }
+
public void SetGraphData(GraphData graph){
Data = graph as T;
}
diff --git a/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs b/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
index fe6a69e..5a9c81e 100644
--- a/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
+++ b/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
@@ -4,6 +4,7 @@ using System.Reflection;
using TNode.Editor.Inspector;
using TNodeCore;
using TNodeCore.Attribute.Ports;
+using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Editor.Serialization;
using TNodeCore.Models;
using UnityEditor.Experimental.GraphView;
@@ -15,7 +16,13 @@ namespace TNodeGraphViewImpl.Editor.NodeViews{
public abstract class BaseNodeView : Node,INodeView where T:NodeData,new(){
protected T _data;
private readonly NodeInspectorInNode _nodeInspectorInNode;
-
+
+ public IBaseDataGraphView BaseDataGraphView{
+ get{
+ var visualElement = this.GetFirstAncestorOfType() as IBaseDataGraphView;
+ return visualElement;
+ }
+ }
public T Data{
get => _data;
set{
@@ -180,6 +187,7 @@ namespace TNodeGraphViewImpl.Editor.NodeViews{
public NodeData GetNodeData();
public void OnDataModified();
+ IBaseDataGraphView BaseDataGraphView{ get; }
}
public interface INodeView:IBaseNodeView where T:NodeData,new(){