NodeCanvas Forums › Support › Task skips execution occasionally
Using NC 2.2 currently.
This issue occurs occasionally when I use the following code to end an action task.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Foo : ActionTask { private Bar bar; protected override void OnExecute() { ... // something like initializing bar bar.onCompleted += SomeCallback; } private void SomeCallback() { if (bar != null) { bar.onCompleted -= SomeCallback; EndAction(); } } } |
Sometimes, the action task is not executed at all after the attaching FSM state is entered.
Actually I found the cause. In general, EndAction is called in OnExecute or OnUpdate, but to cover the case like above, EndAction would set an internal boolean ‘latch’ to true, so the the next call of ExecuteAction will return the status without calling the execution function.
The problematical part is that if EndAction is called, latch is set to true, and if the transition is checked continuously, it’s possible that the state transfers to another state, while ‘latch’ is left true, when it comes back to this state, the task will fail to execute.
Of course, A workaround is to mark the completion in my custom callback, and check the mark in OnUpdate and call EndAction if true.
I’m just wondering if calling EndAction via a delegate is suggested or not, and is it possible for NC to reset the internal state of action tasks when a transition is taking place?
Thanks.
Hello,
Thanks for the very detailed info. Actualy the internal state of the action, like the ‘latch’ flag, is reset when the state exits. I *think* the problem here is that your callback is called after the state (and thus action) execute is called in the frame.
All update calls in NC are comming through the MonoManager class.
Can you please try puting the MonoManager script in a positive Execution Order through “Edit > Project Settings > Script Execution Order” and let me know? I asume this will fix the problem.
Also, I would suggest that you unsubscribe the callback in OnStop method to make sure that it unsubscribes whenever the action is stoped for whatever reason (state exit, FSM stoped). For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Foo : ActionTask { private Bar bar; protected override void OnExecute() { ... // something like initializing bar bar.onCompleted += SomeCallback; } protected override void OnStop(){ bar.onCompleted -= SomeCallback; } private void SomeCallback() { if (bar != null) { EndAction(); } } } |
Let me know if this works. In general the goal is for EndAction to be able to be called from anywhere, yes 🙂
Join us on Discord: https://discord.gg/97q2Rjh
Thanks for your quick response.
But I’m afraid postponing the NC update doesn’t help. (I had a try)
After the callback is invoked, EndAction() is called, so the status of the task becomes success and the ‘latch’ flag is set to true, then NC calls update (no matter in the same frame or the next frame). Because NC checks transition before action execution, If the outgoing condition happens to return true at the moment, the current state is exited, EndAction(null) is called, It’s supposed to set ‘latch’ to false. However, since the status of action is not running anymore, the ‘latch’ remains true. The issue occurs when this state is transferred back the next time.
I created a test case to 100% recur this issue. It’s also attached below.
In the test case, the outgoing condition also subscribes to the same event. And you can see every other loop, the test action would fail to execute.
Hello,
Sorry for late reply.
Thanks a lot for all the information again.
So theere are 2 type of fixes that we can use here.
Either make transition checks happen after task execution in FSMState.cs Update() #111, by placing OnUpdate before the CheckTransitions.
Or a more safe aproach (to keep consistency with already made FSMs), would be in ActionTask.cs EndAction #122 to put:
latch = success != null? true : false;
first, even before the status check:
1 2 3 4 5 6 |
latch = success != null? true : false; if (status != Status.Running) return; |
I will probably go with this way in the next version update.
Thanks again!
Join us on Discord: https://discord.gg/97q2Rjh
It works. Cheers 🙂