I created a task that triggers an action on my character. That action will eventually modify some blackboard variable.
I registered a listener on the blackboard variable to be notified when it changes. When it happens, I complete the task by calling: FinishLatentTask.
This works well except that I ended up with a dangling Blackboard delegate. Since I’m in the scope of the OnBlackboardChange callback, I cannot call UnregisterObserver without invalidating the iterator of the for loop that notified that the blackboard variable have changed.
Is there a virtual method called when the task cease to be relevant? That mechanic exists for decorator and service, but I don’t think it’s there for the task.
Obviously, I’m trying to avoid ticking the task in order to be event driven and therefore more efficient. I could use the AIMessage, but I thought that listener to a blackboard change was a legit thing to do.
I’m afraid there’s no nice way of doing that currently, and you’re right - unregistering an observer from within of the function called on the observer is not a good idea and by looking at the code could possibly result in a crash I’ll file this as an issue to solve.
Having said that, why aren’t you using Blackboard-based BT decorator to observe BB keys and react to their changes?
As a fallback, for now, you can try postponing observer unregistering by spawning a simple task on game thread that will be executed “before next frame”.
I have a latent task which performs a Barrel Roll on my character. My character was setting a blackboard value that indicates the action currently performed by the character. When the Barrel Roll was performed, the task succeeded. I didn’t want to poll the character to check if the Barrel Roll was performed.
I ended up using an AIMessage like in the MoveTo task you provided. It works well.
As a side note, I feel the OnMessage method signature is a little bit restrictive. It doesn’t forward the flags of the AIMessage, but only send the MessageName and the Status. I modified my engine to pass the entire AIMessage. That way, I’ll be able to subclass the AIMessage to bind data with the message. Is this a change that makes sense for you? I could push the change to your branch.