Hello.
Broadcast Delegate using a StateTree Delegate Dispatcher in the parent does not work under certain conditions.
I have attached a reproduction project and the reproduction method is as follows.
- Create states hierarchy in the state tree in the order of Root - A - B and set the Selection Behavior of state A to Try Enter.
- Create a StateTree Task Blueprint and use a timer node on the EnterState event to call a Broadcast Delegate using the StateTreeDelegateDispatcher of the task Blueprint member after n seconds.
- Add a Delay task to state A and set duration as 2 seconds, add the task created above and set duration as 6 seconds, and add transition to move to state B when On State Succeeded.
- Add a Delay task to the B state and set Run Forever to true, then add a transition to the Root state by specifying the Delegate Dispatcher in the task of state A as On Delegate.
- As a result of execution, it entered state A, entered state B 2 seconds later, and was expected to transition according to the delegate 4 seconds later, but the following log occurred: “LogStateTree: Error: Failed to broadcast the delegate. The instance probably stopped.”
I wonder if it is the engine’s intention for delegates to not work in this way, and if it’s appropriate to use them with below modification, since they work as expected.
StateTreeAsyncExecutionContext.cpp(112)
(Before)
`UE::StateTree::Async::FActivePathInfo ActivePath = GetActivePathInfo();
if (ActivePath.IsValid())
{
FStateTreeExecutionState& Exec = Storage->GetMutableExecutionState();
Exec.DelegateActiveListeners.BroadcastDelegate(Dispatcher, Exec);
if (UE::StateTree::ExecutionContext::MarkDelegateAsBroadcasted(Dispatcher, *ActivePath.Frame, *Storage))
{
ScheduleNextTick(Owner.Get(), StateTree.Get(), *Storage);
}
return true;
}`
(After)
`if (IsValidInstanceStorage())
{
FStateTreeExecutionState& Exec = Storage->GetMutableExecutionState();
int32 FrameIndex = Exec.IndexOfActiveFrame(FrameID);
if (FrameIndex != INDEX_NONE)
{
FStateTreeExecutionFrame* CurrentFrame = &Exec.ActiveFrames[FrameIndex];
if (CurrentFrame)
{
Exec.DelegateActiveListeners.BroadcastDelegate(Dispatcher, Exec);
if (UE::StateTree::ExecutionContext::MarkDelegateAsBroadcasted(Dispatcher, *CurrentFrame, *Storage))
{
ScheduleNextTick(Owner.Get(), StateTree.Get(), *Storage);
return true;
}
}
}
}`