NodeGraphProcessor icon indicating copy to clipboard operation
NodeGraphProcessor copied to clipboard

Runtime value of a parameter node

Open mmeiburg opened this issue 4 years ago • 2 comments

Hi,

what is the best way to get the runtime value of an connected Exposed Parameter to an input port.

In my example I have a similar graph like the conditional graph.

image

Here a simple delay node

    public class DelayNode : BaseNode
    {
        [Input("Control")] public ControlLink controlIn;
        [Output("Control")] public ControlLink controlOut;

        [Input, ShowAsDrawer]
        public float duration;
        
        protected override async void Process()
        {
            await Task.Delay(TimeSpan.FromSeconds(duration));
        }

The problem is, I don't get the runtime value by default when I simple start my graph processor. (I wrote an custom editor script where I get all exposed graph properties by a given graph linked in the inspector)

public class SomeCallerClass
{
        public void Play()
        {
            foreach (var p in properties)
                graph.SetParameterValue(p.name, p.value);
            
            processor.Run();
        }
}

Processor code pieces:

public class CustomProcessor : BaseGraphProcessor
{
       // ...
       
        public override void Run()
        {
            InitializeNodes();
            startNode?.OnProcess();
        }
        
        private void InitializeNodes()
        {
            graph.nodes.ForEach(node => node.Initialize(graph));
        }
}

The delay node always get his default value, and not the parameter set before I call Run();

Only if I cache the ParameterNode at the first process by name and call it later like here

        protected bool GetInputParameterValue<T>(string name, out T output)
        {
            output = default(T);
            
            if (string.IsNullOrEmpty(name)) return false;
            
            if (!cachedInputNodes.TryGetValue(name, out var parameterNode))
            {
                parameterNode = inputPorts
                    .FirstOrDefault(x => x.fieldName == name)?
                    .GetEdges()?
                    .Select(x => x.outputNode as ParameterNode)
                    .FirstOrDefault();
                
                if(parameterNode?.output is T) 
                    cachedInputNodes.Add(name, parameterNode);
            }

            if (!(parameterNode?.output is T value))
                return false;

            output = value;
            return true;
        }

Here the changed code that works, but I think its not really comfortable to use.

       protected override async void Process()
       {
           if (GetInputParameterValue<float>(nameof(duration), out var value))
               await Task.Delay(TimeSpan.FromSeconds(value));
       }

Maybe I missed something, but would be cool if I don't habe to find the ParameterNode value by my self.

Anyway, thank you for your great NodeGraphProcessor

mmeiburg avatar Apr 11 '21 05:04 mmeiburg

Okay I can awnser myself :)

With the last version (Fixed parameter node returning a wrong value) I can extend my processor to push all parameter node datas.

public class CustomProcessor : BaseGraphProcessor
{
       // ...
       
        public override void Run()
        {
            #if UNITY_EDITOR
            InitializeParameterNodes();
            #endif
            startNode?.OnProcess();
        }
        
        private void InitializeParameterNodes()
        {
            foreach (var node in graph.nodes.OfType<ParameterNode>())
            {
                node.Initialize(graph);
                node.outputPorts.PushDatas(); 
            }
        }
}

That way I can delete my caching by name stuff and everything works great :)

But I would think that this should not be necessary because OnProcess() should pull all datas (Added with graph.SetParameterValue(...) ) before process. All my nodes call OnProcess() on there ControlLink output nodes. Maybe an issue in PullDatas() ?

// BaseNode.cs

		public void OnProcess()
		{
			inputPorts.PullDatas();

			ExceptionToLog.Call(() => Process());

			InvokeOnProcessed();

			outputPorts.PushDatas();
		}

mmeiburg avatar Apr 11 '21 06:04 mmeiburg

Hello, sorry for the long delay.

I think the issue you have is 'expected' because if I follow correctly the logic of your graph, without your InitializeParameterNodes, the parameter nodes are never processed (because your nodes only process the one connected at the ControlLink). Can you confirm?

If that's the case, then the parameter value is not pushed out of the parameter node. A simple fix if you don't want to implement a dependency system on your nodes to process correctly all the nodes in the graph is to simply go over all the parameters like you did and call the OnProcess() instead of Initialize + PushData()

alelievr avatar May 31 '21 21:05 alelievr