[UE 5.5] StateTrees require manual recompilation in editor on every load. StateTrees fail in packaged builds.

I ran into an issue where some StateTrees fail to initialize properly and require re-compilation every single time the editor is run. These StateTree assets also fail to build for packaged builds. These are the only error messages that are printed when the StateTrees fail initialization:

LogStateTree: Warning: StateTree /Game/AI/StateTree_AI/ST_DefaultNPC.ST_DefaultNPC: could not compile. Please resave the StateTree asset.

LogStateTree: Warning: AIC_DefaultNPC_C_0: FStateTreeExecutionContext::FStateTreeExecutionContext: StateTree asset is not valid ('AIC_DefaultNPC_C_0' using StateTree 'StateTree /Game/AI/StateTree_AI/ST_DefaultNPC.ST_DefaultNPC')

There are no compile errors whatsoever in these StateTrees. In order to work around being required to re-compile multiple StateTrees every editor run, I simple overload the StateTreeAIComponent and re-compile it in code:

void UBFStateTreeAIComponent::InitializeComponent()
{
	Super::InitializeComponent();
	if (StateTreeRef.IsValid())
	{
		UStateTree* stateTree = const_cast<UStateTree*>(StateTreeRef.GetStateTree());
		stateTree->LastCompiledEditorDataHash = 0xFAFAFAFA;
		stateTree->CompileIfChanged();
		return;
	}
}

This obviously will not work in packaged builds because StateTree compilation is entirely within the editor.

This bug does not appear to be related to the complexity of the StateTree as I have reproduced this with an extremely simple StateTree that has no custom tasks, parameters, evaluators, conditions, etc.

Looking into this a little more, the error messages show that this appears to be an engine/editor initialization order issue. The only place where the string “could not compile. Please resave the StateTree asset” could be printed is if the StateTree compilation delegates are not bound:

void UStateTree::CompileIfChanged()
{
	if (UE::StateTree::Delegates::OnRequestCompile.IsBound() && UE::StateTree::Delegates::OnRequestEditorHash.IsBound())
	{
		... [SNIP] ...
	}
	else
	{
		ResetCompiled();
		UE_LOG(LogStateTree, Warning, TEXT("%s: could not compile. Please resave the StateTree asset."), *GetFullName());
	}
}

One interesting observation is that if the failing StateTrees are not bound to any AI Controllers and their StateTree editor window is open, then the editor log will show them as successfully compiling when you load a map and those editor windows open.

Note that this does not appear to be a new issue as it was brought up in April 2022 as well - StateTree requires compile in order to run on editor start

If anyone has any ideas around this I would greatly appreciate this as it blocks being able to test in packaged builds. The next thing I’m going to try is runtime binding of StateTrees to StateTreeAIComponents to work around the potential initialization order issue noted above.

1 Like

For the time being, I have found a workaround for these issues.

If I store my StateTrees in a DataTable, load the DataTable during my GameInstance initialization then fetch and bind the desired StateTree to my custom derived StateTreeAIComponent class during InitializeComponent then I have no problems. The StateTrees remain compiled, no error messages are thrown relating to StateTrees and packaged builds work as expected.

I wasn’t able to track down exactly what was going wrong since I am using the UE 5.5 binaries and not the source build, but this seems like something that should be looked into since it fails in very obscure ways.

I just hit this as well. For me, the root cause was the state tree initialize/compile being called before the state tree editor module could register the “OnRequestCompile” callback.

That is, this compile code:

void UStateTree::Compile()
{
	if (UE::StateTree::Delegates::OnRequestCompile.IsBound())
	{
		UE_LOG(LogStateTree, Log, TEXT("%s: Editor data has changed. Recompiling state tree."), *GetFullName());
		UE::StateTree::Delegates::OnRequestCompile.Execute(*this);
	}
	else
	{
		ResetCompiled();
		UE_LOG(LogStateTree, Warning, TEXT("%s: could not compile. Please resave the StateTree asset."), *GetFullName());
	}
}

was running before the code that registers that OnRequestCompile delegate, which happens in the state tree editor module startup:

void FStateTreeEditorModule::StartupModule()
{
UE::StateTree::Delegates::OnRequestCompile.BindStatic(&UE::StateTree::Editor::CompileStateTree);
//...
}

I used an engine binaries build (5.5) with a debug game editor configuration and was able to breakpoint on the first line of the void UStateTree::Compile() function (also breakpoint the startup module and you can confirm one is happening before the other).

In my case, there was an asset being loaded due to a strong uobject reference in an extension to project settings for the project, so on editor startup it was loading the state tree WAY early, which would try to compile, but before the state tree editor module was even loaded.

I fixed it by changing one of the object references to a soft object pointer, and the state tree is no longer loaded early and properly compiles when it’s loaded further down.

Hopefully a breakpoint as mentioned above could help you track down what’s causing that compile early in your case.

Hope this helps!

1 Like

Ah right, I forgot to enable PDB downloads on the engine binaries.

Anyways, turns out the issue in my case is I was loading a fallback blueprint class via ConstructorHelpers::FClassFinder just in case someone entered a bad value in a json file for a character definition. Easy enough fix here.

Thanks for the advice!