@ -7,20 +7,53 @@ using UnityEngine; 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					namespace  TNodeCore.Components {  
			
		
	
		
			
				
					    public  class  RuntimeGraph : MonoBehaviour {   
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Graph data reference to be used in runtime   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        public  GraphData  graphData ;   
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Runtime copy of scene node data to hold references to scene objects   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        public  List < SceneNodeData >  sceneNodes ;   
			
		
	
		
			
				
					          
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Map of node id to runtime node   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        public  readonly  Dictionary < string ,  RuntimeNode >  RuntimeNodes  =  new  Dictionary < string ,  RuntimeNode > ( ) ;   
			
		
	
		
			
				
					        ///<summary>   
			
		
	
		
			
				
					        /// The graph tool the current runtime graph is using   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        private  GraphTool  _ graphTool ;   
			
		
	
		
			
				
					          
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Inner graph tool to help with graph operations   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        private  class  GraphTool {   
			
		
	
		
			
				
					              
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Topological order of the graph nodes   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            [NonSerialized]  
			
		
	
		
			
				
					            public  readonly  List < RuntimeNode >  TopologicalOrder  =  new  List < RuntimeNode > ( ) ;   
			
		
	
		
			
				
					              
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Entry nodes of the graph. These are the nodes that has no input.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            public  readonly  List < RuntimeNode >  EntryNodes  =  new  List < RuntimeNode > ( ) ;   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Cached data for Dependency traversal.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            public  readonly  Dictionary < string ,  object >  OutputCached  =  new  Dictionary < string ,  object > ( ) ;   
			
		
	
		
			
				
					              
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Ssed to detect if the graph tool is caching the output data of the node   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            private  bool  _ isCachingOutput  =  false ;   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// elements are read only ,do not modify them   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            public  readonly  Dictionary < string ,  RuntimeNode >  RuntimeNodes ;   
			
		
	
		
			
				
					            //Traverse and process all nodes in a topological order,dependency of the node is already resolved.if you want to run specific node,you can use RunNodeDependently instead   
			
		
	
		
			
				
					            public  void  DirectlyTraversal ( ) {   
			
		
	
		
			
				
					                foreach  ( var  node  in  TopologicalOrder ) {   
			
		
	
		
			
				
					                    var  links  =  node . InputLink ;   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -30,26 +63,76 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					                    node . NodeData . Process ( ) ;   
			
		
	
		
			
				
					                }   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            public  void  DependencyTraversal ( RuntimeNode  runtimeNode ) {   
			
		
	
		
			
				
					          
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Cache out port data in the graph tool so that we can directly access the output.   
			
		
	
		
			
				
					            /// The two function assume there will be no change happens in scene nodes or blackboard referenced data during the running,so in a dependency traversal for some   
			
		
	
		
			
				
					            /// batch of nodes.the nodes could directly access the output data in the graph tool instead of waiting dependency traversal resolve the result of the output.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            public  void  StartCachingPort ( ) {   
			
		
	
		
			
				
					                _ isCachingOutput  =  true ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            public  void  EndCachingPort ( ) {   
			
		
	
		
			
				
					                _ isCachingOutput  =  false ;   
			
		
	
		
			
				
					                OutputCached . Clear ( ) ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Resolve dependencies by a deep first search,the depended nodes will be processed to satisfy the need of the the given runtime node   
			
		
	
		
			
				
					            /// Note it's a recursive function.if you want directly traverse all nodes with dependency resolved ,use DirectlyTraversal() instead.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            /// <param name="runtimeNode">The node you want to resolve dependency</param>   
			
		
	
		
			
				
					            /// <param name="dependencyLevel">search depth,no need provide a number when use outside</param>   
			
		
	
		
			
				
					            public  void  RunNodeDependently ( RuntimeNode  runtimeNode , int  dependencyLevel = 0 ) {   
			
		
	
		
			
				
					                var  links  =  runtimeNode . InputLink ;   
			
		
	
		
			
				
					                foreach  ( var  link  in  links ) {   
			
		
	
		
			
				
					                    var  outputNode  =  RuntimeNodes [ link . outPort . nodeDataId ] ;   
			
		
	
		
			
				
					                    DependencyTraversal ( outputNode ) ;   
			
		
	
		
			
				
					                    RunNodeDependently ( outputNode , dependencyLevel + 1 ) ;   
			
		
	
		
			
				
					                    HandlingLink ( link ) ;   
			
		
	
		
			
				
					                }   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                if  ( dependencyLevel  >  DependencyLevelMax ) {   
			
		
	
		
			
				
					                    throw  new  Exception ( "Dependency anomaly detected,check if there is a loop in the graph" ) ;   
			
		
	
		
			
				
					                }   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         
			
		
	
		
			
				
					                //if the runtime node has no output ,it will not be processed   
			
		
	
		
			
				
					                if  ( runtimeNode . OutputLink . Count  = =  0  & &  dependencyLevel  ! =  0 ) {   
			
		
	
		
			
				
					                    return ;   
			
		
	
		
			
				
					                }   
			
		
	
		
			
				
					                runtimeNode . NodeData . Process ( ) ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					                  
			
		
	
		
			
				
					            
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Max depth of dependency traversal,in case of some special situation. the dependency level bigger than this number will be considered as a loop.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            private  const  int  DependencyLevelMax  =  1 1 4 5 ;   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Handling a node link to transfer data from it's output side to the input side   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            /// <param name="nodeLink">Link you want to process</param>   
			
		
	
		
			
				
					            public  void  HandlingLink ( NodeLink  nodeLink ) {   
			
		
	
		
			
				
					                //out node is node output data   
			
		
	
		
			
				
					                //in node is node receive data   
			
		
	
		
			
				
					                var  inNode  =  RuntimeNodes [ nodeLink . inPort . nodeDataId ] ;   
			
		
	
		
			
				
					                var  outNode  =  RuntimeNodes [ nodeLink . outPort . nodeDataId ] ;   
			
		
	
		
			
				
					                  
			
		
	
		
			
				
					                //out node is node output data   
			
		
	
		
			
				
					                //in node is node receive data   
			
		
	
		
			
				
					                var  outValue  =  outNode . GetOutput ( nodeLink . outPort . portEntryName ) ;   
			
		
	
		
			
				
					                  
			
		
	
		
			
				
					                //TODO looks like this string would be too long to make a cache   
			
		
	
		
			
				
					                  
			
		
	
		
			
				
					                var  cachedKey  =  $"{outNode.NodeData.id}-{nodeLink.inPort.portEntryName}" ;   
			
		
	
		
			
				
					                var  outValue  =  OutputCached . ContainsKey ( cachedKey )  ?  OutputCached [ cachedKey ]  :  outNode . GetOutput ( nodeLink . outPort . portEntryName ) ; ;   
			
		
	
		
			
				
					                if  ( _ isCachingOutput ) {   
			
		
	
		
			
				
					                    OutputCached [ cachedKey ]  =  outValue ;   
			
		
	
		
			
				
					                }   
			
		
	
		
			
				
					                inNode . SetInput ( nodeLink . inPort . portEntryName ,  outValue ) ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            /// <summary>   
			
		
	
		
			
				
					            /// Constructor of the graph tool,it will traverse the graph and build the topological order of the graph.   
			
		
	
		
			
				
					            /// </summary>   
			
		
	
		
			
				
					            /// <param name="list">List of nodes you need to traversal to build graph tool</param>   
			
		
	
		
			
				
					            /// <param name="graphNodes">Map stores the mapping of node data id to runtime node</param>   
			
		
	
		
			
				
					          
			
		
	
		
			
				
					            public  GraphTool ( List < RuntimeNode >  list ,  Dictionary < string ,  RuntimeNode >  graphNodes ) {   
			
		
	
		
			
				
					                RuntimeNodes  =  graphNodes ;   
			
		
	
		
			
				
					                if  ( list  = =  null )  return ;   
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -87,10 +170,20 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					              
			
		
	
		
			
				
					              
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Holding the reference of the blackboard ,but it will be override by the runtime graph   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        [SerializeReference]  
			
		
	
		
			
				
					        public  BlackboardData  runtimeBlackboardData ;   
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Check if the runtime graph is build .a built graph has a graph tool set up   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        [NonSerialized]  
			
		
	
		
			
				
					        private  bool  _ build  =  false ;   
			
		
	
		
			
				
					          
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Build the graph tool and other dependencies for the runtime graph   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        public  void  Build ( ) {   
			
		
	
		
			
				
					              
			
		
	
		
			
				
					            var  link  =  graphData . NodeLinks ;   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -109,6 +202,11 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					            _ build  =  true ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Cast the node data to a runtime node   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        /// <param name="nodeData">Node data you provided</param>   
			
		
	
		
			
				
					        /// <returns></returns>   
			
		
	
		
			
				
					        public  RuntimeNode  Get ( NodeData  nodeData ) {   
			
		
	
		
			
				
					            if ( ! _ build )   
			
		
	
		
			
				
					                Build ( ) ;   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -117,20 +215,24 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            return  null ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        /// <summary>   
			
		
	
		
			
				
					        /// Get the runtime node from an id   
			
		
	
		
			
				
					        /// </summary>   
			
		
	
		
			
				
					        /// <param name="id"></param>   
			
		
	
		
			
				
					        /// <returns></returns>   
			
		
	
		
			
				
					        public  RuntimeNode  Get ( string  id ) {   
			
		
	
		
			
				
					            if  ( RuntimeNodes . ContainsKey ( id ) ) {   
			
		
	
		
			
				
					                return  RuntimeNodes [ id ] ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            return  null ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        //DFS search for resolving dependency    
			
		
	
		
			
				
					        public  bool  Resolve Dependency ( NodeData  startNode ) {   
			
		
	
		
			
				
					        //DFS search to run a node.    
			
		
	
		
			
				
					        public  bool  RunOn Dependency ( NodeData  startNode ) {   
			
		
	
		
			
				
					            if ( ! _ build )   
			
		
	
		
			
				
					                Build ( ) ;   
			
		
	
		
			
				
					            if  ( _ graphTool  = =  null )   
			
		
	
		
			
				
					                return  false ;   
			
		
	
		
			
				
					            _ graphTool . DependencyTraversal ( Get ( startNode ) ) ;   
			
		
	
		
			
				
					            _ graphTool . RunNodeDependently ( Get ( startNode ) ) ;   
			
		
	
		
			
				
					            return  true ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        public  bool  ResolveDependency ( ) {   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -152,10 +254,20 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					              
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        public  List < RuntimeNode >  GetRuntimeNodesOfType < T > ( ) {   
			
		
	
		
			
				
					            return  RuntimeNodes . Values . Where ( x  = >  x . NodeType  = =  typeof ( T ) ) . ToList ( ) ;   
			
		
	
		
			
				
					            return  RuntimeNodes . Values . Where ( x  = >  typeof ( T ) . IsAssignableFrom ( x . NodeType ) ) . ToList ( ) ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        public   List < RuntimeNode >  GetRuntimeNodesOfType ( Type  type ) {   
			
		
	
		
			
				
					            return  RuntimeNodes . Values . Where ( x  = >  x . NodeType  = =  type ) . ToList ( ) ;   
			
		
	
		
			
				
					            return  RuntimeNodes . Values . Where ( x  = >  type . IsAssignableFrom ( type ) ) . ToList ( ) ;   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        public  void  RunNodesOfType ( Type  t ) {   
			
		
	
		
			
				
					            var  nodes  =  GetRuntimeNodesOfType ( t ) ;   
			
		
	
		
			
				
					            _ graphTool . StartCachingPort ( ) ;   
			
		
	
		
			
				
					            foreach  ( var  runtimeNode  in  nodes ) {   
			
		
	
		
			
				
					                RunOnDependency ( runtimeNode . NodeData ) ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					            _ graphTool . EndCachingPort ( ) ;   
			
		
	
		
			
				
					              
			
		
	
		
			
				
					              
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        private  void  ModifyOrCreateOutNode ( NodeLink  linkData ) {   
			
		
	
		
			
				
					            var  outNodeId  =  linkData . outPort . nodeDataId ;   
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -170,7 +282,7 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					        public  void  OnValidate ( ) {   
			
		
	
		
			
				
					            if ( runtimeBlackboardData = = null | | runtimeBlackboardData . GetType ( ) = = typeof ( BlackboardData ) ) {   
			
		
	
		
			
				
					                if  ( graphData  ! =  null )   
			
		
	
		
			
				
					                    runtimeBlackboardData  =  graphData . blackboardData . Clone ( )  as  BlackboardData ;   
			
		
	
		
			
				
					                    runtimeBlackboardData  =  graphData . blackboardData ? . Clone ( )  as  BlackboardData ;   
			
		
	
		
			
				
					            }   
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -186,6 +298,7 @@ namespace TNodeCore.Components{ 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        public  void  Start ( ) {   
			
		
	
		
			
				
					            Build ( ) ;   
			
		
	
		
			
				
					            
			
		
	
		
			
				
					        }   
			
		
	
		
			
				
					        public  virtual  void  RuntimeExecute ( ) {   
			
		
	
		
			
				
					            _ graphTool . DirectlyTraversal ( ) ;