Merge pull request #35 from taoria/working-in-process

Working in process
main
taoria 3 years ago committed by GitHub
commit f3b2268cd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      README.md
  2. 4
      TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs
  3. 9
      TNode/TNodeCore/Editor/NodeGraphView/IBaseDataGraphView.cs
  4. 2
      TNode/TNodeCore/Runtime/Attributes/GraphUsageAttribute.cs
  5. 6
      TNode/TNodeCore/Runtime/Attributes/HideInBlackboard.cs
  6. 3
      TNode/TNodeCore/Runtime/Attributes/HideInBlackboard.cs.meta
  7. 5
      TNode/TNodeCore/Runtime/Attributes/ModelColor.cs
  8. 3
      TNode/TNodeCore/Runtime/Attributes/ModelColor.cs.meta
  9. 3
      TNode/TNodeCore/Runtime/Attributes/Ports/InputAttribute.cs
  10. 8
      TNode/TNodeCore/Runtime/Attributes/Ports/OutputAttribute.cs
  11. 8
      TNode/TNodeCore/Runtime/Attributes/Ports/PortAttribute.cs
  12. 10
      TNode/TNodeCore/Runtime/Models/BlackboardData.cs
  13. 7
      TNode/TNodeCore/Runtime/Models/IModel.cs
  14. 19
      TNode/TNodeCore/Runtime/Models/Model.cs
  15. 0
      TNode/TNodeCore/Runtime/Models/Model.cs.meta
  16. 7
      TNode/TNodeCore/Runtime/Models/NodeData.cs
  17. 21
      TNode/TNodeCore/Runtime/NodeLogger.cs
  18. 3
      TNode/TNodeCore/Runtime/NodeLogger.cs.meta
  19. 14
      TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs
  20. 2
      TNode/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs
  21. 4
      TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs
  22. 2
      TNode/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
  23. 161
      TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
  24. 53
      TNode/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
  25. 3
      TNode/TNodeGtfImpl/Editor.meta

@ -1,10 +1,10 @@
# T-Node # T-Node
Node graph creation tool based on unity experimental graphview and if possible latter,GTF. Node graph creation tool based on 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 of the repo is to make graph creation easier and more intuitive.
Note **it's not usable and productive on current stage** and need a better Note **it's not usable and productive on current stage** and need a better
development . development .
and it's mainly for my own use now.
The tool separate its graph editor implementation and the graph creation logic. The tool separate its graph editor implementation and the graph creation logic.
@ -12,25 +12,24 @@ The tool separate its graph editor implementation and the graph creation logic.
currently under development currently under development
# Main Features # Some Features
* Create graph script by the creator tool * Create graph script a the creator tool
* Node creation based on specified type of graph * Node creation based on specified type of graph
* Easy port creation via attribute * Easy port creation via attribute
* Runtime graph * Runtime graph
* Blackboard for runtime graph as exposed parameters * Blackboard for runtime graph as exposed parameters
* Runtime graph execution * Runtime graph execution
* An easy test mode (Runtime graph only) * An easy test mode (Runtime graph only)
* Scene object nodes hold scene objects
# Some To-dos # Some To-dos
* Caching runtime state for faster execution
* Undo redo support
* Function as port * Function as port
* Better blackboard support * Circular dependency support for some situations such as FSM
* Edge colors customization
# Usage # Usage
No ,It's better not to use TNode at current stage until it's stable. Not yet documented
### Convention ### Convention

