Files
UnrealEngine/Engine/Plugins/AI/MassAI/Source/MassAIBehavior/Private/MassStateTreeSchema.cpp
2025-05-18 13:04:45 +08:00

83 lines
2.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MassStateTreeSchema.h"
#include "MassEntityTypes.h"
#include "MassStateTreeDependency.h"
#include "MassStateTreeTypes.h"
#include "StateTree.h"
#include "StateTreeConditionBase.h"
#include "StateTreeConsiderationBase.h"
#include "StateTreeExecutionTypes.h"
#include "StateTreeLinker.h"
#include "Subsystems/WorldSubsystem.h"
#ifndef UE_WITH_MASS_STATETREE_DEPENDENCIES_DEBUG
#define UE_WITH_MASS_STATETREE_DEPENDENCIES_DEBUG 0
#endif
bool UMassStateTreeSchema::IsStructAllowed(const UScriptStruct* InScriptStruct) const
{
// Only allow Mass evals and tasks,and common conditions.
return InScriptStruct->IsChildOf(FMassStateTreeEvaluatorBase::StaticStruct())
|| InScriptStruct->IsChildOf(FStateTreeEvaluatorCommonBase::StaticStruct())
|| InScriptStruct->IsChildOf(FMassStateTreeTaskBase::StaticStruct())
|| InScriptStruct->IsChildOf(FStateTreeConditionBase::StaticStruct())
|| InScriptStruct->IsChildOf(FStateTreeConsiderationBase::StaticStruct());
}
bool UMassStateTreeSchema::IsExternalItemAllowed(const UStruct& InStruct) const
{
// Allow only WorldSubsystems and fragments as external data.
return InStruct.IsChildOf(UWorldSubsystem::StaticClass())
|| UE::Mass::IsA<FMassFragment>(&InStruct)
|| UE::Mass::IsA<FMassSharedFragment>(&InStruct)
|| UE::Mass::IsA<FMassConstSharedFragment>(&InStruct);
}
bool UMassStateTreeSchema::Link(FStateTreeLinker& Linker)
{
Dependencies.Empty();
UE::MassBehavior::FStateTreeDependencyBuilder Builder(Dependencies);
auto BuildDependencies = [&Builder](const UStateTree* StateTree)
{
for (FConstStructView Node : StateTree->GetNodes())
{
if (const FMassStateTreeEvaluatorBase* Evaluator = Node.GetPtr<const FMassStateTreeEvaluatorBase>())
{
Evaluator->GetDependencies(Builder);
}
else if (const FMassStateTreeTaskBase* Task = Node.GetPtr<const FMassStateTreeTaskBase>())
{
Task->GetDependencies(Builder);
}
}
};
TArray<const UStateTree*, TInlineAllocator<4>> StateTrees;
StateTrees.Add(CastChecked<const UStateTree>(GetOuter()));
for (int32 Index = 0; Index < StateTrees.Num(); ++Index)
{
const UStateTree* StateTree = StateTrees[Index];
BuildDependencies(StateTree);
// The StateTree::Link order is not deterministic. Build the dependencies and add them to this list.
for (const FCompactStateTreeState& State : StateTree->GetStates())
{
if (State.LinkedAsset && State.Type == EStateTreeStateType::LinkedAsset)
{
StateTrees.AddUnique(State.LinkedAsset);
}
}
}
#if UE_WITH_MASS_STATETREE_DEPENDENCIES_DEBUG
for (const FStateTreeExternalDataDesc& Desc : Linker.GetExternalDataDescs())
{
const bool bContains = Dependencies.ContainsByPredicate([&Desc](const FMassStateTreeDependency& Other) { return Desc.Struct == Other.Type; });
ensureMsgf(bContains, TEXT("Tree %s is missing a mass dependency"), *StateTree->GetPathName());
}
#endif
return true;
}