Is a double deactivation on a btdecorator a bug?
We have been working extensively with behavior trees in our project and have run into a problem which we have been unable to solve. We will try to give as much detail as possible for you to reproduce the problem, but we will simplify the details of the implementation a bit.
We have implemented a decorator that functions as a 'scope' object, overriding OnNodeActivation and OnNodeDeactivation. OnNodeActivation sets a boolean in the actor controlled by the AI controller to true, and OnNodeDeactivation sets that boolean to false. We were operating under the assumption that an activation will always be followed by a deactivation and that deactivation will only be called once. As such deactivation verifies (asserts) that the boolean was not already set to false. This assert however was triggered, but with a very low reproduction rate making it hard to track the underlying issue.
To further look into the issue we added a memory struct to the decorator as is done in the engine also and added extra logging to trace the activation / deactivation pattern. We found that when the assert is triggered, OnNodeDeactivation is called twice in a row (but with some time in between). We added state to the memory struct to try to detect this double activation setting a bool (Activated) when OnNodeActivation is called and setting a different bool (Deactivated) when OnNodeDeactivation is called. Both are set to false in CalculateRawConditionValue and InitializeMemory. We expected that on the second OnNodeDeactivation call Deactivated would already be set to true, but this happened not to be the case. In the end we logged the memory address of the used memory struct as well and found that upon the 2nd entry of OnNodeDeactivation a different address was used.
An example of the log:
The last hexadecimal number on each log line here is the address of the node memory (Obtained through GetNodeMemory(SearchData))
As you can see the memory address it the same for the CalculateRawConditionValue, OnNodeActivation and OnNodeDeactivation. But then the last OnNodeDeactivation has different adress. The state of that memory is not the initial state of the memory (both booleans set to false) nor the state after the first OnNodeDeactivation (both booleans set to true). The state is what the memory would be after OnNodeActivation but before OnNodeDeactivation. To us it seems that the underlying system might have made a copy of the memory after OnNodeActivation and used that for the second OnNodeDeactivation.
The callstack for the 2nd deactivation is:
Some extra information that might be helpful:
What we would expect:
We hope you can provide some insight into what is going wrong, or if we are doing something wrong. Thanks in advance.
Follow this question
Once you sign in you will be able to subscribe for any updates here