Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

136 lines
3.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "EnvironmentQuery/Tests/EnvQueryTest_Volume.h"
#include "EngineUtils.h"
#include "EnvironmentQuery/Items/EnvQueryItemType_VectorBase.h"
#include "GameFramework/Volume.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(EnvQueryTest_Volume)
#define LOCTEXT_NAMESPACE "EnvQueryGenerator"
UEnvQueryTest_Volume::UEnvQueryTest_Volume(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
Cost = EEnvTestCost::Medium;
ValidItemType = UEnvQueryItemType_VectorBase::StaticClass();
SetWorkOnFloatValues(false);
bDoComplexVolumeTest = false;
bSkipTestIfNoVolumes = false;
}
#if WITH_EDITOR
void UEnvQueryTest_Volume::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
Cost = VolumeContext.Get() ? EEnvTestCost::Medium : EEnvTestCost::High;
}
#endif
void UEnvQueryTest_Volume::RunTest(FEnvQueryInstance& QueryInstance) const
{
const UObject* DataOwner = QueryInstance.Owner.Get();
BoolValue.BindData(DataOwner, QueryInstance.QueryID);
struct FVolumeBoundsCache
{
public:
FVolumeBoundsCache(AVolume& InVolume) : Volume(InVolume)
{
BoundingBox = Volume.GetBounds().GetBox();
}
bool IsPointInsideBoundingBox(const FVector TestPoint) const
{
return BoundingBox.IsInside(TestPoint);
}
bool EncompassesPoint(const FVector TestPoint) const
{
return Volume.EncompassesPoint(TestPoint);
}
private:
AVolume& Volume;
FBox BoundingBox;
};
TArray<AActor*> ContextVolumeActors;
TArray<FVolumeBoundsCache> ContextVolumes;
if (VolumeContext)
{
QueryInstance.PrepareContext(VolumeContext, ContextVolumeActors);
ContextVolumes.Reserve(ContextVolumeActors.Num());
for (AActor* VolumeActor : ContextVolumeActors)
{
AVolume* Volume = Cast<AVolume>(VolumeActor);
if (Volume)
{
ContextVolumes.Add(FVolumeBoundsCache(*Volume));
}
}
}
else if (VolumeClass)
{
for (TActorIterator<AVolume> It(QueryInstance.World, VolumeClass); It; ++It)
{
AVolume* Volume = *It;
if (Volume)
{
ContextVolumes.Add(FVolumeBoundsCache(*Volume));
}
}
}
const bool bWantsInside = BoolValue.GetValue();
// Initially Items are marked as "passed", so in principle we only need to run the code below if there are volumes
// to test and we're not allowed to skip this test.
// We can however also skip if there are no volumes, but bWantsInside == false since the code below would only result
// in assigning "passed" to all Items, which is the default state, as described.
if (ContextVolumes.Num() > 0 || (bSkipTestIfNoVolumes == false && bWantsInside == true))
{
for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
{
const FVector ItemLocation = GetItemLocation(QueryInstance, It.GetIndex());
bool bPointIsInsideAVolume = false;
for (const FVolumeBoundsCache& VolumeAndBounds : ContextVolumes)
{
if (VolumeAndBounds.IsPointInsideBoundingBox(ItemLocation))
{
if (!bDoComplexVolumeTest || VolumeAndBounds.EncompassesPoint(ItemLocation))
{
bPointIsInsideAVolume = true;
break;
}
}
}
It.SetScore(TestPurpose, FilterType, bPointIsInsideAVolume, bWantsInside);
}
}
}
FText UEnvQueryTest_Volume::GetDescriptionTitle() const
{
FString VolumeDesc(TEXT("No Source Volume Context/Class set"));
if (VolumeContext)
{
VolumeDesc = UEnvQueryTypes::DescribeContext(VolumeContext).ToString();
}
else if (VolumeClass)
{
VolumeDesc = VolumeClass->GetDescription();
}
return FText::FromString(FString::Printf(TEXT("%s : %s (%s)"),
*Super::GetDescriptionTitle().ToString(), *VolumeDesc, bDoComplexVolumeTest ? TEXT("Complex Physic Volume Test") : TEXT("Simple Bounding Box Test")));
}
FText UEnvQueryTest_Volume::GetDescriptionDetails() const
{
return GetDescriptionTitle();
}
#undef LOCTEXT_NAMESPACE