Compare commits

..

5 Commits

  1. 54
      Samples/New HelloGraph.asset
  2. 11
      Samples/Nodes/AddNode.cs
  3. 20
      Samples/Nodes/CheckSizeNode.cs
  4. 3
      TNodeCore/Runtime/Components/ConditionalGraph.cs
  5. 2
      TNodeCore/Runtime/Logger/NodeLogger.cs
  6. 13
      TNodeCore/Runtime/Models/ConditionalNode.cs
  7. 2
      TNodeCore/Runtime/RuntimeCache/IModelPortAccessor.cs
  8. 33
      TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs
  9. 13
      TNodeCore/Runtime/RuntimeModels/ConditionalRuntimeNode.cs
  10. 7
      TNodeCore/Runtime/RuntimeModels/RuntimeNode.cs
  11. 4
      TNodeCore/Runtime/RuntimeModels/StaticGraph.cs
  12. 3
      TNodeCore/Runtime/Tools/GraphTool.cs
  13. 5
      TNodeGraphViewImpl/Editor/GraphBlackboard/DefaultGraphBlackboardView.cs
  14. 4
      TNodeGraphViewImpl/Editor/GraphWatcherView/GraphWatcherView.cs
  15. 3
      Tests/StaticGraphTest.cs

@ -18,6 +18,7 @@ MonoBehaviour:
- id: 2 - id: 2
- id: 3 - id: 3
- id: 4 - id: 4
- id: 5
nodeLinks: nodeLinks:
- inPort: - inPort:
portEntryName: A portEntryName: A
@ -37,12 +38,18 @@ MonoBehaviour:
outPort: outPort:
portEntryName: C portEntryName: C
nodeDataId: 4300534d-023d-4b56-a0cb-39e197e68845 nodeDataId: 4300534d-023d-4b56-a0cb-39e197e68845
- inPort:
portEntryName: B
nodeDataId: 926f2eea-3403-4663-88bd-7ed16ce029fa
outPort:
portEntryName: Value
nodeDataId: 7faced8f-0880-4fc3-b26b-aac148024af8
blackboardData: blackboardData:
id: 5 id: 6
sceneReference: sceneReference:
editorModels: [] editorModels: []
graphViewModel: graphViewModel:
id: 6 id: 7
references: references:
version: 1 version: 1
00000000: 00000000:
@ -51,7 +58,7 @@ MonoBehaviour:
positionInView: positionInView:
serializedVersion: 2 serializedVersion: 2
x: 674 x: 674
y: 261 y: 239
width: 0 width: 0
height: 0 height: 0
id: 6dba1aab-0db9-45a0-b3f7-e8fe9c47c168 id: 6dba1aab-0db9-45a0-b3f7-e8fe9c47c168
@ -67,8 +74,8 @@ MonoBehaviour:
data: data:
positionInView: positionInView:
serializedVersion: 2 serializedVersion: 2
x: 674 x: 676
y: 330 y: 281
width: 0 width: 0
height: 0 height: 0
id: 5fd53e10-e727-45e3-8458-04a6ec8581c4 id: 5fd53e10-e727-45e3-8458-04a6ec8581c4
@ -84,8 +91,8 @@ MonoBehaviour:
data: data:
positionInView: positionInView:
serializedVersion: 2 serializedVersion: 2
x: 781 x: 786
y: 252 y: 228
width: 0 width: 0
height: 0 height: 0
id: 4300534d-023d-4b56-a0cb-39e197e68845 id: 4300534d-023d-4b56-a0cb-39e197e68845
@ -97,8 +104,8 @@ MonoBehaviour:
data: data:
positionInView: positionInView:
serializedVersion: 2 serializedVersion: 2
x: 908 x: 928
y: 252 y: 189
width: 0 width: 0
height: 0 height: 0
id: f236a611-cc64-4fce-88d2-40baf7f4a490 id: f236a611-cc64-4fce-88d2-40baf7f4a490
@ -110,8 +117,8 @@ MonoBehaviour:
data: data:
positionInView: positionInView:
serializedVersion: 2 serializedVersion: 2
x: 1119 x: 1168
y: 210 y: 188
width: 0 width: 0
height: 0 height: 0
id: 926f2eea-3403-4663-88bd-7ed16ce029fa id: 926f2eea-3403-4663-88bd-7ed16ce029fa
@ -119,6 +126,23 @@ MonoBehaviour:
entryPoint: 0 entryPoint: 0
isTest: 0 isTest: 0
00000005: 00000005:
type: {class: BlackboardDragNode, ns: TNodeCore.Runtime.Models, asm: Taoria.TNodeCore.Runtime}
data:
positionInView:
serializedVersion: 2
x: 1056.5
y: 315
width: 0
height: 0
id: 7faced8f-0880-4fc3-b26b-aac148024af8
nodeName:
entryPoint: 0
isTest: 0
blackboardDragTypeString: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
blackDragData: Value.0
isListElement: 1
00000006:
type: {class: HelloBlackboard, ns: TNode.Samples, asm: Assembly-CSharp} type: {class: HelloBlackboard, ns: TNode.Samples, asm: Assembly-CSharp}
data: data:
positionInView: positionInView:
@ -131,9 +155,9 @@ MonoBehaviour:
HelloString: HelloString:
HelloGameObject: {fileID: 0} HelloGameObject: {fileID: 0}
Value: Value:
- 11 - 23.9
- 102.1 - 102.1
00000006: 00000007:
type: {class: GraphViewModel, ns: TNode.TNodeCore.Editor.Models, asm: Taoria.TNodeCore.Runtime} type: {class: GraphViewModel, ns: TNode.TNodeCore.Editor.Models, asm: Taoria.TNodeCore.Runtime}
data: data:
positionInView: positionInView:
@ -143,6 +167,6 @@ MonoBehaviour:
width: 0 width: 0
height: 0 height: 0
id: id:
persistScale: 1 persistScale: 0.57175326
persistOffset: {x: -212, y: 19} persistOffset: {x: -366, y: 193}
isBlackboardOn: 1 isBlackboardOn: 1

