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

116 lines
4.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MassStateTreeTrait.h"
#include "MassStateTreeFragments.h"
#include "MassStateTreeSubsystem.h"
#include "MassAIBehaviorTypes.h"
#include "StateTree.h"
#include "VisualLogger/VisualLogger.h"
#include "MassEntityTemplateRegistry.h"
#include "Engine/World.h"
#include "MassEntityUtils.h"
void UMassStateTreeTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const
{
FMassEntityManager& EntityManager = UE::Mass::Utils::GetEntityManagerChecked(World);
UMassStateTreeSubsystem* MassStateTreeSubsystem = World.GetSubsystem<UMassStateTreeSubsystem>();
if (!MassStateTreeSubsystem && !BuildContext.IsInspectingData())
{
UE_VLOG(&World, LogMassBehavior, Error, TEXT("Failed to get Mass StateTree Subsystem."));
return;
}
if (!StateTree && !BuildContext.IsInspectingData())
{
UE_VLOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree asset is not set or unavailable."));
return;
}
if (StateTree != nullptr && !BuildContext.IsInspectingData() && !StateTree->IsReadyToRun())
{
UE_VLOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree asset is ready to run."));
return;
}
FMassStateTreeSharedFragment SharedStateTree;
SharedStateTree.StateTree = StateTree;
const FConstSharedStruct StateTreeFragment = EntityManager.GetOrCreateConstSharedFragment(SharedStateTree);
BuildContext.AddConstSharedFragment(StateTreeFragment);
BuildContext.AddFragment<FMassStateTreeInstanceFragment>();
}
bool UMassStateTreeTrait::ValidateTemplate(const FMassEntityTemplateBuildContext& BuildContext, const UWorld& World, FAdditionalTraitRequirements& OutTraitRequirements) const
{
UMassStateTreeSubsystem* MassStateTreeSubsystem = World.GetSubsystem<UMassStateTreeSubsystem>();
if (!MassStateTreeSubsystem)
{
UE_VLOG(&World, LogMassBehavior, Error, TEXT("Failed to get Mass StateTree Subsystem."));
return false;
}
if (!StateTree)
{
UE_VLOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree asset is not set or unavailable."));
return false;
}
// Make sure all the required subsystems can be found.
bool bIssuesFound = false;
for (const FStateTreeExternalDataDesc& ItemDesc : StateTree->GetExternalDataDescs())
{
if (ensure(ItemDesc.Struct) && ItemDesc.Requirement == EStateTreeExternalDataRequirement::Required)
{
if (ItemDesc.Struct->IsChildOf(UWorldSubsystem::StaticClass()))
{
if (BuildContext.IsInspectingData() == false)
{
const TSubclassOf<UWorldSubsystem> SubClass = Cast<UClass>(const_cast<UStruct*>(ToRawPtr(ItemDesc.Struct)));
USubsystem* Subsystem = World.GetSubsystemBase(SubClass);
UE_CVLOG_UELOG(!Subsystem, MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree %s: Could not find required subsystem %s"), *GetNameSafe(StateTree), *GetNameSafe(ItemDesc.Struct));
bIssuesFound = bIssuesFound || !Subsystem;
}
}
else if (UE::Mass::IsA<FMassFragment>(ItemDesc.Struct))
{
const UScriptStruct& FragmentType = *CastChecked<UScriptStruct>(ItemDesc.Struct);
if (BuildContext.HasFragment(FragmentType) == false)
{
OutTraitRequirements.Add(&FragmentType);
UE_VLOG_UELOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree %s: Could not find required fragment %s"), *GetNameSafe(StateTree), *GetNameSafe(ItemDesc.Struct));
bIssuesFound = true;
}
}
else if (UE::Mass::IsA<FMassSharedFragment>(ItemDesc.Struct))
{
const UScriptStruct& FragmentType = *CastChecked<UScriptStruct>(ItemDesc.Struct);
if (BuildContext.HasSharedFragment(FragmentType) == false)
{
OutTraitRequirements.Add(&FragmentType);
UE_VLOG_UELOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree %s: Could not find required shared fragment %s"), *GetNameSafe(StateTree), *GetNameSafe(ItemDesc.Struct));
bIssuesFound = true;
}
}
else if (UE::Mass::IsA<FMassConstSharedFragment>(ItemDesc.Struct))
{
const UScriptStruct& FragmentType = *CastChecked<UScriptStruct>(ItemDesc.Struct);
if (BuildContext.HasConstSharedFragment(FragmentType) == false)
{
OutTraitRequirements.Add(&FragmentType);
UE_VLOG_UELOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree %s: Could not find required const shared fragment %s"), *GetNameSafe(StateTree), *GetNameSafe(ItemDesc.Struct));
bIssuesFound = true;
}
}
else
{
UE_VLOG_UELOG(MassStateTreeSubsystem, LogMassBehavior, Error, TEXT("StateTree %s: Unsupported requirement %s"), *GetNameSafe(StateTree), *GetNameSafe(ItemDesc.Struct));
bIssuesFound = true;
}
}
}
return !bIssuesFound;
}