Files
UnrealEngine/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/Contexts/EnvQueryContext_BlueprintBase.cpp
2025-05-18 13:04:45 +08:00

144 lines
4.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "EnvironmentQuery/Contexts/EnvQueryContext_BlueprintBase.h"
#include "GameFramework/Actor.h"
#include "AITypes.h"
#include "EnvironmentQuery/Items/EnvQueryItemType_Actor.h"
#include "EnvironmentQuery/Items/EnvQueryItemType_Point.h"
#include "EnvironmentQuery/EnvQueryManager.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(EnvQueryContext_BlueprintBase)
namespace
{
FORCEINLINE bool DoesImplementBPFunction(FName FuncName, const UObject* Ob, const UClass* StopAtClass)
{
return (Ob->GetClass()->FindFunctionByName(FuncName)->GetOuter() != StopAtClass);
}
}
UEnvQueryContext_BlueprintBase::UEnvQueryContext_BlueprintBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer), CallMode(UEnvQueryContext_BlueprintBase::InvalidCallMode)
{
UClass* StopAtClass = UEnvQueryContext_BlueprintBase::StaticClass();
bool bImplementsProvideSingleActor = DoesImplementBPFunction(GET_FUNCTION_NAME_CHECKED(UEnvQueryContext_BlueprintBase, ProvideSingleActor), this, StopAtClass);
bool bImplementsProvideSingleLocation = DoesImplementBPFunction(GET_FUNCTION_NAME_CHECKED(UEnvQueryContext_BlueprintBase, ProvideSingleLocation), this, StopAtClass);
bool bImplementsProvideActorSet = DoesImplementBPFunction(GET_FUNCTION_NAME_CHECKED(UEnvQueryContext_BlueprintBase, ProvideActorsSet), this, StopAtClass);
bool bImplementsProvideLocationsSet = DoesImplementBPFunction(GET_FUNCTION_NAME_CHECKED(UEnvQueryContext_BlueprintBase, ProvideLocationsSet), this, StopAtClass);
int32 ImplementationsCount = 0;
if (bImplementsProvideSingleActor)
{
++ImplementationsCount;
CallMode = SingleActor;
}
if (bImplementsProvideSingleLocation)
{
++ImplementationsCount;
CallMode = SingleLocation;
}
if (bImplementsProvideActorSet)
{
++ImplementationsCount;
CallMode = ActorSet;
}
if (bImplementsProvideLocationsSet)
{
++ImplementationsCount;
CallMode = LocationSet;
}
if (ImplementationsCount != 1)
{
}
}
void UEnvQueryContext_BlueprintBase::ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const
{
UObject* QuerierObject = QueryInstance.Owner.Get();
if ((QuerierObject == nullptr) || (CallMode == InvalidCallMode))
{
return;
}
// NOTE: QuerierActor is redundant with QuerierObject and should be removed in the future. It's here for now for
// backwards compatibility.
AActor* QuerierActor = Cast<AActor>(QuerierObject);
switch (CallMode)
{
case SingleActor:
{
AActor* ResultingActor = NULL;
ProvideSingleActor(QuerierObject, QuerierActor, ResultingActor);
// store the result only if it's a valid actor, otherwise the FEnvQueryContextData will think it succeeded
// and proceed with the query
if (ResultingActor)
{
UEnvQueryItemType_Actor::SetContextHelper(ContextData, ResultingActor);
}
}
break;
case SingleLocation:
{
FVector ResultingLocation = FAISystem::InvalidLocation;
ProvideSingleLocation(QuerierObject, QuerierActor, ResultingLocation);
// filter out invalid locations as they don't represent valid context
if (FAISystem::IsValidLocation(ResultingLocation))
{
UEnvQueryItemType_Point::SetContextHelper(ContextData, ResultingLocation);
}
}
break;
case ActorSet:
{
TArray<AActor*> ActorSet;
ProvideActorsSet(QuerierObject, QuerierActor, ActorSet);
// remove nulls as they don't represent valid information, i.e. null actors are invalid rather than an "is missing" information
ActorSet.Remove(nullptr);
if (ActorSet.Num())
{
UEnvQueryItemType_Actor::SetContextHelper(ContextData, ActorSet);
}
}
break;
case LocationSet:
{
TArray<FVector> LocationSet;
ProvideLocationsSet(QuerierObject, QuerierActor, LocationSet);
// filter out invalid locations as they don't represent valid context
LocationSet.RemoveAll([](const FVector& Element) { return !FAISystem::IsValidLocation(Element); });
if (LocationSet.Num())
{
UEnvQueryItemType_Point::SetContextHelper(ContextData, LocationSet);
}
}
break;
default:
break;
}
}
UWorld* UEnvQueryContext_BlueprintBase::GetWorld() const
{
check(GetOuter() != NULL);
UEnvQueryManager* EnvQueryManager = Cast<UEnvQueryManager>(GetOuter());
if (EnvQueryManager != NULL)
{
return EnvQueryManager->GetWorld();
}
// Outer should always be UEnvQueryManager* in the game, which implements GetWorld() and therefore makes this
// a correct world context. However, in the editor the outer is /Script/AIModule (at compile time), which
// does not explicitly implement GetWorld(). For that reason, calling GetWorld() generically in that case on the
// AIModule calls to the base implementation, which causes a blueprint compile warning in the Editor
// which states that the function isn't safe to call on this (due to requiring WorldContext which it doesn't
// provide). Simply returning NULL in this case fixes those erroneous blueprint compile warnings.
return NULL;
}