@ -1,15 +1,18 @@
using TNodeCore.Runtime.Attributes; 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;
namespace Samples.Nodes{ namespace Samples.Nodes{
[GraphUsage(typeof(HelloGraph),"Math")] [GraphUsage(typeof(HelloGraph),"Math")]
public class AddNode:NodeData{ public class AddNode:NodeData{
[Input] public float A{ get; set; } = default;
[Input] [Input]
public float A{ get; set; } public float B{ get; set; }= default;
[Input]
public float B{ get; set; }
[Output] public float C => A + B; [Output] public float C => A + B;
public override void Process(){
this.Log($"{C}");
}
} }
} }

@ -1,7 +1,8 @@
using TNode.TNodeCore.Runtime.Models; using TNodeCore.Runtime;
using TNodeCore.Runtime.Attributes; using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Attributes.Ports; using TNodeCore.Runtime.Attributes.Ports;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using UnityEngine;
namespace Samples.Nodes{ namespace Samples.Nodes{
[GraphUsage(typeof(HelloGraph),"Math")] [GraphUsage(typeof(HelloGraph),"Math")]
@ -10,19 +11,24 @@ namespace Samples.Nodes{
public float A{ get; set; } public float A{ get; set; }
[Output] [Output]
public TransitionCondition Bigger(){ public TransitionCondition<float> Bigger(){
return new TransitionCondition(){ return new TransitionCondition<float>(){
Condition = A>0, Condition = A>0,
Priority = 0 Priority = 0,
DataFunc = ()=>A
}; };
} }
[Output] [Output]
public TransitionCondition SmallerOrEqual(){ public TransitionCondition<float> SmallerOrEqual(){
return new TransitionCondition(){ return new TransitionCondition<float>(){
Condition = A<=0, Condition = A<=0,
Priority = 0 Priority = 0,
DataFunc = ()=>A
}; };
} }
public override void Process(){
this.Log($"{A}");
}
} }
} }

