diff --git a/Samples/New HelloGraph.asset b/Samples/New HelloGraph.asset index 304ba7e..9d75329 100644 --- a/Samples/New HelloGraph.asset +++ b/Samples/New HelloGraph.asset @@ -17,7 +17,6 @@ MonoBehaviour: - id: 1 - id: 2 - id: 3 - - id: 4 nodeLinks: - inPort: portEntryName: A @@ -38,12 +37,12 @@ MonoBehaviour: portEntryName: Value nodeDataId: 06f5acb9-58d5-41b3-b7f5-bd90f7f9ab94 blackboardData: - id: 5 + id: 4 sceneReference: editorModels: - - id: 6 + - id: 5 graphViewModel: - id: 7 + id: 6 references: version: 1 00000000: @@ -52,7 +51,7 @@ MonoBehaviour: positionInView: serializedVersion: 2 x: -345 - y: 21 + y: -42 width: 0 height: 0 id: 23526615-f15c-4bdf-96c2-38a57d30b10d @@ -64,25 +63,12 @@ MonoBehaviour: blackDragData: HelloGameObject isListElement: 0 00000001: - type: {class: AddNode, ns: Samples, asm: Assembly-CSharp} - data: - positionInView: - serializedVersion: 2 - x: 0 - y: 0 - width: 0 - height: 0 - id: f33d73da-40c5-4b3a-ace7-40105e3489b6 - nodeName: AddNode - entryPoint: 0 - isTest: 0 - 00000002: type: {class: BlackboardDragNode, ns: TNodeCore.Runtime.Models, asm: TNodeCore} data: positionInView: serializedVersion: 2 x: -345 - y: 60 + y: -84 width: 0 height: 0 id: ae519ad8-4bc8-46c5-a98a-dc95bc85b58a @@ -93,13 +79,13 @@ MonoBehaviour: Version=0.0.0.0, Culture=neutral, PublicKeyToken=null blackDragData: HelloGameObject isListElement: 0 - 00000003: + 00000002: type: {class: BlackboardDragNode, ns: TNodeCore.Runtime.Models, asm: TNodeCore} data: positionInView: serializedVersion: 2 x: -345 - y: -21 + y: -126 width: 0 height: 0 id: 06f5acb9-58d5-41b3-b7f5-bd90f7f9ab94 @@ -110,24 +96,20 @@ MonoBehaviour: Version=0.0.0.0, Culture=neutral, PublicKeyToken=null blackDragData: HelloGameObject isListElement: 0 - 00000004: - type: {class: BlackboardDragNode, ns: TNodeCore.Runtime.Models, asm: TNodeCore} + 00000003: + type: {class: AddNode, ns: Samples, asm: Assembly-CSharp} data: positionInView: serializedVersion: 2 - x: 0 - y: 0 + x: -17 + y: -18 width: 0 height: 0 - id: a705abd9-5c22-4410-812f-d824ddfa60d8 - nodeName: + id: f33d73da-40c5-4b3a-ace7-40105e3489b6 + nodeName: AddNode entryPoint: 0 isTest: 0 - blackboardDragTypeString: System.String, mscorlib, Version=4.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - blackDragData: HelloString - isListElement: 0 - 00000005: + 00000004: type: {class: HelloBlackboard, ns: TNode.Samples, asm: Assembly-CSharp} data: positionInView: @@ -143,7 +125,7 @@ MonoBehaviour: - {x: 0, y: 0, z: 0} V2S: - {x: 0, y: 0} - 00000006: + 00000005: type: {class: PlacematModel, ns: TNode.TNodeCore.Editor.Models, asm: TNodeCore} data: positionInView: @@ -156,7 +138,7 @@ MonoBehaviour: hostModels: [] zOrder: 0 title: Title - 00000007: + 00000006: type: {class: GraphViewModel, ns: TNode.TNodeCore.Editor.Models, asm: TNodeCore} data: positionInView: diff --git a/TNodeCore/Runtime/Attributes/Ports/PortAttribute.cs b/TNodeCore/Runtime/Attributes/Ports/PortAttribute.cs index 7aad3cc..c4327b4 100644 --- a/TNodeCore/Runtime/Attributes/Ports/PortAttribute.cs +++ b/TNodeCore/Runtime/Attributes/Ports/PortAttribute.cs @@ -32,7 +32,7 @@ namespace TNodeCore.Runtime.Attributes.Ports{ Path } [MeansImplicitUse] - [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] public class PortAttribute:System.Attribute{ public readonly string Name; public readonly PortNameHandling NameHandling; diff --git a/TNodeCore/Runtime/Components/ConditionalGraph.cs b/TNodeCore/Runtime/Components/ConditionalGraph.cs index 8419a4f..1495d81 100644 --- a/TNodeCore/Runtime/Components/ConditionalGraph.cs +++ b/TNodeCore/Runtime/Components/ConditionalGraph.cs @@ -17,6 +17,17 @@ namespace TNode.TNodeCore.Runtime.Components{ } EntryNode = entry.FirstOrDefault() as ConditionalRuntimeNode; } + + + + public void Run(){ + var res = StepForward(); + while (StepForward().MoveNext()){ + + } + + + } public IEnumerator StepForward(){ CurrentNode = EntryNode; @@ -24,7 +35,7 @@ namespace TNode.TNodeCore.Runtime.Components{ //First let's process the node CurrentNode.NodeData.Process(); //Then check if there are conditional transitions - var conditionalTransitions = CurrentNode.GetNextNodesId(); + var conditionalTransitions = CurrentNode.GetConditionalNextIds(); var transitionNode = new List(); foreach (var conditionalTransition in conditionalTransitions){ diff --git a/TNodeCore/Runtime/ConditionalRuntimeNode.cs b/TNodeCore/Runtime/ConditionalRuntimeNode.cs index 4b8c8f9..516975a 100644 --- a/TNodeCore/Runtime/ConditionalRuntimeNode.cs +++ b/TNodeCore/Runtime/ConditionalRuntimeNode.cs @@ -22,7 +22,7 @@ namespace TNodeCore.Runtime{ } } - public string[] GetNextNodesId(){ + public string[] GetConditionalNextIds(){ var ports = PossibleTransition.Where(x => x.Item2()); var portNames = ports.Select(x => x.Item1); //Search output links to found the link contains portNames as outport's name diff --git a/TNodeCore/Runtime/Models/NodeData.cs b/TNodeCore/Runtime/Models/NodeData.cs index b59c9e8..56d7813 100644 --- a/TNodeCore/Runtime/Models/NodeData.cs +++ b/TNodeCore/Runtime/Models/NodeData.cs @@ -26,6 +26,9 @@ namespace TNodeCore.Runtime.Models{ public virtual void Process(){ } + + + public virtual IEnumerator AfterProcess(){ yield return null; } diff --git a/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs b/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs index ba806da..3e04081 100644 --- a/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs +++ b/TNodeCore/Runtime/RuntimeCache/RuntimeCache.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using TNodeCore.Runtime.Attributes; +using TNodeCore.Runtime.Attributes.Ports; using TNodeCore.Runtime.Interfaces; using TNodeCore.Runtime.Models; using UnityEngine; @@ -34,10 +35,43 @@ namespace TNodeCore.Runtime.RuntimeCache{ public void SetValue(object model, object value){ Set((T1)model,(T2)value); } - public Type Type{ get; set; } } + public class MethodAccessorInput:IMethodAccessorInput{ + public readonly Action Set; + + public MethodAccessorInput(string methodName){ + Type t = typeof(T1); + MethodInfo setter = t.GetMethod(methodName); + if (setter != null) + Set = (Action) Delegate.CreateDelegate(typeof(Action), null, setter); + } + + public void SetValue(object model,object value){ + Set((T1)model,(T2)value); + } + } + + public class MethodAccessorOutput : IMethodAccessorOutput{ + public readonly Func Get; + + public MethodAccessorOutput(string methodName){ + Type t = typeof(T1); + MethodInfo getter = t.GetMethod(methodName); + if(getter!=null) + Get = (Func)Delegate.CreateDelegate(typeof(Func), null, getter); + + + } + public object GetValue(object model){ + return Get((T1)model); + } + } + public interface IMethodAccessorInput{ + public void SetValue(object model,object o); + } + internal class PortConverterHelper : IPortConverterHelper{ private readonly PortTypeConversion _converter; public PortConverterHelper(Type type){ @@ -78,6 +112,8 @@ namespace TNodeCore.Runtime.RuntimeCache{ } //delegate return a value from a nodedata public delegate object GetValueDelegate(Model nodeData); + public delegate void CachedInputFunction(Model nodeData,object value); + public delegate object CachedOutputFunction(Model nodeData); public delegate void SetValueDelegate(Model nodeData,object value); @@ -88,6 +124,11 @@ namespace TNodeCore.Runtime.RuntimeCache{ new Dictionary>(); public readonly Dictionary> CachedPropertyAccessors = new Dictionary> (); + public readonly Dictionary> InputMethodPorts = new Dictionary>(); + + public readonly Dictionary> OutputMethodPorts = + new Dictionary>(); + /// /// TODO: Converters now work globally, but it should be possible to specify a converter for a specific graph.but it will be too nested.so in current implementation, we will use a global converter. /// @@ -179,6 +220,7 @@ namespace TNodeCore.Runtime.RuntimeCache{ } } private readonly Dictionary,bool> _possibleImplicitConversions = new Dictionary,bool> (); + public bool HasImplicitConversion(Type baseType, Type targetType){ var tuple = new Tuple(baseType, targetType); if (_possibleImplicitConversions.ContainsKey(tuple)){ @@ -277,23 +319,39 @@ namespace TNodeCore.Runtime.RuntimeCache{ } } } - public static IModelPropertyAccessor Create(string propName,Type targetType,Type valueType){ + //TODO: CACHE IT AS FUNCTION + private static IModelPropertyAccessor CreatePropertyCache(string propName,Type targetType,Type valueType){ var makeGenericType = typeof (PropAccessor<,>).MakeGenericType(targetType,valueType); var constructor = makeGenericType.GetConstructor(new Type[]{typeof(string)}); var instance = constructor?.Invoke(new object[]{propName}); return (IModelPropertyAccessor) instance; } + public static IMethodAccessorInput CreateMethodInputCache(string methodName,Type targetType,Type inputTypes){ + var makeGenericType = typeof (MethodAccessorInput<,>).MakeGenericType(targetType,inputTypes); + var constructor = makeGenericType.GetConstructor(new Type[]{typeof(string)}); + var instance = constructor?.Invoke(new object[]{methodName}); + return (IMethodAccessorInput) instance; + } + public static IMethodAccessorOutput CreateMethodOutputCache(string methodName,Type targetType,Type outputTypes){ + var makeGenericType = typeof (MethodAccessorOutput<,>).MakeGenericType(targetType,outputTypes); + var constructor = makeGenericType.GetConstructor(new Type[]{typeof(string)}); + var instance = constructor?.Invoke(new object[]{methodName}); + return (IMethodAccessorOutput) instance; + } public void CacheRuntimeNodeData(Type type){ if (type == null) return; if(!CachedDelegatesForGettingValue.ContainsKey(type)){ CachedDelegatesForGettingValue.Add(type, new Dictionary()); CachedDelegatesForSettingValue.Add(type,new Dictionary()); CachedPropertyAccessors.Add(type,new Dictionary()); - + InputMethodPorts.Add(type,new Dictionary()); + OutputMethodPorts.Add(type,new Dictionary()); + + var properties = type.GetProperties(); foreach(var property in properties){ - var propertyAccessor = Create(property.Name,type,property.PropertyType); + var propertyAccessor = CreatePropertyCache(property.Name,type,property.PropertyType); CachedPropertyAccessors[type].Add(property.Name,propertyAccessor); } //register the fields @@ -308,8 +366,46 @@ namespace TNodeCore.Runtime.RuntimeCache{ } } + var methods = type.GetMethods(); + foreach(var method in methods){ + //Check if the method has an [Port] attribute + var portAttribute = method.GetCustomAttribute(); + if(portAttribute != null){ + + //if the port is an input port. cached it as an function of setting value + + if(portAttribute is InputAttribute){ + var inputMethodAccessor = CreateMethodInputCache(method.Name, type, + method.GetParameters()[0].ParameterType); + InputMethodPorts[type].Add(method.Name,inputMethodAccessor); + + } + + if (portAttribute is OutputAttribute){ + var outputMethodAccessor = CreateMethodOutputCache(method.Name, type, + method.ReturnType); + OutputMethodPorts[type].Add(method.Name,outputMethodAccessor); + } + } + + } + } + } + + private SetValueDelegate SetValueDelegateForMethod(MethodInfo method){ + //Check if the method has not an return type + if(method.ReturnType == typeof(void)){ + //check if the method has only one parameter + if(method.GetParameters().Length == 1){ + //Cache the method + var methodDelegate = (SetValueDelegate) Delegate.CreateDelegate(typeof(SetValueDelegate),method); + return methodDelegate; + } } + + return null; } + private GetValueDelegate GetValueDelegateForField(FieldInfo field){ return field.GetValue; @@ -322,6 +418,11 @@ namespace TNodeCore.Runtime.RuntimeCache{ } + public interface IMethodAccessorOutput{ + object GetValue(object model); + } + + public class ImplicitConversionHelper : IPortConverterHelper{ public Func ConvertFunc; public ImplicitConversionHelper(){ diff --git a/TNodeCore/Runtime/RuntimeNode.cs b/TNodeCore/Runtime/RuntimeNode.cs index 713eb00..3062874 100644 --- a/TNodeCore/Runtime/RuntimeNode.cs +++ b/TNodeCore/Runtime/RuntimeNode.cs @@ -34,6 +34,7 @@ namespace TNodeCore.Runtime{ public string[] GetPortsOfType (){ var ports = new List(); foreach (var port in _portAccessors.Keys){ + if(_portAccessors[port].Type==typeof(T)){ ports.Add(port); }