@ -3,6 +3,7 @@ using System.Collections.Generic;
using TNodeCore.Editor.NodeGraphView; using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
namespace TNodeCore.Editor.EditorPersistence{ namespace TNodeCore.Editor.EditorPersistence{
@ -14,7 +15,8 @@ namespace TNodeCore.Editor.EditorPersistence{
public GraphImplType graphImplType = GraphImplType.GraphViewImpl; public GraphImplType graphImplType = GraphImplType.GraphViewImpl;
public static Func<Type,IBaseDataGraphView> GraphViewImplCreator; public static Func<Type,IBaseDataGraphView> GraphViewImplCreator;
public static Func<Type,IBaseDataGraphView> GtfImplCreator; public static Func<Type,IBaseDataGraphView> GtfImplCreator;
[FormerlySerializedAs("testMode")] public bool autoUpdate;
public IDataGraphView<T> GetGraphView<T> () where T:GraphData{ public IDataGraphView<T> GetGraphView<T> () where T:GraphData{
switch (graphImplType){ switch (graphImplType){
case GraphImplType.GraphViewImpl:{ case GraphImplType.GraphViewImpl:{

@ -14,7 +14,7 @@ namespace TNodeCore.Editor.NodeGraphView{
public void RemoveLink(NodeLink nodeLink); public void RemoveLink(NodeLink nodeLink);
public bool TestMode{ get; set; } public bool AutoUpdate{ get; set; }
public void CreateBlackboard(); public void CreateBlackboard();
public GraphData GetGraphData(); public GraphData GetGraphData();
public BlackboardData GetBlackboardData(); public BlackboardData GetBlackboardData();
@ -30,9 +30,12 @@ namespace TNodeCore.Editor.NodeGraphView{
public void SetGraphData(GraphData graph); public void SetGraphData(GraphData graph);
void NotifyRuntimeUpdate();
public Action AfterRuntimeGraphUpdate{ get; set; } public Action AfterGraphResolved{ get; set; }
void AfterEditorLoadGraphView(); void AfterEditorLoadGraphView();
//todo remove it later ,keep it now
void NotifyRuntimeUpdate();
} }
} }

@ -4,7 +4,7 @@ using TNodeCore.Runtime.Models;
namespace TNodeCore.Runtime.Attributes{ namespace TNodeCore.Runtime.Attributes{
/// <summary> /// <summary>
/// Use this attribute to claim the usage of a type derived IModel IModel /// Use this attribute to claim the usage of a type derived Model Model
/// it can be applied to the same node multiple times. /// it can be applied to the same node multiple times.
/// <example> /// <example>
/// [GraphUsage(DialogueGraph)] /// [GraphUsage(DialogueGraph)]

@ -0,0 +1,6 @@
namespace TNodeCore.Runtime.Attributes{
public class HideInBlackboard:System.Attribute{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 731893f9f7824b939cee169d61092ad3
timeCreated: 1659517588

@ -0,0 +1,5 @@
namespace TNodeCore.Runtime.Attributes{
public class ModelColor{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cdec5767969f4e11bbcfb245693796f9
timeCreated: 1659521617

@ -1,5 +1,6 @@
using System; using System;
using JetBrains.Annotations; using JetBrains.Annotations;
using UnityEngine;
namespace TNodeCore.Runtime.Attributes.Ports{ namespace TNodeCore.Runtime.Attributes.Ports{
[MeansImplicitUse] [MeansImplicitUse]
@ -7,5 +8,7 @@ namespace TNodeCore.Runtime.Attributes.Ports{
public class InputAttribute : PortAttribute{ public class InputAttribute : PortAttribute{
public InputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared) : base(name, nameHandling,typeHandling){ public InputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared) : base(name, nameHandling,typeHandling){
} }
public InputAttribute(Color color):base(color){
}
} }
} }

@ -1,8 +1,14 @@
namespace TNodeCore.Runtime.Attributes.Ports{ using UnityEngine;
namespace TNodeCore.Runtime.Attributes.Ports{
public class OutputAttribute:PortAttribute{ public class OutputAttribute:PortAttribute{
public OutputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling = TypeHandling.Declared) : base(name, nameHandling,typeHandling){ public OutputAttribute(string name="", PortNameHandling nameHandling = PortNameHandling.Auto,TypeHandling typeHandling = TypeHandling.Declared) : base(name, nameHandling,typeHandling){
} }
public OutputAttribute(Color color):base(color){
}
} }
} }

@ -1,6 +1,8 @@
using System; using System;
using UnityEngine;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace TNodeCore.Runtime.Attributes.Ports{ namespace TNodeCore.Runtime.Attributes.Ports{
public enum PortNameHandling{ public enum PortNameHandling{
@ -23,6 +25,7 @@ namespace TNodeCore.Runtime.Attributes.Ports{
public readonly PortNameHandling NameHandling; public readonly PortNameHandling NameHandling;
public Type HandledType; public Type HandledType;
public bool Multiple = true; public bool Multiple = true;
public Color PortColor = Color.black;
public TypeHandling TypeHandling{ get; set; } public TypeHandling TypeHandling{ get; set; }
public PortAttribute(string name,PortNameHandling nameHandling=PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared){ public PortAttribute(string name,PortNameHandling nameHandling=PortNameHandling.Auto,TypeHandling typeHandling=TypeHandling.Declared){
this.Name = name; this.Name = name;
@ -30,6 +33,11 @@ namespace TNodeCore.Runtime.Attributes.Ports{
this.TypeHandling = typeHandling; this.TypeHandling = typeHandling;
} }
public PortAttribute(Color color):this("",PortNameHandling.Auto,TypeHandling.Declared){
PortColor = color;
}
} }
} }

@ -1,4 +1,5 @@
using System; using System;
using UnityEngine;
namespace TNodeCore.Runtime.Models{ namespace TNodeCore.Runtime.Models{
/// <summary> /// <summary>
@ -6,11 +7,10 @@ namespace TNodeCore.Runtime.Models{
/// </summary> /// </summary>
[Serializable] [Serializable]
public class BlackboardData:IModel,ICloneable{ public class BlackboardData:Model,ICloneable{
public object Clone(){
return this.MemberwiseClone();
}
} }
} }

@ -1,7 +0,0 @@
using System;
namespace TNodeCore.Runtime.Models{
public interface IModel:ICloneable{
}
}

@ -0,0 +1,19 @@
using System;
using TNodeCore.Runtime.Attributes;
using UnityEngine;
using UnityEngine.Serialization;
namespace TNodeCore.Runtime.Models{
[Serializable]
public abstract class Model:ICloneable{
#if UNITY_EDITOR
[HideInBlackboard]
public Rect positionInView;
#endif
public object Clone(){
var memberwiseClone = this.MemberwiseClone();
return memberwiseClone;
}
}
}

@ -12,7 +12,7 @@ namespace TNodeCore.Runtime.Models{
/// ///
/// </summary> /// </summary>
[Serializable] [Serializable]
public class NodeData:IModel{ public class NodeData:Model{
public NodeData() : base(){ public NodeData() : base(){
//Object Registration //Object Registration
@ -37,8 +37,7 @@ namespace TNodeCore.Runtime.Models{
} }
#endif #endif
public object Clone(){
return this.MemberwiseClone();
}
} }
} }

@ -0,0 +1,21 @@
using System.Collections.Generic;
using TNodeCore.Runtime.Models;
using UnityEngine;
namespace TNodeCore.Runtime{
public static class NodeLogger{
public static Dictionary<string, INodeLoggerImpl> Loggers = new ();
public static void Log(this NodeData t,string message){
if (!Loggers.ContainsKey(t.id)) return;
var nodeLoggerImpl = Loggers[t.id];
nodeLoggerImpl.Log(message);
Debug.Log(message);
}
}
public interface INodeLoggerImpl{
public void Log(string message);
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 48be07a2cf064167b15d378ac41757c4
timeCreated: 1659592209

@ -64,8 +64,8 @@ namespace TNodeCore.Runtime.RuntimeCache{
get{ return _instance ??= new RuntimeCache(); } get{ return _instance ??= new RuntimeCache(); }
} }
//delegate return a value from a nodedata //delegate return a value from a nodedata
public delegate object GetValueDelegate(IModel nodeData); public delegate object GetValueDelegate(Model nodeData);
public delegate void SetValueDelegate(IModel nodeData,object value); public delegate void SetValueDelegate(Model nodeData,object value);
@ -258,11 +258,11 @@ namespace TNodeCore.Runtime.RuntimeCache{
public static class RuntimeExtension{ public static class RuntimeExtension{
//todo latter on i will try some way caching reflection more efficiently //todo latter on i will try some way caching reflection more efficiently
public static T GetValue<T>(this IModel data,string path,Type type=null){ public static T GetValue<T>(this Model data,string path,Type type=null){
var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[type??data.GetType()][path]; var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[type??data.GetType()][path];
return (T) method.Invoke(data); return (T) method.Invoke(data);
} }
public static object GetValue(this IModel data, string path,Type type=null){ public static object GetValue(this Model data, string path,Type type=null){
if(!RuntimeCache.Instance.CachedDelegatesForGettingValue.ContainsKey(type??data.GetType())){ if(!RuntimeCache.Instance.CachedDelegatesForGettingValue.ContainsKey(type??data.GetType())){
return null; return null;
} }
@ -270,7 +270,7 @@ namespace TNodeCore.Runtime.RuntimeCache{
var method = dic.ContainsKey(path) ? dic[path] : null; var method = dic.ContainsKey(path) ? dic[path] : null;
return method?.Invoke(data); return method?.Invoke(data);
} }
public static object GetListValue(this IModel data,string path,int index,Type type=null){ public static object GetListValue(this Model data,string path,int index,Type type=null){
if(!RuntimeCache.Instance.CachedDelegatesForGettingValue.ContainsKey(type??data.GetType())){ if(!RuntimeCache.Instance.CachedDelegatesForGettingValue.ContainsKey(type??data.GetType())){
return null; return null;
} }
@ -286,11 +286,11 @@ namespace TNodeCore.Runtime.RuntimeCache{
return list[index]; return list[index];
} }
public static void SetValue<T>(this IModel data,string path,T value,Type type=null){ public static void SetValue<T>(this Model data,string path,T value,Type type=null){
var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path]; var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path];
method.Invoke(data,value); method.Invoke(data,value);
} }
public static void SetValue(this IModel data,string path,object value,Type type=null){ public static void SetValue(this Model data,string path,object value,Type type=null){
var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path]; var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path];
method.Invoke(data,value); method.Invoke(data,value);
} }

@ -89,7 +89,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
private void SetGraphUsageAttribute(Type type){ private void SetGraphUsageAttribute(Type type){
foreach (var attribute in type.GetCustomAttributes(typeof(GraphUsageAttribute), true)){ foreach (var attribute in type.GetCustomAttributes(typeof(GraphUsageAttribute), true)){
var parent = type.BaseType; var parent = type.BaseType;
if (typeof(IModel).IsAssignableFrom(type.BaseType)){ if (typeof(Model).IsAssignableFrom(type.BaseType)){
//Check if GraphDataUsage dictionary has GraphDataType of attribute //Check if GraphDataUsage dictionary has GraphDataType of attribute
if (typeof(NodeData).IsAssignableFrom(type)){ if (typeof(NodeData).IsAssignableFrom(type)){

@ -6,6 +6,7 @@ using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Editor.Serialization; using TNodeCore.Editor.Serialization;
using TNodeCore.Runtime.Attributes; using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using Unity.VisualScripting;
using UnityEditor; using UnityEditor;
using UnityEditor.Experimental.GraphView; using UnityEditor.Experimental.GraphView;
using UnityEditor.UIElements; using UnityEditor.UIElements;
@ -22,8 +23,8 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
} }
protected override void UpdateBlackboard(BlackboardData data){ protected override void UpdateBlackboard(BlackboardData data){
Clear();
if (data == null) return; if (data == null) return;
this.Clear();
var serializedObject = new SerializedObject((BlackboardDataWrapper)data); var serializedObject = new SerializedObject((BlackboardDataWrapper)data);
var currentGraphView = graphView as IBaseDataGraphView; var currentGraphView = graphView as IBaseDataGraphView;
var isRuntimeGraph = currentGraphView?.IsRuntimeGraph ?? false; var isRuntimeGraph = currentGraphView?.IsRuntimeGraph ?? false;
@ -33,6 +34,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
Add(blackboardGlobalSection); Add(blackboardGlobalSection);
foreach (var field in data.GetType() foreach (var field in data.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)){ .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)){
if(field.HasAttribute(typeof(HideInBlackboard))) continue;
//if the field is MonoBehaviour,add a property field for blackboard //if the field is MonoBehaviour,add a property field for blackboard
//skip if the field is a list or Ilist //skip if the field is a list or Ilist
if (!typeof(IList).IsAssignableFrom(field.FieldType)&&!field.FieldType.IsArray){ if (!typeof(IList).IsAssignableFrom(field.FieldType)&&!field.FieldType.IsArray){

@ -67,7 +67,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.Inspector{
Add(drawer); Add(drawer);
} }
var globalTest = GetFirstAncestorOfType<IBaseDataGraphView>()?.TestMode; var globalTest = GetFirstAncestorOfType<IBaseDataGraphView>()?.AutoUpdate;
if(globalTest??false){ if(globalTest??false){
CreateTestButton(); CreateTestButton();
} }

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using TNode.TNodeGraphViewImpl.Editor.Cache; using TNode.TNodeGraphViewImpl.Editor.Cache;
using TNode.TNodeGraphViewImpl.Editor.GraphBlackboard; using TNode.TNodeGraphViewImpl.Editor.GraphBlackboard;
using TNode.TNodeGraphViewImpl.Editor.Inspector; using TNode.TNodeGraphViewImpl.Editor.Inspector;
@ -16,6 +17,7 @@ using TNodeCore.Editor.Tools.NodeCreator;
using TNodeCore.Runtime.Components; using TNodeCore.Runtime.Components;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using TNodeCore.Runtime.RuntimeCache; using TNodeCore.Runtime.RuntimeCache;
using Unity.VisualScripting;
using UnityEditor; using UnityEditor;
using UnityEditor.Experimental.GraphView; using UnityEditor.Experimental.GraphView;
using UnityEngine; using UnityEngine;
@ -25,16 +27,18 @@ using Edge = UnityEditor.Experimental.GraphView.Edge;
namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
public class BaseDataGraphView<T>:GraphView,IDataGraphView<T> where T:GraphData{ public class BaseDataGraphView<T>:GraphView,IDataGraphView<T> where T:GraphData{
#region const
public const float RefreshRate = 1f;
#endregion
#region variables and properties #region variables and properties
private T _data; private T _data;
private RuntimeGraph _runtimeGraph; private RuntimeGraph _runtimeGraph;
private bool _isInspectorOn; private bool _isInspectorOn;
private NodeSearchWindowProvider _nodeSearchWindowProvider; private NodeSearchWindowProvider _nodeSearchWindowProvider;
private NodeInspector _nodeInspector; private NodeInspector _nodeInspector;
private Dictionary<string,Node> _nodeDict = new(); private Dictionary<string,Node> _nodeDict = new();
private IBlackboardView _blackboard; private IBlackboardView _blackboard;
private bool _runtimeGraphUpdate; private bool _loaded;
public T Data{ public T Data{
get{ return _data; } get{ return _data; }
set{ set{
@ -98,15 +102,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
var res = DragAndDrop.objectReferences; var res = DragAndDrop.objectReferences;
foreach (var obj in res){ foreach (var obj in res){
if (obj is T graphData){ if (obj is T graphData){
Data = graphData;
IsRuntimeGraph = false; IsRuntimeGraph = false;
Data = graphData;
} }
else{ else{
if (obj is GameObject gameObject){ if (obj is GameObject gameObject){
if (gameObject.GetComponent<RuntimeGraph>() != null){ if (gameObject.GetComponent<RuntimeGraph>() != null){
if (gameObject.GetComponent<RuntimeGraph>().graphData != null){ if (gameObject.GetComponent<RuntimeGraph>().graphData != null){
_runtimeGraph = gameObject.GetComponent<RuntimeGraph>(); _runtimeGraph = gameObject.GetComponent<RuntimeGraph>();
IsRuntimeGraph = true; IsRuntimeGraph = true;
BuildRuntimeGraphBehaviour(); BuildRuntimeGraphBehaviour();
@ -114,7 +117,6 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
if(Data==null){ if(Data==null){
Debug.LogError($"Dragged a wrong graph data to editor,expected {typeof(T)} but got {gameObject.GetComponent<RuntimeGraph>().graphData.GetType()}"); Debug.LogError($"Dragged a wrong graph data to editor,expected {typeof(T)} but got {gameObject.GetComponent<RuntimeGraph>().graphData.GetType()}");
} }
} }
} }
} }
@ -147,25 +149,36 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
private void BuildRuntimeGraphBehaviour(){ private void BuildRuntimeGraphBehaviour(){
EditorApplication.update+= UpdateRuntimeGraphBehaviour; //EditorApplication.update+= UpdateRuntimeGraphBehaviour;
UpdateRuntimeGraphBehaviourInTime();
} }
private void UpdateRuntimeGraphBehaviour(){ private async void UpdateRuntimeGraphBehaviourInTime(){
if(_runtimeGraph != null){
if (_runtimeGraphUpdate){ while (_loaded){
_runtimeGraphUpdate = false; await Task.Delay(TimeSpan.FromSeconds(RefreshRate));
_runtimeGraph.ResolveDependency(); if(_runtimeGraph != null){
if (AutoUpdate){
AfterRuntimeGraphUpdate?.Invoke(); _runtimeGraph.ResolveDependency();
AfterGraphResolved?.Invoke();
}
} }
}
else{
EditorApplication.update -= UpdateRuntimeGraphBehaviour;
} }
} }
// private void UpdateRuntimeGraphBehaviour(){
// if(_runtimeGraph != null){
// if (_runtimeGraphUpdate){
// _runtimeGraphUpdate = false;
// _runtimeGraph.ResolveDependency();
//
// AfterGraphResolved?.Invoke();
// }
// }
// else{
// EditorApplication.update -= UpdateRuntimeGraphBehaviour;
// }
// }
private void CheckDataAfterInit(){ private void CheckDataAfterInit(){
if(Data == null){ if(Data == null){
@ -201,6 +214,18 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
OnGraphViewCreate(); OnGraphViewCreate();
BuildUndo(); BuildUndo();
_loaded = true;
SetDetachedFromPanel();
}
private void SetDetachedFromPanel(){
this.RegisterCallback<DetachFromPanelEvent>(evt => {
_loaded = false;
});
} }
private void BuildUndo(){ private void BuildUndo(){
@ -227,22 +252,32 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
//Add a toggle button to toggle test mode //Add a toggle button to toggle test mode
var testModeToggle = new Toggle{ var autoUpdateToggle = new Toggle{
name = "TestModeToggle", name = "TestModeToggle",
label = "Test Mode", label = "Test Mode",
value = false value = AutoUpdate
}; };
testModeToggle.RegisterValueChangedCallback(evt => { autoUpdateToggle.RegisterValueChangedCallback(evt => {
if (evt.newValue){ if (evt.newValue){
TestMode = true; AutoUpdate = true;
} }
else{ else{
TestMode = false; AutoUpdate = false;
} }
}); });
visualElement.Add(testModeToggle); visualElement.Add(autoUpdateToggle);
var runButton = new Button{
name = "RunButton",
text = "Run Once"
};
runButton.RegisterCallback<ClickEvent>(evt => {
if (IsRuntimeGraph){
_runtimeGraph.ResolveDependency();
AfterGraphResolved?.Invoke();
}
});
visualElement.Add(runButton);
} }
public void RegisterDragEvent(){ public void RegisterDragEvent(){
@ -341,8 +376,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
private void AddPersistentNode(NodeData dataNode){ private void AddPersistentNode(NodeData dataNode){
var nodePos = Owner.graphEditorData.graphElementsData.FirstOrDefault(x => x.guid == dataNode.id)?.pos ?? var nodePos = dataNode.positionInView;
new Rect(0, 0, 200, 200);
AddTNode(dataNode, nodePos); AddTNode(dataNode, nodePos);
} }
//OnDataChanged event //OnDataChanged event
@ -391,21 +425,21 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
public void SaveEditorData(GraphEditorData graphEditorData){ public void SaveEditorData(GraphEditorData graphEditorData){
graphEditorData.graphElementsData?.Clear(); // graphEditorData.graphElementsData?.Clear();
//iterator nodes // //iterator nodes
if (graphEditorData.graphElementsData == null){ // if (graphEditorData.graphElementsData == null){
graphEditorData.graphElementsData = new List<GraphElementEditorData>(); // graphEditorData.graphElementsData = new List<GraphElementEditorData>();
} // }
foreach (var node in this.nodes){ // foreach (var node in this.nodes){
var nodeEditorData = new GraphElementEditorData{ // var nodeEditorData = new GraphElementEditorData{
pos = node.GetPosition(), // pos = node.GetPosition(),
}; // };
if (node is IBaseNodeView nodeView){ // if (node is IBaseNodeView nodeView){
nodeEditorData.guid = nodeView.GetNodeData().id; // nodeEditorData.guid = nodeView.GetNodeData().id;
} // }
graphEditorData.graphElementsData.Add(nodeEditorData); // graphEditorData.graphElementsData.Add(nodeEditorData);
EditorUtility.SetDirty(graphEditorData); // EditorUtility.SetDirty(graphEditorData);
} // }
} }
public void SaveWithEditorData(GraphEditorData graphEditorData){ public void SaveWithEditorData(GraphEditorData graphEditorData){
@ -499,8 +533,15 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
#region implement interfaces #region implement interfaces
public void AddTNode(NodeData nodeData, Rect rect){ public void AddTNode(NodeData nodeData, Rect rect){
if (NodeEditorExtensions.CreateNodeViewFromNodeType(nodeData.GetType()) is Node nodeView){ if (NodeEditorExtensions.CreateNodeViewFromNodeType(nodeData.GetType()) is Node nodeView){
nodeView.SetPosition(rect); //convert rect at graph space
var resPos = this.viewTransform.matrix.inverse.MultiplyPoint3x4(rect.position);
rect.position = resPos;
if(nodeView is IBaseNodeView nodeViewInterface){
nodeViewInterface.SetNodeData(nodeData);
}
AddElement(nodeView); AddElement(nodeView);
((IBaseNodeView)nodeView).InitializePosition(rect);
//Add a select callback to the nodeView //Add a select callback to the nodeView
nodeView.RegisterCallback<MouseDownEvent>(evt => { nodeView.RegisterCallback<MouseDownEvent>(evt => {
if (evt.clickCount == 1){ if (evt.clickCount == 1){
@ -510,14 +551,17 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
} }
}); });
if(nodeView is IBaseNodeView nodeViewInterface){
nodeViewInterface.SetNodeData(nodeData);
}
_nodeDict.Add(nodeData.id, nodeView); if(_nodeDict.ContainsKey(nodeData.id)==false)
_nodeDict.Add(nodeData.id, nodeView);
if (_data.NodeDictionary.ContainsKey(nodeData.id) == false){ if (_data.NodeDictionary.ContainsKey(nodeData.id) == false){
Undo.RegisterCompleteObjectUndo(_data,"Node Creation"); Undo.RegisterCompleteObjectUndo(_data,"Node Creation");
_data.NodeDictionary.Add(nodeData.id,nodeData); _data.NodeDictionary.Add(nodeData.id,nodeData);
} }
//register an callback ,when right click context menu //register an callback ,when right click context menu
nodeView.RegisterCallback<ContextClickEvent>(evt => { nodeView.RegisterCallback<ContextClickEvent>(evt => {
var menu = new GenericMenu(); var menu = new GenericMenu();
@ -529,6 +573,8 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
}); });
menu.ShowAsContext(); menu.ShowAsContext();
}); });
} }
} }
@ -557,12 +603,21 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
_data.NodeLinks.Remove(nodeLink); _data.NodeLinks.Remove(nodeLink);
} }
public bool TestMode{ get; set; } public bool AutoUpdate{
get=>Owner.graphEditorData.autoUpdate; set=>Owner.graphEditorData.autoUpdate = value;
}
public override EventPropagation DeleteSelection(){
Undo.RegisterCompleteObjectUndo(_data,"Delete Selection");
var res = base.DeleteSelection();
SaveGraphData();
ResetGraphView();
return res;
}
public void CreateBlackboard(){ public void CreateBlackboard(){
_blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T)); _blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T));
_blackboard.Setup(this,Owner); _blackboard.Setup(this,Owner);
Debug.Log(Owner);
var castedBlackboard = _blackboard as Blackboard; var castedBlackboard = _blackboard as Blackboard;
Add(castedBlackboard); Add(castedBlackboard);
Rect blackboardPos = new Rect(0,0,300,700); Rect blackboardPos = new Rect(0,0,300,700);
@ -594,11 +649,9 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
public void NotifyRuntimeUpdate(){ public void NotifyRuntimeUpdate(){
_runtimeGraphUpdate = true;
} }
public Action AfterGraphResolved{ get; set; }
public Action AfterRuntimeGraphUpdate{ get; set; }
#endregion #endregion
} }

@ -18,6 +18,27 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
public abstract class BaseNodeView<T> : Node,INodeView<T> where T:NodeData,new(){ public abstract class BaseNodeView<T> : Node,INodeView<T> where T:NodeData,new(){
protected T _data; protected T _data;
private readonly NodeInspectorInNode _nodeInspectorInNode; private readonly NodeInspectorInNode _nodeInspectorInNode;
private NodeViewLogger _viewLogger;
private class NodeViewLogger:INodeLoggerImpl{
public BaseNodeView<T> NodeView { get; set; }
public void Log(string message){
var loggerAreaParent = NodeView.extensionContainer;
if (loggerAreaParent == null){
return;
}
var loggerArea = loggerAreaParent.Q<TextField>("loggerArea");
if(loggerArea == null){
loggerArea = new TextField();
loggerArea.name = "loggerArea";
loggerArea.AddToClassList("loggerArea");
loggerAreaParent.Add(loggerArea);
}
loggerArea.multiline = true;
loggerArea.value = message;
}
}
public IBaseDataGraphView BaseDataGraphView{ public IBaseDataGraphView BaseDataGraphView{
get{ get{
@ -31,18 +52,22 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
if(_data!=null) if(_data!=null)
((NodeDataWrapper)_data).OnValueChanged -= OnDataValueChanged; ((NodeDataWrapper)_data).OnValueChanged -= OnDataValueChanged;
_data = value; _data = value;
OnDataChanged?.Invoke(value); OnDataChanged?.Invoke(value);
if(_data!=null) if(_data!=null)
((NodeDataWrapper)_data).OnValueChanged += OnDataValueChanged; ((NodeDataWrapper)_data).OnValueChanged += OnDataValueChanged;
} }
} }
private void OnDataValueChanged(DataWrapper<NodeDataWrapper, NodeData> obj){ private void OnDataValueChanged(DataWrapper<NodeDataWrapper, NodeData> obj){
Refresh(); Refresh();
if (BaseDataGraphView == null) return;
if (BaseDataGraphView.IsRuntimeGraph){ if (BaseDataGraphView.IsRuntimeGraph){
BaseDataGraphView.NotifyRuntimeUpdate(); BaseDataGraphView.NotifyRuntimeUpdate();
} }
} }
public sealed override string title{ public sealed override string title{
get => base.title; get => base.title;
@ -65,6 +90,13 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
if (_nodeInspectorInNode != null){ if (_nodeInspectorInNode != null){
_nodeInspectorInNode.Data = obj; _nodeInspectorInNode.Data = obj;
} }
_viewLogger ??= new NodeViewLogger{NodeView = this};
if (NodeLogger.Loggers.ContainsKey(obj.id)){
NodeLogger.Loggers[obj.id] = _viewLogger;
}
else{
NodeLogger.Loggers.Add(obj.id,_viewLogger);
}
BuildInputAndOutputPort(); BuildInputAndOutputPort();
this.expanded = true; this.expanded = true;
this.RefreshExpandedState(); this.RefreshExpandedState();
@ -106,7 +138,6 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
foreach (var propertyInfo in propertyInfos){ foreach (var propertyInfo in propertyInfos){
if (propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true).FirstOrDefault() is OutputAttribute attribute){ if (propertyInfo.GetCustomAttributes(typeof(OutputAttribute),true).FirstOrDefault() is OutputAttribute attribute){
Port port = new CustomPort(Orientation.Horizontal, Direction.Output, Port port = new CustomPort(Orientation.Horizontal, Direction.Output,
attribute.Multiple ? Port.Capacity.Multi : Port.Capacity.Single, attribute.Multiple ? Port.Capacity.Multi : Port.Capacity.Single,
BuildPortType(attribute, propertyInfo)); BuildPortType(attribute, propertyInfo));
@ -115,16 +146,18 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
var portName = ObjectNames.NicifyVariableName(BuildPortName(attribute,propertyInfo)); var portName = ObjectNames.NicifyVariableName(BuildPortName(attribute,propertyInfo));
port.portName = portName; port.portName = portName;
port.name = propertyInfo.Name; port.name = propertyInfo.Name;
} }
} }
foreach (var propertyInfo in propertyInfos){ foreach (var propertyInfo in propertyInfos){
if(propertyInfo.GetCustomAttributes(typeof(InputAttribute),true).FirstOrDefault() is InputAttribute attribute){ if(propertyInfo.GetCustomAttributes(typeof(InputAttribute),true).FirstOrDefault() is InputAttribute attribute){
Port port = new CustomPort(Orientation.Horizontal, Direction.Input,attribute.Multiple?Port.Capacity.Multi:Port.Capacity.Single,BuildPortType(attribute,propertyInfo)); Port port = new CustomPort(Orientation.Horizontal, Direction.Input,attribute.Multiple?Port.Capacity.Multi:Port.Capacity.Single,BuildPortType(attribute,propertyInfo));
this.inputContainer.Add(port); this.inputContainer.Add(port);
var portName = BuildPortName(attribute,propertyInfo); var portName = BuildPortName(attribute,propertyInfo);
port.portName = portName; port.portName = portName;
port.name = propertyInfo.Name; port.name = propertyInfo.Name;
} }
} }
} }
@ -184,6 +217,18 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
Refresh(); Refresh();
} }
public override void SetPosition(Rect newPos){
var graphView = (GraphView)BaseDataGraphView;
//Cast newPos s position to global space
var globalPos = graphView.contentViewContainer.LocalToWorld(newPos.position);
_data.positionInView.position = globalPos;
base.SetPosition(newPos);
}
public void InitializePosition(Rect pos){
base.SetPosition(pos);
}
public void Refresh(){ public void Refresh(){
title = _data.nodeName; title = _data.nodeName;
} }
@ -195,6 +240,8 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
public void OnDataModified(); public void OnDataModified();
IBaseDataGraphView BaseDataGraphView{ get; } IBaseDataGraphView BaseDataGraphView{ get; }
public void InitializePosition(Rect pos);
} }
public interface INodeView<T>:IBaseNodeView where T:NodeData,new(){ public interface INodeView<T>:IBaseNodeView where T:NodeData,new(){

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fa7dcd53ede6483793978d44af911270
timeCreated: 1659437565
Loading…
Cancel
Save