@ -17,9 +17,6 @@ namespace TNode.TNodeCore.Runtime.Components{
} }
EntryNode = entry.FirstOrDefault() as ConditionalRuntimeNode; EntryNode = entry.FirstOrDefault() as ConditionalRuntimeNode;
} }
public void Run(){ public void Run(){
var res = StepForward(); var res = StepForward();
while (StepForward().MoveNext()){ while (StepForward().MoveNext()){

@ -10,7 +10,7 @@ namespace TNodeCore.Runtime{
if (!Loggers.ContainsKey(t.id)) return; if (!Loggers.ContainsKey(t.id)) return;
var nodeLoggerImpl = Loggers[t.id]; var nodeLoggerImpl = Loggers[t.id];
nodeLoggerImpl.Log(message); nodeLoggerImpl.Log(message);
Debug.Log(message);
} }
} }

@ -1,9 +1,8 @@
using TNodeCore.Runtime; 
using TNodeCore.Runtime.Attributes.Ports;
using TNodeCore.Runtime.Models;
using Unity.Plastic.Newtonsoft.Json.Serialization;
namespace TNode.TNodeCore.Runtime.Models{ using System;
namespace TNodeCore.Runtime.Models{
public class ConditionalNode:NodeData{ public class ConditionalNode:NodeData{
} }
@ -25,6 +24,10 @@ namespace TNode.TNodeCore.Runtime.Models{
public object GetValue(){ public object GetValue(){
return DataFunc.Invoke(); return DataFunc.Invoke();
} }
public static implicit operator T(TransitionCondition<T> condition){
return condition.DataFunc.Invoke();
}
} }
public interface IBaseTransition{ public interface IBaseTransition{
public bool Condition{ get; set; } public bool Condition{ get; set; }

@ -6,6 +6,8 @@ namespace TNodeCore.Runtime.RuntimeCache{
object GetValue(object model); object GetValue(object model);
void SetValue(object model, object value); void SetValue(object model, object value);
void Reset(object model);
public Type Type{ get; set; } public Type Type{ get; set; }

@ -13,6 +13,8 @@ namespace TNodeCore.Runtime.RuntimeCache{
public class PortAccessor<T1, T2>:IModelPortAccessor{ public class PortAccessor<T1, T2>:IModelPortAccessor{
public readonly Func<T1, T2> Get; public readonly Func<T1, T2> Get;
public readonly Action<T1, T2> Set; public readonly Action<T1, T2> Set;
private readonly Action<T1> _resetFunc;
private readonly T2 _defaultValue;
public PortAccessor(string name,bool property){ public PortAccessor(string name,bool property){
if (property){ if (property){
Type t = typeof(T1); Type t = typeof(T1);
@ -20,10 +22,21 @@ namespace TNodeCore.Runtime.RuntimeCache{
MethodInfo getter = t.GetMethod("get_" + name); MethodInfo getter = t.GetMethod("get_" + name);
MethodInfo setter = t.GetMethod("set_" + name); MethodInfo setter = t.GetMethod("set_" + name);
Type = getter?.ReturnType??setter?.GetParameters()[0].ParameterType; Type = getter?.ReturnType??setter?.GetParameters()[0].ParameterType;
if(getter!=null) if(getter!=null)
Get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, getter); Get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, getter);
if(setter!=null) if(setter!=null)
Set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, setter); Set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, setter);
if (Set != null){
var dummy = Activator.CreateInstance<T1>();
if (Get != null)
_defaultValue = Get(dummy);
_resetFunc += (obj) => {
Set(obj, _defaultValue);
};
}
} }
else{ else{
Type t = typeof(T1); Type t = typeof(T1);
@ -46,6 +59,12 @@ namespace TNodeCore.Runtime.RuntimeCache{
public void SetValue(object model, object value){ public void SetValue(object model, object value){
Set((T1)model,(T2)value); Set((T1)model,(T2)value);
} }
public void Reset(object model){
//Get
_resetFunc?.Invoke((T1)model);
}
public Type Type{ get; set; } public Type Type{ get; set; }
} }
@ -214,19 +233,21 @@ namespace TNodeCore.Runtime.RuntimeCache{
private void CachingImplicitConversion(Type baseType, Type targetType){ private void CachingImplicitConversion(Type baseType, Type targetType){
if (HasImplicitConversion(baseType, targetType)) return; if (!HasImplicitConversion(baseType, targetType)) return;
if (CachedPortConverters.ContainsKey(baseType)&&CachedPortConverters[baseType].ContainsKey(targetType)) return;
//Create Implicit Conversion Helper that caches the implicit cast function //Create Implicit Conversion Helper that caches the implicit cast function
var typeConverter = Activator.CreateInstance(typeof(ImplicitConversionHelper<,>).MakeGenericType(baseType, targetType)) as IPortConverterHelper; var typeConverter = Activator.CreateInstance(typeof(ImplicitConversionHelper<,>).MakeGenericType(baseType, targetType)) as IPortConverterHelper;
if (!CachedPortConverters.ContainsKey(baseType)){ if (!CachedPortConverters.ContainsKey(baseType)){
CachedPortConverters.Add(baseType,new Dictionary<Type,IPortConverterHelper>()); CachedPortConverters.Add(baseType,new Dictionary<Type,IPortConverterHelper>());
} }
CachedPortConverters[baseType].Add(targetType,typeConverter); 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)){
//Find the cached port failed ,check if there is an implicit conversion //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. //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.
@ -384,14 +405,20 @@ namespace TNodeCore.Runtime.RuntimeCache{
var method = typeof(T2).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(T1) }, null); var method = typeof(T2).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(T1) }, null);
if (method == null){ if (method == null){
//Search it in T1 //Search it in T1
method = typeof(T1).GetMethod("op_Implicit", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(T2) }, null); Debug.Log($"{typeof(T1)}");
method = typeof(T1).GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(x => x.ReturnType==typeof(T2) && x.Name=="op_Implicit");
} }
//Create the delegate //Create the delegate
if (method != null) if (method != null)
ConvertFunc = (Func<T1, T2>) Delegate.CreateDelegate(typeof(Func<T1, T2>), method); ConvertFunc = (Func<T1, T2>) Delegate.CreateDelegate(typeof(Func<T1, T2>), method);
if (ConvertFunc == null){
Debug.Log($"{method==null}");
}
} }
public object Convert(object value){ public object Convert(object value){
return ConvertFunc((T1) value); return ConvertFunc((T1) value);
} }
} }

@ -1,18 +1,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using TNode.TNodeCore.Runtime.Models;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using UnityEngine; using UnityEngine;
namespace TNodeCore.Runtime{ namespace TNodeCore.Runtime{
public class ConditionalRuntimeNode:RuntimeNode{ public class ConditionalRuntimeNode:RuntimeNode{
private readonly List<Tuple<string,Func<TransitionCondition>>> _possibleTransition; private readonly List<Tuple<string,Func<IBaseTransition>>> _possibleTransition;
public ConditionalRuntimeNode(NodeData nodeData) : base(nodeData){ public ConditionalRuntimeNode(NodeData nodeData) : base(nodeData){
if (nodeData is ConditionalNode conditionalNode){ if (nodeData is ConditionalNode conditionalNode){
var transitionPort = GetPortsOfType<TransitionCondition>(); var transitionPort = GetPortsOfType<IBaseTransition>();
_possibleTransition = new List<Tuple<string,Func<TransitionCondition>>>(); _possibleTransition = new List<Tuple<string,Func<IBaseTransition>>>();
var allOutput = GetPortsOfType<object>().Where(x => GetPortDirection(x) == Direction.Output); var allOutput = GetPortsOfType<object>().Where(x => GetPortDirection(x) == Direction.Output);
var enumerable = allOutput as string[] ?? allOutput.ToArray(); var enumerable = allOutput as string[] ?? allOutput.ToArray();
if (enumerable.Count() != transitionPort.Length){ if (enumerable.Count() != transitionPort.Length){
@ -22,7 +21,7 @@ namespace TNodeCore.Runtime{
} }
foreach (var port in transitionPort){ foreach (var port in transitionPort){
if(GetPortDirection(port)==Direction.Input) continue; if(GetPortDirection(port)==Direction.Input) continue;
_possibleTransition.Add(new Tuple<string, Func<TransitionCondition>>(port,() => (TransitionCondition)GetOutput(port)) ); _possibleTransition.Add(new Tuple<string, Func<IBaseTransition>>(port,() => (IBaseTransition)GetOutput(port)) );
} }
} }
else{ else{
@ -39,8 +38,8 @@ namespace TNodeCore.Runtime{
} }
public string GetNextNodeId(){ public string GetNextNodeId(){
List<Tuple<string,TransitionCondition>> possibleCondition = _possibleTransition List<Tuple<string,IBaseTransition>> possibleCondition = _possibleTransition
.Select(x=>new Tuple<string,TransitionCondition>(x.Item1,x.Item2())) .Select(x=>new Tuple<string,IBaseTransition>(x.Item1,x.Item2()))
.Where(x=>x.Item2.Condition).ToList(); .Where(x=>x.Item2.Condition).ToList();
possibleCondition.Sort((a, b) => { possibleCondition.Sort((a, b) => {
var compareTo = b.Item2.Priority.CompareTo(a.Item2.Priority); var compareTo = b.Item2.Priority.CompareTo(a.Item2.Priority);

@ -121,6 +121,12 @@ namespace TNodeCore.Runtime{
_portAccessors = RuntimeCache.RuntimeCache.Instance.CachedPortAccessors[_type]; _portAccessors = RuntimeCache.RuntimeCache.Instance.CachedPortAccessors[_type];
} }
public void ResetPortValue(){
foreach (var modelPortAccessor in _portAccessors){
modelPortAccessor.Value.Reset(this.NodeData);
}
}
public List<string> GetInputNodesId(){ public List<string> GetInputNodesId(){
List<string> dependencies = new List<string>(); List<string> dependencies = new List<string>();
foreach (NodeLink link in InputLinks) foreach (NodeLink link in InputLinks)
@ -129,7 +135,6 @@ namespace TNodeCore.Runtime{
} }
return dependencies; return dependencies;
} }
} }
public enum Direction{ public enum Direction{
Input, Input,

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using TNode.TNodeCore.Runtime.Models;
using TNode.TNodeCore.Runtime.Tools; using TNode.TNodeCore.Runtime.Tools;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using UnityEngine; using UnityEngine;
@ -21,7 +20,6 @@ namespace TNodeCore.Runtime.RuntimeModels{
var inNodeId = linkData.inPort.nodeDataId; var inNodeId = linkData.inPort.nodeDataId;
var inNode = _nodes[inNodeId]; var inNode = _nodes[inNodeId];
Debug.Log($"{inNode},{outNode}");
inNode.InputLinks.Add(linkData); inNode.InputLinks.Add(linkData);
} }
public StaticGraph(GraphData graphData){ public StaticGraph(GraphData graphData){
@ -29,8 +27,6 @@ namespace TNodeCore.Runtime.RuntimeModels{
var nodes = graphData.NodeDictionary.Values.ToList(); var nodes = graphData.NodeDictionary.Values.ToList();
var links = graphData.NodeLinks; var links = graphData.NodeLinks;
_nodes = new Dictionary<string, RuntimeNode>(); _nodes = new Dictionary<string, RuntimeNode>();
foreach (var nodeData in nodes){ foreach (var nodeData in nodes){
if(_nodes.ContainsKey(nodeData.id)) continue; if(_nodes.ContainsKey(nodeData.id)) continue;

@ -297,7 +297,8 @@ namespace TNode.TNodeCore.Runtime.Tools{
//TODO looks like this string would be too long to make a cache //TODO looks like this string would be too long to make a cache
var cachedKey = $"{outNode.NodeData.id}-{nodeLink.inPort.portEntryName}"; var cachedKey = $"{outNode.NodeData.id}-{nodeLink.inPort.portEntryName}";
var outValue = OutputCached.ContainsKey(cachedKey) ? OutputCached[cachedKey] : outNode.GetOutput(nodeLink.outPort.portEntryName);; var outValue = OutputCached.ContainsKey(cachedKey) ? OutputCached[cachedKey] : outNode.GetOutput(nodeLink.outPort.portEntryName);
if (_isCachingOutput){ if (_isCachingOutput){
OutputCached[cachedKey] = outValue; OutputCached[cachedKey] = outValue;
} }

@ -88,8 +88,11 @@ namespace TNodeGraphViewImpl.Editor.GraphBlackboard{
bool isRuntimeGraph, bool isRuntimeGraph,
BlackboardSection blackboardSection, int index){ BlackboardSection blackboardSection, int index){
var property = serializedObject.FindProperty("data"); var property = serializedObject.FindProperty("data");
property = property.FindPropertyRelative(field.Name).GetArrayElementAtIndex(index); property = property.FindPropertyRelative(field.Name)?.GetArrayElementAtIndex(index);
if (property == null){
Debug.LogError($"Can not find property {field.Name} in {serializedObject.targetObject.name}");
}
BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){ BlackboardDataEntry entry = new BlackboardDataEntry(field.FieldType){
propertyPath = field.Name+"."+index, propertyPath = field.Name+"."+index,
}; };

@ -28,7 +28,6 @@ namespace TNodeGraphViewImpl.Editor.GraphWatcherView{
} }
var baseNodeViews = gv.nodes.ToList().Select(x=>(IBaseNodeView)x); var baseNodeViews = gv.nodes.ToList().Select(x=>(IBaseNodeView)x);
var node = baseNodeViews.First(x=>x.GetNodeData().id==runtimeNodeGraph.CurrentNode().id); var node = baseNodeViews.First(x=>x.GetNodeData().id==runtimeNodeGraph.CurrentNode().id);
Debug.Log(node.GetNodeData().id);
var nodeView = (Node)node; var nodeView = (Node)node;
_highlightedNode = nodeView; _highlightedNode = nodeView;
_highlightedNode.AddToClassList("highlightNode"); _highlightedNode.AddToClassList("highlightNode");
@ -50,6 +49,9 @@ namespace TNodeGraphViewImpl.Editor.GraphWatcherView{
_highlightedNode.style.borderRightWidth = _highlightedNode.style.borderTopWidth = 0; _highlightedNode.style.borderRightWidth = _highlightedNode.style.borderTopWidth = 0;
} }
runtimeNodeGraph.ResetState(); runtimeNodeGraph.ResetState();
foreach (var runtimeNode in runtimeNodeGraph.GetRuntimeNodes()){
runtimeNode.ResetPortValue();
}
} }
}; };

@ -1,13 +1,12 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using TNode.TNodeCore.Runtime.Models;
using TNodeCore.Editor.Tools.NodeCreator; using TNodeCore.Editor.Tools.NodeCreator;
using TNodeCore.Runtime; using TNodeCore.Runtime;
using TNodeCore.Runtime.Attributes; using TNodeCore.Runtime.Attributes;
using TNodeCore.Runtime.Attributes.Ports; using TNodeCore.Runtime.Attributes.Ports;
using TNodeCore.Runtime.Models; using TNodeCore.Runtime.Models;
using TNodeCore.Runtime.RuntimeModels; using TNodeCore.Runtime.RuntimeModels;
using UnityEditor.VersionControl;
using UnityEngine; using UnityEngine;
namespace Tests{ namespace Tests{

Loading…
Cancel
Save