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

Working in process
main
taoria 3 years ago committed by GitHub
commit a323a4957a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      README.md
  2. 3
      TNode/GraphCreator.meta
  3. 3
      TNode/GraphCreator/Editor.meta
  4. 8
      TNode/GraphCreator/Editor/GraphCreator.cs
  5. 3
      TNode/GraphCreator/Editor/GraphCreator.cs.meta
  6. 3
      TNode/GraphCreator/Runtime.meta
  7. 3
      TNode/GraphCreator/Runtime/Blackboard.meta
  8. 9
      TNode/GraphCreator/Runtime/Blackboard/GraphMetaBlackboard.cs
  9. 3
      TNode/GraphCreator/Runtime/Blackboard/GraphMetaBlackboard.cs.meta
  10. 1
      TNode/GraphCreator/Runtime/GraphMetaNode.cs
  11. 3
      TNode/GraphCreator/Runtime/GraphMetaNode.cs.meta
  12. 6
      TNode/GraphCreator/Runtime/MetaGraph.cs
  13. 3
      TNode/GraphCreator/Runtime/MetaGraph.cs.meta
  14. 3
      TNode/GraphCreator/Runtime/Nodes.meta
  15. 16
      TNode/GraphCreator/Runtime/Nodes/GraphMetaNode.cs
  16. 3
      TNode/GraphCreator/Runtime/Nodes/GraphMetaNode.cs.meta
  17. 8
      TNode/Samples.meta
  18. 23
      TNode/Samples/AddNode.cs
  19. 3
      TNode/Samples/AddNode.cs.meta
  20. 8
      TNode/Samples/Editor.meta
  21. 17
      TNode/Samples/Editor/HelloEditor.asset
  22. 8
      TNode/Samples/Editor/HelloEditor.asset.meta
  23. 26
      TNode/Samples/Editor/HelloEditor.cs
  24. 14
      TNode/Samples/Editor/HelloEditor.cs.meta
  25. 17
      TNode/Samples/HelloBlackboard.cs
  26. 3
      TNode/Samples/HelloBlackboard.cs.meta
  27. 11
      TNode/Samples/HelloGraph.cs
  28. 11
      TNode/Samples/HelloGraph.cs.meta
  29. 114
      TNode/Samples/New HelloGraph.asset
  30. 8
      TNode/Samples/New HelloGraph.asset.meta
  31. 2
      TNode/TNodeCore/Editor/EditorPersistence/GraphEditorData.cs
  32. 8
      TNode/TNodeCore/Editor/GraphCreatorEditor.cs
  33. 3
      TNode/TNodeCore/Editor/GraphCreatorEditor.cs.meta
  34. 1
      TNode/TNodeCore/Editor/GraphEditor.cs
  35. 4
      TNode/TNodeCore/Editor/Resources/ScriptTemplates/ExampleGraph.cs.txt
  36. 3
      TNode/TNodeCore/Editor/Resources/ScriptTemplates/ExampleGraph.cs.txt.meta
  37. 5
      TNode/TNodeCore/Editor/Resources/ScriptTemplates/NewGraph.cs.txt
  38. 33
      TNode/TNodeCore/Editor/Resources/ScriptTemplates/NewGraphEditor.cs.txt
  39. 8
      TNode/TNodeCore/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs
  40. 5
      TNode/TNodeCore/Runtime/Attributes/ModelColor.cs
  41. 17
      TNode/TNodeCore/Runtime/Attributes/PortColor.cs
  42. 0
      TNode/TNodeCore/Runtime/Attributes/PortColor.cs.meta
  43. 2
      TNode/TNodeCore/Runtime/Attributes/ShowInNode.cs
  44. 0
      TNode/TNodeCore/Runtime/Attributes/ShowInNode.cs.meta
  45. 5
      TNode/TNodeCore/Runtime/Interfaces/IPortTypeConversion.cs
  46. 3
      TNode/TNodeCore/Runtime/Logger.meta
  47. 0
      TNode/TNodeCore/Runtime/Logger/NodeLogger.cs
  48. 0
      TNode/TNodeCore/Runtime/Logger/NodeLogger.cs.meta
  49. 5
      TNode/TNodeCore/Runtime/Models/BlackboardData.cs
  50. 96
      TNode/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs
  51. 7
      TNode/TNodeCore/Runtime/RuntimeNode.cs
  52. 28
      TNode/TNodeGraphViewImpl/Editor/Cache/NodeEditorExtensions.cs
  53. 26
      TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/BlackboardDataEntry.cs
  54. 13
      TNode/TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs
  55. 2
      TNode/TNodeGraphViewImpl/Editor/Inspector/NodeInspectorInNode.cs
  56. 69
      TNode/TNodeGraphViewImpl/Editor/NodeGraphView/DataGraphView.cs
  57. 1
      TNode/TNodeGraphViewImpl/Editor/NodeViews/DragNodeView.cs
  58. 34
      TNode/TNodeGraphViewImpl/Editor/NodeViews/NodeView.cs
  59. 16
      TNode/TNodeGraphViewImpl/Editor/Resources/BlackboardDataEntry.uss
  60. 10
      TNode/TNodeGraphViewImpl/Editor/Search/BlackboardSearchWindowProvider.cs
  61. 8
      TNode/TNodeGtfImpl.meta

@ -3,34 +3,29 @@ Node graph creation tool based on unity experimental graphview and if possible l
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
development .
The tool separate its graph editor implementation and the graph creation logic.
# Install
currently under development
# Some Features # Some Features
* Create graph script a the creator tool * creator tool create graph easily
* 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 * Scene object nodes hold scene objects like blackboard
# Some to-dos
* Port connectivity of two types have implicit conversion
* Node placement
* Vertical node
* A universal merger handle multiple input
* Support static graph data traversal
# Install & Usage
Right now this lib is still under development.
# Some To-dos
* Function as port
* Circular dependency support for some situations such as FSM
* Edge colors customization
# Usage
Not yet documented
### Convention

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b880945b54834ff892ab441f95ebf64a
timeCreated: 1659601013

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 088ae3752f0e44ad91bf019cc64536fc
timeCreated: 1659601180

