State Tree Parent State Reenter logic

In State Tree, when a parent state is re-entered it (by default) gets a call to Exit State and Enter State, with the change type EStateTreeStateChangeType::Sustained.

Is there a way to distinguish if this is because a child state of the parent state transitioned to a different child state, or if the parent state itself was reselected?

We have a scenario where we want to do some logic when the parent state is reselected, but not when the active child state of that parent has changed. How can we tell from the params in the EnterState event?

[Attachment Removed]

Hi there,

I’m not sure exactly what setup you have, however In my attempt to recreate and test this I found that the Sustained change type was only present when transitioning from the child state to the parent state (re-entry). This was the case for both exit and enter. From within the editor/blueprints this is about as much as you can do.

Outside of blueprint there is a lot more options. I would recommend creating a state tree task in c++ by deriving from UStateTreeTaskBlueprintBase. There is a lot more information that can be used from the FStateTreeTransitionResult. Additionally using the FStateTreeExecutionContext you can get the active frames, get pointers to the transition, source & current states using the ID from the transition. These pointers can tell you a lot about the state. Name, Gameplay tags, whether it has a parent state etc.

Here is an example that’s not exactly relevant but i will demonstrate how you can get this info:

const FCompactStateTreeState* UMyObject::GetCurrentState(FStateTreeExecutionContext& Context)
{
	if (!Context.IsValid())
	{
		return nullptr;
	}
 
	for (auto Frame : Context.GetActiveFrames())
	{
		const UStateTree* CurrentStateTree = Frame.StateTree;
		if (CurrentStateTree == nullptr)
		{
			continue;
		}
 
		// Get the last valid active state (which should be the actual current state)
		for (int i = Frame.ActiveStates.Num() - 1; i >= 0; --i)
		{
			if (!Frame.ActiveStates[i].IsValid())
			{
				continue;
			}
 
			if (const FCompactStateTreeState* StatePtr = CurrentStateTree->GetStateFromHandle(Frame.ActiveStates[i]))
			{
				return StatePtr;
			}
		}
	}
 
	return nullptr;
}

- Louis

[Attachment Removed]

Ah! I see, I was wrong that you get “Sustained” events in the parent task when child tasks change (but the parent doesn’t). OK, then this does exactly what we want already, thank you.

[Attachment Removed]