@ -0,0 +1,8 @@
using TNode.GraphCreator.Runtime;
using TNodeCore.Editor;
namespace TNode.GraphCreator.Editor{
public class GraphCreator:GraphEditor<MetaGraph>{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b727fc33cca34734bff028a952645808
timeCreated: 1659601005

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e10ab803f7cf4762b5e72874dc3a69a0
timeCreated: 1659601201

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3a0683e43c164065927b50fc72d9065c
timeCreated: 1659601323

@ -0,0 +1,9 @@
using TNodeCore.Editor.EditorPersistence;
using TNodeCore.Runtime.Models;
namespace TNode.GraphCreator.Runtime.Blackboard{
public class GraphMetaBlackboard:BlackboardData{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33c75ee828f4484abbe9009859357182
timeCreated: 1659601335

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e4bc602c13c042819a553d6142faf3ba
timeCreated: 1659601223

@ -0,0 +1,6 @@
using TNodeCore.Runtime.Models;
namespace TNode.GraphCreator.Runtime{
public class MetaGraph : GraphData{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e0047d8d81f646128eab9c94957129f4
timeCreated: 1659601169

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a54e22f7a85c4befbf19d09e14259869
timeCreated: 1659601272

@ -0,0 +1,16 @@
using System;
using TNodeCore.Runtime.Attributes;
namespace TNode.GraphCreator.Runtime.Nodes{
using TNodeCore.Runtime.Models;
namespace TNode.GraphCreator.Runtime{
[GraphUsage(typeof(MetaGraph))]
[Serializable]
public class GraphMetaNode:NodeData{
[ShowInNode]
public string createNodeName;
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f00e9ec34ac442da5e7b7b21042e37b
timeCreated: 1659601280

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc7f08d6196fcc24c97cf3b03543b697
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,23 @@

using TNodeCore.Runtime;
using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Attributes.Ports;
using TNodeCore.Runtime.Models;
using UnityEngine;
namespace Samples{
[GraphUsage(typeof(HelloGraph),"Math")]
public class AddNode:NodeData{
[Input]
public Vector3 A{ get; set; }
[Input]
public Vector2 B{ get; set; }
[Output]
public Vector3 Res{ get; set; }
public override void Process(){
Res = A + (Vector3)B;
this.Log(Res.ToString());
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f9814ff421124feda824b77793cf24f2
timeCreated: 1659705932

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 15edfa2efedd3854c95e45fefd5caf48
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,17 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 99ad0af56b40495cb6bd6165e652266c, type: 3}
m_Name: HelloEditor
m_EditorClassIdentifier:
graphElementsData: []
graphImplType: 0
autoUpdate: 0

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 060ae44fcac9b534f9bdca3c3e5f1484
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,26 @@
using Samples;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
using TNodeCore.Editor;
public class HelloEditor : GraphEditor<HelloGraph>{
[OnOpenAsset]
public static bool OnOpenAsset(int instanceID, int line){
var graph = EditorUtility.InstanceIDToObject(instanceID) as HelloGraph;
if (graph != null) {
var wnd = GetWindow<HelloEditor>();
wnd.titleContent = new GUIContent("HelloGraph Editor");
wnd.Show();
wnd.SetupNonRuntime(graph);
return true;
}
return false;
}
[MenuItem("Window/HelloEditor")]
public static void ShowWindow(){
var res = GetWindow<HelloEditor>();
res.titleContent = new GUIContent("HelloGraph Editor");
res.Show();
}
}

@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 7bffb928791aff340912bba71fc356e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- mVisualTreeAsset: {fileID: 9197481963319205126, guid: b67f6dcbe2361b649ad2b7845207321b, type: 3}
- graphEditorData: {fileID: 11400000, guid: 060ae44fcac9b534f9bdca3c3e5f1484, type: 2}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using Samples;
using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Models;
using UnityEngine;
namespace TNode.Samples{
[GraphUsage(typeof(HelloGraph))]
public class HelloBlackboard:BlackboardData{
public string HelloString = "Hello World";
public List<Vector3> V3S;
public List<Vector2> V2S;
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: edaf56bfb57443eb85ecadd142c4ce7d
timeCreated: 1659706002

@ -0,0 +1,11 @@
using System;
using TNodeCore.Runtime.Models;
using UnityEngine;
namespace Samples{
[CreateAssetMenu(fileName = "New HelloGraph", menuName = "TNode/HelloGraph")]
[Serializable]
public class HelloGraph : GraphData{
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2051a0adbd1ba974084a535dd06ab7d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,114 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2051a0adbd1ba974084a535dd06ab7d7, type: 3}
m_Name: New HelloGraph
m_EditorClassIdentifier:
nodeList:
- rid: 4804121563801583862
- rid: 4804121563801583898
- rid: 4804121563801583870
- rid: 4804121563801583866
nodeLinks:
- inPort:
portEntryName: A
nodeDataId: 6ceba867-fe0d-40c3-9d30-2d5d12803b52
outPort:
portEntryName: Value
nodeDataId: ac84573e-638d-45fa-b4e2-1a81c31fa9e7
- inPort:
portEntryName: B
nodeDataId: 6ceba867-fe0d-40c3-9d30-2d5d12803b52
outPort:
portEntryName: Value
nodeDataId: b2ab4a52-e65d-4104-8891-dc316af217d9
blackboardData:
rid: 4804121563801583854
sceneReference:
references:
version: 2
RefIds:
- rid: 4804121563801583854
type: {class: HelloBlackboard, ns: TNode.Samples, asm: Assembly-CSharp}
data:
positionInView:
serializedVersion: 2
x: 0
y: 0
width: 0
height: 0
HelloString: Hello World
V3S:
- {x: 0, y: 0, z: 0}
- {x: 0, y: 0, z: 0}
- {x: 0, y: 0, z: 0}
V2S:
- {x: 0, y: 0}
- {x: 0, y: 0}
- {x: 0, y: 0}
- rid: 4804121563801583862
type: {class: BlackboardDragNodeData, ns: TNodeCore.Runtime.Models, asm: NewAssembly}
data:
positionInView:
serializedVersion: 2
x: 256
y: 264
width: 0
height: 0
id: bae506a7-58ec-4b79-9c21-747fa2b6a7ba
nodeName:
entryPoint: 0
isTest: 0
blackDragData: HelloString
isListElement: 0
- rid: 4804121563801583866
type: {class: AddNode, ns: Samples, asm: Assembly-CSharp}
data:
positionInView:
serializedVersion: 2
x: 620
y: 234
width: 0
height: 0
id: 6ceba867-fe0d-40c3-9d30-2d5d12803b52
nodeName: AddNode
entryPoint: 0
isTest: 0
- rid: 4804121563801583870
type: {class: BlackboardDragNodeData, ns: TNodeCore.Runtime.Models, asm: NewAssembly}
data:
positionInView:
serializedVersion: 2
x: 469.00006
y: 336
width: 0
height: 0
id: b2ab4a52-e65d-4104-8891-dc316af217d9
nodeName:
entryPoint: 0
isTest: 0
blackDragData: V2S.0
isListElement: 1
- rid: 4804121563801583898
type: {class: BlackboardDragNodeData, ns: TNodeCore.Runtime.Models, asm: NewAssembly}
data:
positionInView:
serializedVersion: 2
x: 469
y: 213
width: 0
height: 0
id: ac84573e-638d-45fa-b4e2-1a81c31fa9e7
nodeName:
entryPoint: 0
isTest: 0
blackDragData: V3S.0
isListElement: 1

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 490933fc590be444780d73cd9f777ed4
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

@ -23,8 +23,6 @@ namespace TNodeCore.Editor.EditorPersistence{
return (IDataGraphView<T>)GraphViewImplCreator.Invoke(typeof(T)); return (IDataGraphView<T>)GraphViewImplCreator.Invoke(typeof(T));
} }
case GraphImplType.GraphToolsFoundationImpl: case GraphImplType.GraphToolsFoundationImpl:
throw new NotImplementedException(); throw new NotImplementedException();
default: default:

@ -0,0 +1,8 @@
using UnityEditor;
namespace TNodeCore.Editor{
public class GraphCreatorEditor:EditorWindow{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 059e73589b764d7db8e53b75c86d634d
timeCreated: 1659600695

@ -80,6 +80,7 @@ namespace TNodeCore.Editor{
GraphView.IsRuntimeGraph = false; GraphView.IsRuntimeGraph = false;
} }
private void BuildGraphView(){ private void BuildGraphView(){
GraphView = graphEditorData.GetGraphView<T>(); GraphView = graphEditorData.GetGraphView<T>();
GraphView.Owner = this; GraphView.Owner = this;

@ -0,0 +1,4 @@

public class Example$GraphClassName$Node:NodeData{
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 608d45120d7a4f5ca5091a1427d8843a
timeCreated: 1659602294

@ -1,7 +1,6 @@
using TNode.Models; using UnityEngine;
using UnityEngine;
using UnityEditor;
using System; using System;
using TNodeCore.Runtime.Models;
[CreateAssetMenu(fileName = "New $GraphClassName$", menuName = "TNode/$GraphClassName$")] [CreateAssetMenu(fileName = "New $GraphClassName$", menuName = "TNode/$GraphClassName$")]
[Serializable] [Serializable]
public class $GraphClassName$ : GraphData{ public class $GraphClassName$ : GraphData{

@ -1,22 +1,25 @@
using TNode.Editor; using UnityEditor;
using UnityEditor;
using UnityEditor.Callbacks; using UnityEditor.Callbacks;
using UnityEditor.Experimental.GraphView;
using UnityEngine; using UnityEngine;
using UnityEngine.UIElements; using TNodeCore.Editor;
using System;
public class $EditorClassName$ : GraphEditor<$GraphClassName$>{ public class $EditorClassName$ : GraphEditor<$GraphClassName$>{
[OnOpenAsset] [OnOpenAsset]
public static bool OnOpenAsset(int instanceID, int line){ public static bool OnOpenAsset(int instanceID, int line){
var graph = EditorUtility.InstanceIDToObject(instanceID) as $GraphClassName$; var graph = EditorUtility.InstanceIDToObject(instanceID) as $GraphClassName$;
if (graph != null) if (graph != null) {
{ var wnd = GetWindow<$EditorClassName$>();
var wnd = GetWindow<$EditorClassName$>(); wnd.titleContent = new GUIContent("$GraphClassName$ Editor");
wnd.titleContent = new GUIContent("$GraphClassName$ Editor"); wnd.Show();
wnd.CreateGUI(); wnd.SetupNonRuntime(graph);
wnd._graphView.Data = graph; return true;
return true; }
} return false;
return false;
} }
[MenuItem("Window/$EditorClassName$")]
public static void ShowWindow(){
var res = GetWindow<$EditorClassName$>();
res.titleContent = new GUIContent("$GraphClassName$ Editor");
res.Show();
}
} }

@ -26,7 +26,7 @@ namespace TNodeCore.Editor.Tools.GraphEditorCreator{
GraphEditorCreator wnd = GetWindow<GraphEditorCreator>(); GraphEditorCreator wnd = GetWindow<GraphEditorCreator>();
wnd.titleContent = new GUIContent("GraphEditorCreator"); wnd.titleContent = new GUIContent("GraphEditorCreator");
//Set position to the center of the screen //Set position to the center of the screen
wnd.position = new(Screen.width / 2, Screen.height / 2, 500, 300); wnd.position = new(Screen.width / 2.0f, Screen.height / 2.0f, 500, 300);
//set this window non resizable //set this window non resizable
wnd.minSize = new Vector2(500, 300); wnd.minSize = new Vector2(500, 300);
wnd.maxSize = new Vector2(500, 300); wnd.maxSize = new Vector2(500, 300);
@ -125,13 +125,13 @@ namespace TNodeCore.Editor.Tools.GraphEditorCreator{
var source = _sourceGeneratorForGraphEditor.GenerateGraphEditor(editorName, graphName); var source = _sourceGeneratorForGraphEditor.GenerateGraphEditor(editorName, graphName);
var sourceGraph = _sourceGeneratorForGraphEditor.GenerateGraph(graphName); var sourceGraph = _sourceGeneratorForGraphEditor.GenerateGraph(graphName);
var sourceGraphView = _sourceGeneratorForGraphEditor.GenerateGraphView(graphViewName, graphName); //var sourceGraphView = _sourceGeneratorForGraphEditor.GenerateGraphView(graphViewName, graphName);
string editorPath = Path.Combine(path, editorName + ".cs"); string editorPath = Path.Combine(path, editorName + ".cs");
string graphPath = Path.Combine(pathBeforeEditor, graphName + ".cs"); string graphPath = Path.Combine(pathBeforeEditor, graphName + ".cs");
string graphViewPath = Path.Combine(path, graphViewName + ".cs"); //string graphViewPath = Path.Combine(path, graphViewName + ".cs");
File.WriteAllText(editorPath, source); File.WriteAllText(editorPath, source);
File.WriteAllText(graphPath, sourceGraph); File.WriteAllText(graphPath, sourceGraph);
File.WriteAllText(graphViewPath, sourceGraphView); //File.WriteAllText(graphViewPath, sourceGraphView);
//Refresh the AssetDatabase to import the new file //Refresh the AssetDatabase to import the new file
AssetDatabase.Refresh(); AssetDatabase.Refresh();

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

@ -0,0 +1,17 @@
using System;
using UnityEngine;
namespace TNodeCore.Runtime.Attributes{
/// <summary>
/// this attribute only works on implemented types
/// </summary>
public class PortColorAttribute : Attribute{
public Color Color;
public PortColorAttribute(float r, float g, float b){
Color = new Color(r, g, b);
}
public PortColorAttribute(int r, int g,int b){
Color = new Color(r/255.0f, g/255.0f, b/255.0f);
}
}
}

@ -3,7 +3,7 @@
namespace TNodeCore.Runtime.Attributes{ namespace TNodeCore.Runtime.Attributes{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class ShowInNodeViewAttribute:System.Attribute{ public class ShowInNode:System.Attribute{
} }
} }

@ -3,5 +3,10 @@
public abstract class PortTypeConversion<TFrom, TTo>{ public abstract class PortTypeConversion<TFrom, TTo>{
public abstract TTo Convert(TFrom tFrom); public abstract TTo Convert(TFrom tFrom);
} }
public abstract class TwoWayPortTypeConversion<TFrom, TTo> : PortTypeConversion<TFrom,TTo>{
public abstract TFrom ConvertBack(TTo tTo);
}
} }

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f70fd0a222b9459093dff6c2b0679c3c
timeCreated: 1659682655

@ -7,10 +7,7 @@ namespace TNodeCore.Runtime.Models{
/// </summary> /// </summary>
[Serializable] [Serializable]
public class BlackboardData:Model,ICloneable{ public abstract class BlackboardData:Model{
} }
} }

@ -46,10 +46,22 @@ namespace TNodeCore.Runtime.RuntimeCache{
return _converter.Convert((T1)value); return _converter.Convert((T1)value);
} }
} }
//Store a t1 to t2 conversion but use two way converter's convert back method
internal class PortConverterHelperReverse<T1, T2> : IPortConverterHelper{
private readonly TwoWayPortTypeConversion<T2, T1> _converter;
public object Convert(object value){
return _converter.ConvertBack((T1)value);
}
public PortConverterHelperReverse(Type type){
_converter = Activator.CreateInstance(type) as TwoWayPortTypeConversion<T2, T1>;
}
}
internal interface IPortConverterHelper{ internal interface IPortConverterHelper{
public object Convert(object value); public object Convert(object value);
} }
public class PropertyNotFoundException : Exception{ public class PropertyNotFoundException : Exception{
@ -128,16 +140,15 @@ namespace TNodeCore.Runtime.RuntimeCache{
} }
private void CacheRuntimePortTypeConversion(Type type){ private void CacheRuntimePortTypeConversion(Type type){
if (type.BaseType == null) return;
if (type.BaseType != null){ if (type.BaseType != null){
var genericType = type.BaseType.GetGenericTypeDefinition(); var genericType = type.BaseType.GetGenericTypeDefinition();
if (genericType != typeof(PortTypeConversion<,>)){ if (genericType != typeof(PortTypeConversion<,>)|| genericType != typeof(TwoWayPortTypeConversion<,>)){
return; return;
} }
} }
else{
return;
}
//Forward direction
var type1 = type.BaseType.GetGenericArguments()[0]; var type1 = type.BaseType.GetGenericArguments()[0];
var type2 = type.BaseType.GetGenericArguments()[1]; var type2 = type.BaseType.GetGenericArguments()[1];
var specificType = typeof(PortConverterHelper<,>).MakeGenericType(type1, type2); var specificType = typeof(PortConverterHelper<,>).MakeGenericType(type1, type2);
@ -149,20 +160,74 @@ namespace TNodeCore.Runtime.RuntimeCache{
CachedPortConverters.Add(type1,new Dictionary<Type,IPortConverterHelper>()); CachedPortConverters.Add(type1,new Dictionary<Type,IPortConverterHelper>());
} }
CachedPortConverters[type1].Add(type2,instance); CachedPortConverters[type1].Add(type2,instance);
//Reverse direction
if(type.BaseType.GetGenericTypeDefinition()==typeof(TwoWayPortTypeConversion<,>)){
var specificTypeReverse = typeof(PortConverterHelperReverse<,>).MakeGenericType(type2, type1);
var instanceReverse = Activator.CreateInstance(specificTypeReverse, type) as IPortConverterHelper;
if (instanceReverse == null){
return;
}
if (!CachedPortConverters.ContainsKey(type2)){
CachedPortConverters.Add(type2,new Dictionary<Type,IPortConverterHelper>());
}
CachedPortConverters[type2].Add(type1,instanceReverse);
}
}
private readonly Dictionary<Tuple<Type,Type>,bool> _possibleImplicitConversions = new ();
public bool HasImplicitConversion(Type baseType, Type targetType){
var tuple = new Tuple<Type, Type>(baseType, targetType);
if (_possibleImplicitConversions.ContainsKey(tuple)){
return _possibleImplicitConversions[tuple];
}
var res =baseType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType)
.Any(mi => {
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == baseType;
});
return _possibleImplicitConversions[tuple] = res;
}
private void CachingImplicitConversion(Type baseType, Type targetType){
if (HasImplicitConversion(baseType, targetType)) return;
//Create Implicit Conversion Helper that caches the implicit cast function
var typeConverter = Activator.CreateInstance(typeof(ImplicitConversionHelper<,>).MakeGenericType(baseType, targetType)) as IPortConverterHelper;
if (!CachedPortConverters.ContainsKey(baseType)){
CachedPortConverters.Add(baseType,new Dictionary<Type,IPortConverterHelper>());
}
CachedPortConverters[baseType].Add(targetType,typeConverter);
} }
public object GetConvertedValue(Type from,Type to,object value){ public object GetConvertedValue(Type from,Type to,object value){
if(!CachedPortConverters.ContainsKey(from)){ if(!CachedPortConverters.ContainsKey(from)){
throw new ConversionFailedException("No converter found for type "+from); //Find the cached port failed ,check if there is an implicit conversion
//This inner cache method would only run once,so add a guard to prevent it run again,even though the function itself has a guard statement.
if(HasImplicitConversion(from,to)){
CachingImplicitConversion(from,to);
}
} }
if(!CachedPortConverters[from].ContainsKey(to)){ if(!CachedPortConverters[from].ContainsKey(to)){
//Just like above, this function should be checked in here too
if(HasImplicitConversion(from,to)){
CachingImplicitConversion(from,to);
}
return value; return value;
} }
return CachedPortConverters[from][to].Convert(value); return CachedPortConverters[from][to].Convert(value);
} }
private bool GetImplcitConvertedValue(Type from, Type to){
throw new NotImplementedException();
}
public List<Type> GetSupportedTypes(Type type){ public List<Type> GetSupportedTypes(Type type){
if(!CachedPortConverters.ContainsKey(type)){ if(!CachedPortConverters.ContainsKey(type)){
return null; return new List<Type>();
} }
return CachedPortConverters[type].Keys.ToList(); return CachedPortConverters[type].Keys.ToList();
} }
@ -248,6 +313,25 @@ namespace TNodeCore.Runtime.RuntimeCache{
} }
public class ImplicitConversionHelper<T1,T2> : IPortConverterHelper{
public Func<T1, T2> ConvertFunc;
public ImplicitConversionHelper(){
//Caching the implicit method that converts t1 to t2
var method = typeof(T2).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(T1) }, null);
if (method == null){
//Search it in T1
method = typeof(T1).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(T2) }, null);
}
//Create the delegate
if (method != null)
ConvertFunc = (Func<T1, T2>) Delegate.CreateDelegate(typeof(Func<T1, T2>), method);
}
public object Convert(object value){
return ConvertFunc((T1) value);
}
}
public class ConversionFailedException : Exception{ public class ConversionFailedException : Exception{
public ConversionFailedException(string noConverterFoundForType):base(noConverterFoundForType){ public ConversionFailedException(string noConverterFoundForType):base(noConverterFoundForType){

@ -23,16 +23,15 @@ namespace TNodeCore.Runtime{
var portType = _portAccessors[portName].Type; var portType = _portAccessors[portName].Type;
if(portType!=valueType && !portType.IsAssignableFrom(valueType)){ if(portType!=valueType && !portType.IsAssignableFrom(valueType)){
var res =RuntimeCache.RuntimeCache.Instance.GetConvertedValue(valueType, portType, value); var res =RuntimeCache.RuntimeCache.Instance.GetConvertedValue(valueType, portType, value);
_portAccessors[portName].SetValue(this.NodeData, res); _portAccessors[portName].SetValue(NodeData, res);
} }
else{ else{
_portAccessors[portName].SetValue(NodeData,value);
_portAccessors[portName].SetValue(this.NodeData,value);
} }
} }
public object GetOutput(string portName){ public object GetOutput(string portName){
return _portAccessors[portName].GetValue(this.NodeData); return _portAccessors[portName].GetValue(NodeData);
} }

@ -10,7 +10,9 @@ using TNodeCore.Editor.EditorPersistence;
using TNodeCore.Editor.NodeGraphView; using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Runtime.Attributes; using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using Unity.VisualScripting;
using UnityEditor; using UnityEditor;
using UnityEngine;
namespace TNode.TNodeGraphViewImpl.Editor.Cache{ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
/// <summary> /// <summary>
@ -40,7 +42,12 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
get{ return _instance ??= new NodeEditorSingleton(); } get{ return _instance ??= new NodeEditorSingleton(); }
} }
private static readonly string[] ExcludedAssemblies = new string[]{"Microsoft", "UnityEngine","UnityEditor","mscorlib","System"};
private static readonly string[] ExcludedAssemblies = new[]{
"Microsoft", "UnityEngine","UnityEditor","mscorlib",
"System","Mono","PlasticPipe","unityplastic","ExCSS",
"Unity","PlayerBuildProgramLibrary","netstandard","log4net","Newtonsoft","Bee","nunit","PsdPlugin"
};
public static T CreateViewComponentFromBaseType<T>(){ public static T CreateViewComponentFromBaseType<T>(){
var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)]; var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)];
var instance = (T)Activator.CreateInstance(implementedType); var instance = (T)Activator.CreateInstance(implementedType);
@ -63,10 +70,12 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
private NodeEditorSingleton(){ private NodeEditorSingleton(){
//exclude unity ,system ,and microsoft types //exclude unity ,system ,and microsoft types
var assemblies = AppDomain. var assemblies = AppDomain.CurrentDomain.GetAssemblies();
CurrentDomain.GetAssemblies()
.Where(x=>ExcludedAssemblies.All(y=>!x.GetName().Name.Split(".")[0].Equals(y)));
assemblies = assemblies.Where(x => !ExcludedAssemblies.Contains(x.FullName.Split('.',',',' ')[0])).ToArray();
foreach (var ass in assemblies){
}
foreach(var assembly in assemblies){ foreach(var assembly in assemblies){
foreach(var type in assembly.GetTypes()){ foreach(var type in assembly.GetTypes()){
if(type.IsClass && !type.IsAbstract){ if(type.IsClass && !type.IsAbstract){
@ -84,9 +93,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
private IBaseDataGraphView GraphViewImplCreator(Type arg){ private IBaseDataGraphView GraphViewImplCreator(Type arg){
var genericType = typeof(BaseDataGraphView<>).MakeGenericType(arg); var genericType = typeof(BaseDataGraphView<>).MakeGenericType(arg);
var instance = CreateViewComponentFromBaseType(genericType) as IBaseDataGraphView; var instance = CreateViewComponentFromBaseType(genericType) as IBaseDataGraphView;
if (instance == null){
//fallback to default graph view
instance = (IBaseDataGraphView) Activator.CreateInstance(genericType);
}
return instance; return instance;
} }
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(Model).IsAssignableFrom(type.BaseType)){ if (typeof(Model).IsAssignableFrom(type.BaseType)){
@ -201,11 +215,15 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
} }
public static List<string> GetGraphCategories(Type t){ public static List<string> GetGraphCategories(Type t){
if(!NodeEditorSingleton.Instance.GraphDataUsage.ContainsKey(t)){
return new List<string>();
}
var list = NodeEditorSingleton.Instance.GraphDataUsage[t]; var list = NodeEditorSingleton.Instance.GraphDataUsage[t];
//Merge same category //Merge same category
var res = list.Select(x=>x.GetCustomAttribute<GraphUsageAttribute>().Category).Distinct().ToList(); var res = list.Select(x=>x.GetCustomAttribute<GraphUsageAttribute>().Category).Distinct().ToList();
return res; return res;
} }
//TODO Move this method to runtime place
public static BlackboardData GetAppropriateBlackboardData(Type t){ public static BlackboardData GetAppropriateBlackboardData(Type t){
if (NodeEditorSingleton.Instance.GraphBlackboard.ContainsKey(t)){ if (NodeEditorSingleton.Instance.GraphBlackboard.ContainsKey(t)){
return (BlackboardData)Activator.CreateInstance(NodeEditorSingleton.Instance.GraphBlackboard[t]); return (BlackboardData)Activator.CreateInstance(NodeEditorSingleton.Instance.GraphBlackboard[t]);
@ -257,8 +275,10 @@ namespace TNode.TNodeGraphViewImpl.Editor.Cache{
} }
} }
[InitializeOnLoad] [InitializeOnLoad]
public class Launcher{ public class Launcher{
static Launcher(){ static Launcher(){
Debug.Log("NES Launched");
NodeEditorSingleton.Instance.Initialize(); NodeEditorSingleton.Instance.Initialize();
} }
} }

@ -1,5 +1,6 @@
using System; using System;
using System.Collections; using System.Reflection;
using TNodeCore.Runtime.Attributes;
using UnityEditor.Experimental.GraphView; using UnityEditor.Experimental.GraphView;
using UnityEngine; using UnityEngine;
using UnityEngine.UIElements; using UnityEngine.UIElements;
@ -8,37 +9,34 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
public class BlackboardDataEntry:GraphElement{ public class BlackboardDataEntry:GraphElement{
public Type propertyType; public Type propertyType;
public string propertyPath; public string propertyPath;
private Color _convertedColor;
public BlackboardDataEntry(Type type){ public BlackboardDataEntry(Type type){
propertyType = type; propertyType = type;
if (typeof(Component).IsAssignableFrom(propertyType)){ if (typeof(Component).IsAssignableFrom(propertyType)){
this.AddToClassList("typeComponent"); this.AddToClassList("typeComponent");
} }else if (typeof(GameObject).IsAssignableFrom(propertyType)){
if (typeof(GameObject).IsAssignableFrom(propertyType)){
this.AddToClassList("gameObject"); this.AddToClassList("gameObject");
}else{
this.AddToClassList(propertyType.Name);
} }
if (typeof(Vector2).IsAssignableFrom(propertyType)){
this.AddToClassList("vector");
}
if (typeof(Vector2Int).IsAssignableFrom(propertyType)){
this.AddToClassList("vector");
}
if (typeof(IList).IsAssignableFrom(propertyType)){
this.AddToClassList("list");
}
this.capabilities |= Capabilities.Selectable | Capabilities.Deletable | Capabilities.Droppable | Capabilities.Renamable; this.capabilities |= Capabilities.Selectable | Capabilities.Deletable | Capabilities.Droppable | Capabilities.Renamable;
this.AddManipulator(new SelectionDropper()); this.AddManipulator(new SelectionDropper());
var styleSheet = Resources.Load<StyleSheet>("BlackboardDataEntry"); var styleSheet = Resources.Load<StyleSheet>("BlackboardDataEntry");
this.styleSheets.Add(styleSheet); this.styleSheets.Add(styleSheet);
if (type.GetCustomAttribute<PortColorAttribute>() is {} portColorAttribute){
_convertedColor = portColorAttribute.Color;
}
this.RegisterCallback<MouseEnterEvent>((evt) => { this.RegisterCallback<MouseEnterEvent>((evt) => {
style.borderBottomColor=style.borderRightColor=style.borderLeftColor=style.borderTopColor=new Color(1,1,1,1); style.borderBottomColor=style.borderRightColor=style.borderLeftColor=style.borderTopColor=new Color(1,1,1,1);
}); });
this.RegisterCallback<MouseLeaveEvent>((evt) => { this.RegisterCallback<MouseLeaveEvent>((evt) => {
style.borderBottomColor = style.borderRightColor = style.borderBottomColor = style.borderRightColor =
style.borderLeftColor = style.borderTopColor = StyleKeyword.Null; style.borderLeftColor = style.borderTopColor = _convertedColor==default?StyleKeyword.Null:_convertedColor;
}); });
} }
} }
} }

@ -50,24 +50,24 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
blackboardList.Add(foldout); blackboardList.Add(foldout);
Add(blackboardList); Add(blackboardList);
if(field.GetValue(data)==null) continue;
if (field.GetValue(data) is IList list){ if (field.GetValue(data) is IList list){
for (var i = 0; i < list.Count; i++){ for (var i = 0; i < list.Count; i++){
CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i); CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i);
} }
} }
if (field.GetValue(data).GetType().IsArray){ if (field.GetValue(data).GetType().IsArray){
var array = (Array)field.GetValue(data); var array = (Array)field.GetValue(data);
if(array==null) continue;
for (var i = 0; i < array.Length; i++){ for (var i = 0; i < array.Length; i++){
CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i); CreateBlackboardDataEntryForListItem(field, serializedObject, isRuntimeGraph, blackboardList, i);
} }
} }
} }
} }
addItemRequested += (sender) => { addItemRequested = (sender) => {
var res = ScriptableObject.CreateInstance<BlackboardSearchWindowProvider>(); var res = ScriptableObject.CreateInstance<BlackboardSearchWindowProvider>();
Debug.Log(res);
//Get right top corner of the blackboard //Get right top corner of the blackboard
var blackboardPos = GetPosition().position+OwnerWindow.position.position; var blackboardPos = GetPosition().position+OwnerWindow.position.position;
@ -80,14 +80,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
SearchWindow.Open(searchWindowContext, res); SearchWindow.Open(searchWindowContext, res);
}; };
} }
private static void CreateBlackboardDataEntryForListItem(FieldInfo field, SerializedObject serializedObject, private static void CreateBlackboardDataEntryForListItem(FieldInfo field, SerializedObject serializedObject,
bool isRuntimeGraph, bool isRuntimeGraph,
BlackboardSection blackboardSection, int index){ BlackboardSection blackboardSection, int index){
var property =serializedObject.FindProperty("data").FindPropertyRelative(field.Name).GetArrayElementAtIndex(index); var property = serializedObject.FindProperty("data");
property = property.FindPropertyRelative(field.Name).GetArrayElementAtIndex(index);
BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){ BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){
propertyPath = field.Name+"."+index, propertyPath = field.Name+"."+index,
@ -102,6 +102,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.GraphBlackboard{
} }
private static void CreateBlackboardDataEntry(FieldInfo field, SerializedObject serializedObject, bool isRuntimeGraph, private static void CreateBlackboardDataEntry(FieldInfo field, SerializedObject serializedObject, bool isRuntimeGraph,
BlackboardSection blackboardSection){ BlackboardSection blackboardSection){
BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){ BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){

@ -46,7 +46,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.Inspector{
foreach (var field in _data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public|BindingFlags.NonPublic)){ foreach (var field in _data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public|BindingFlags.NonPublic)){
//Create corresponding property field //Create corresponding property field
//check if the field has ShowInNodeView attribute //check if the field has ShowInNodeView attribute
var showInNodeViewAttribute = field.GetCustomAttribute<ShowInNodeViewAttribute>() != null; var showInNodeViewAttribute = field.GetCustomAttribute<ShowInNode>() != null;
if (!showInNodeViewAttribute) if (!showInNodeViewAttribute)
continue; continue;
var drawer = new PropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name)); var drawer = new PropertyField(serializedObject.FindProperty("data").FindPropertyRelative(field.Name));

@ -145,6 +145,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
if (Data != null){ if (Data != null){
visualElement.RemoveFromHierarchy(); visualElement.RemoveFromHierarchy();
} }
CreateMenu();
}; };
} }
@ -219,7 +220,6 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
SetDetachedFromPanel(); SetDetachedFromPanel();
} }
private void SetDetachedFromPanel(){ private void SetDetachedFromPanel(){
@ -241,6 +241,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
protected void CreateMenu(){ protected void CreateMenu(){
if (this.Q("TopMenu") != null) return;
var visualElement = new VisualElement{ var visualElement = new VisualElement{
name = "TopMenu" name = "TopMenu"
}; };
@ -278,6 +279,16 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
}); });
visualElement.Add(runButton); visualElement.Add(runButton);
var blackboardButton = new Button{
name = "blackboardButton",
text = "Blackboard"
};
blackboardButton.RegisterCallback<ClickEvent>(evt => {
if(_blackboard==null)
CreateBlackboard();
});
visualElement.Add(blackboardButton);
} }
public void RegisterDragEvent(){ public void RegisterDragEvent(){
@ -399,12 +410,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
private void BlackboardUpdate(){ private void UpdateBlackboardData(){
if (_data == null) return;
if (_data.blackboardData == null || _data.blackboardData.GetType()==(typeof(BlackboardData))){ if (_data.blackboardData == null || _data.blackboardData.GetType()==(typeof(BlackboardData))){
_data.blackboardData = NodeEditorExtensions.GetAppropriateBlackboardData(_data.GetType());
_data.blackboardData = NodeEditorExtensions.GetAppropriateBlackboardData(_data.GetType());
Debug.Log(_data.blackboardData);
if (_data.blackboardData == null) return; if (_data.blackboardData == null) return;
} }
_blackboard.SetBlackboardData(GetBlackboardData()); _blackboard.SetBlackboardData(GetBlackboardData());
} }
@ -506,15 +519,45 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
}); });
} }
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){ public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){
var supportedTypes = RuntimeCache.Instance.GetSupportedTypes(startPort.portType);
var compatiblePorts = ports.Where(x => startPort != x && var compatiblePorts = ports.Where(x => startPort != x &&
(x.portType == startPort.portType || (x.portType == startPort.portType ||
x.portType.IsAssignableFrom(startPort.portType) x.portType.IsAssignableFrom(startPort.portType)
)).ToList(); )).ToList();
if (supportedTypes != null){ if(startPort.direction==Direction.Input){
compatiblePorts.AddRange(ports.Where(x => supportedTypes.Contains(x.portType)).ToList()); //Search output to find ports with type that have implicit conversion or define converter that convert to type of the startPort
var outputPorts = ports.Where(x => x.direction == Direction.Output).ToList();
foreach (var outputPort in outputPorts){
//Want a port type that can convert to to the type of the startPort
if (HasImplicitConversion(outputPort.portType,startPort.portType)){
compatiblePorts.Add(outputPort);
}
if (RuntimeCache.Instance.GetSupportedTypes(outputPort.portType).Contains(startPort.portType)){
compatiblePorts.Add(outputPort);
}
}
} }
else{
var inputPorts = ports.Where(x => x.direction == Direction.Input).ToList();
foreach (var inputPort in inputPorts){
//check if start port could implicitly convert to input port type
if (HasImplicitConversion(startPort.portType,inputPort.portType)){
compatiblePorts.Add(inputPort);
}
//Check if input port type is supported by output port type
if (RuntimeCache.Instance.GetSupportedTypes(startPort.portType).Contains(inputPort.portType)){
compatiblePorts.Add(inputPort);
}
}
}
return compatiblePorts; return compatiblePorts;
@ -607,6 +650,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
get=>Owner.graphEditorData.autoUpdate; set=>Owner.graphEditorData.autoUpdate = value; get=>Owner.graphEditorData.autoUpdate; set=>Owner.graphEditorData.autoUpdate = value;
} }
public override EventPropagation DeleteSelection(){ public override EventPropagation DeleteSelection(){
Undo.RegisterCompleteObjectUndo(_data,"Delete Selection"); Undo.RegisterCompleteObjectUndo(_data,"Delete Selection");
var res = base.DeleteSelection(); var res = base.DeleteSelection();
@ -616,13 +660,14 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeGraphView{
} }
public void CreateBlackboard(){ public void CreateBlackboard(){
_blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T)); _blackboard = NodeEditorExtensions.CreateBlackboardWithGraphData(typeof(T)) ;
_blackboard.Setup(this,Owner); _blackboard.Setup(this,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);
castedBlackboard?.SetPosition(blackboardPos); castedBlackboard?.SetPosition(blackboardPos);
OnDataChanged+= (sender, e) => { BlackboardUpdate(); }; UpdateBlackboardData();
OnDataChanged+= (sender, e) => { UpdateBlackboardData(); };
} }
public GraphData GetGraphData(){ public GraphData GetGraphData(){

@ -33,6 +33,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
label.text = ObjectNames.NicifyVariableName(obj.BlackDragData); label.text = ObjectNames.NicifyVariableName(obj.BlackDragData);
//Get serialized property's icon //Get serialized property's icon
Texture2D icon = null; Texture2D icon = null;
if (serializedProperty == null) return;
if (serializedProperty.boxedValue is Object value){ if (serializedProperty.boxedValue is Object value){
icon = AssetPreview.GetMiniThumbnail(value); icon = AssetPreview.GetMiniThumbnail(value);
} }

@ -6,6 +6,7 @@ using TNode.TNodeGraphViewImpl.Editor.Ports;
using TNodeCore.Editor.NodeGraphView; using TNodeCore.Editor.NodeGraphView;
using TNodeCore.Editor.Serialization; using TNodeCore.Editor.Serialization;
using TNodeCore.Runtime; using TNodeCore.Runtime;
using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Attributes.Ports; using TNodeCore.Runtime.Attributes.Ports;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using UnityEditor; using UnityEditor;
@ -141,27 +142,31 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
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));
BuildPort(port, attribute, propertyInfo,outputContainer);
this.outputContainer.Add(port);
var portName = ObjectNames.NicifyVariableName(BuildPortName(attribute,propertyInfo));
port.portName = portName;
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,
Port port = new CustomPort(Orientation.Horizontal, Direction.Input,attribute.Multiple?Port.Capacity.Multi:Port.Capacity.Single,BuildPortType(attribute,propertyInfo)); Direction.Input,attribute.Multiple?Port.Capacity.Multi: Port.Capacity.Single,BuildPortType(attribute,propertyInfo));
this.inputContainer.Add(port); BuildPort(port,attribute,propertyInfo,inputContainer);
var portName = BuildPortName(attribute,propertyInfo);
port.portName = portName;
port.name = propertyInfo.Name;
} }
} }
} }
private void BuildPort(Port port, PortAttribute attribute, PropertyInfo propertyInfo,VisualElement portContainer){
portContainer.Add(port);
var portName = ObjectNames.NicifyVariableName(BuildPortName(attribute, propertyInfo));
port.portName = portName;
port.name = propertyInfo.Name;
var colorAtt = propertyInfo.PropertyType.GetCustomAttribute<PortColorAttribute>();
if (colorAtt != null){
var color = colorAtt.Color;
port.portColor = color;
}
}
public void StartARenameTitleTextField(){ public void StartARenameTitleTextField(){
var textField = new TextField{ var textField = new TextField{
value = title, value = title,
@ -220,8 +225,7 @@ namespace TNode.TNodeGraphViewImpl.Editor.NodeViews{
public override void SetPosition(Rect newPos){ public override void SetPosition(Rect newPos){
var graphView = (GraphView)BaseDataGraphView; var graphView = (GraphView)BaseDataGraphView;
//Cast newPos s position to global space //Cast newPos s position to global space
var globalPos = graphView.contentViewContainer.LocalToWorld(newPos.position); _data.positionInView.position = newPos.position;
_data.positionInView.position = globalPos;
base.SetPosition(newPos); base.SetPosition(newPos);
} }

@ -6,7 +6,19 @@
border-width: 1px; border-width: 1px;
border-color: rgba(201, 249, 116, 255); border-color: rgba(201, 249, 116, 255);
} }
.vector{ .Int32{
border-width: 1px; border-width: 1px;
border-color: rgba(0.788, 0.969, 0.455, 1.000); border-color: rgba(148,130,230,255);
}
.Float{
border-width: 1px;
border-color: aquamarine;
}
.System32{
border-width: 1px;
border-color: aquamarine;
}
.String{
border-width: 1px;
border-color: crimson;
} }

@ -31,17 +31,21 @@ namespace TNode.TNodeGraphViewImpl.Editor.Search{
if (list == null) throw new ArgumentNullException(nameof(list)); if (list == null) throw new ArgumentNullException(nameof(list));
//search fields with List type //search fields with List type
Texture2D icon = new Texture2D(2,2); Texture2D icon = new Texture2D(2,2);
foreach (var field in type.GetFields()){ foreach (var field in type.GetFields()){
if (field.FieldType.IsGenericType){ if (field.FieldType.IsGenericType){
var genericType = field.FieldType.GetGenericTypeDefinition(); var genericType = field.FieldType.GetGenericTypeDefinition();
if (genericType == typeof(List<>)){ if (genericType == typeof(List<>)){
var castedList = field.GetValue(blackboardData) as IList;
if (castedList == null){
field.SetValue(blackboardData, Activator.CreateInstance(field.FieldType));
}
list.Add(new SearchTreeEntry(new GUIContent(field.Name,icon)){ list.Add(new SearchTreeEntry(new GUIContent(field.Name,icon)){
level = 1, level = 1,
userData = new InternalSearchTreeUserData(){ userData = new InternalSearchTreeUserData(){
List = field.GetValue(blackboardData) as IList, List = field.GetValue(blackboardData) as IList,
Type = field.FieldType.GetGenericArguments()[0] Type = field.FieldType.GetGenericArguments()[0]
} }
}); });
} }
} }
@ -64,7 +68,9 @@ namespace TNode.TNodeGraphViewImpl.Editor.Search{
if (userData is InternalSearchTreeUserData){ if (userData is InternalSearchTreeUserData){
var list = ((InternalSearchTreeUserData) userData).List; var list = ((InternalSearchTreeUserData) userData).List;
Debug.Log(list); if (list == null){
}
var type = ((InternalSearchTreeUserData) userData).Type; var type = ((InternalSearchTreeUserData) userData).Type;
if (!typeof(Object).IsAssignableFrom(type)){ if (!typeof(Object).IsAssignableFrom(type)){
var newItem = Activator.CreateInstance(type); var newItem = Activator.CreateInstance(type);

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fcfff7d02bd7fbb41a515c4c4359aab2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Loading…
Cancel
Save