void UEnvQueryGenerator_ProjectedPoints::ProjectAndFilterNavPoints(TArray<FVector>& Points, const ANavigationData* NavData) const { if (ProjectionData.TraceMode == EEnvQueryTrace::Navigation && NavData) { TSharedPtr<const FNavigationQueryFilter> NavigationFilter = UNavigationQueryFilter::GetQueryFilter(NavData, ProjectionData.NavigationFilter); const ARecastNavMesh* NavMesh = Cast<const ARecastNavMesh>(NavData); TArray<FNavigationProjectionWork> Workload; Workload.Reserve(Points.Num()); if (ProjectionData.ProjectDown == ProjectionData.ProjectUp) { for (const auto& Point : Points) { Workload.Add(FNavigationProjectionWork(Point)); } } else { const FVector VerticalOffset = FVector(0, 0, (ProjectionData.ProjectUp - ProjectionData.ProjectDown) / 2); for (const auto& Point : Points) { Workload.Add(FNavigationProjectionWork(Point + VerticalOffset)); } } const FVector ProjectionExtent(ProjectionData.ExtentX, ProjectionData.ExtentX, (ProjectionData.ProjectDown + ProjectionData.ProjectUp) / 2); NavData->BatchProjectPoints(Workload, ProjectionExtent, NavigationFilter); for (int32 PointIndex = Workload.Num() - 1; PointIndex >= 0; PointIndex--) { if (Workload[PointIndex].bResult == false) { Points.RemoveAt(PointIndex); } else { Points[PointIndex] = Workload[PointIndex].OutLocation.Location; } } } }
void UEnvQueryTest_Project::RunTest(FEnvQueryInstance& QueryInstance) const { BoolValue.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID); bool bWantsProjected = BoolValue.GetValue(); UEnvQueryItemType_Point* ItemTypeCDO = QueryInstance.ItemType->GetDefaultObject<UEnvQueryItemType_Point>(); if (ItemTypeCDO == nullptr) { return; } if (ProjectionData.TraceMode == EEnvQueryTrace::Navigation) { const ANavigationData* NavData = FEQSHelpers::FindNavigationDataForQuery(QueryInstance); if (NavData) { TSharedPtr<const FNavigationQueryFilter> NavigationFilter = UNavigationQueryFilter::GetQueryFilter(*NavData, ProjectionData.NavigationFilter); TArray<FNavigationProjectionWork> Workload; Workload.Reserve(QueryInstance.Items.Num()); const FVector VerticalOffset = (ProjectionData.ProjectDown == ProjectionData.ProjectUp) ? FVector::ZeroVector : FVector(0, 0, (ProjectionData.ProjectUp - ProjectionData.ProjectDown) / 2); for (int32 Idx = 0; Idx < QueryInstance.Items.Num(); Idx++) { if (QueryInstance.Items[Idx].IsValid()) { const FVector& ItemLocation = GetItemLocation(QueryInstance, Idx); Workload.Add(FNavigationProjectionWork(ItemLocation + VerticalOffset)); } } const FVector ProjectionExtent(ProjectionData.ExtentX, ProjectionData.ExtentX, (ProjectionData.ProjectDown + ProjectionData.ProjectUp) / 2); NavData->BatchProjectPoints(Workload, ProjectionExtent, NavigationFilter); int32 Idx = 0; for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It, Idx++) { const bool bProjected = Workload[Idx].bResult; if (bProjected) { ItemTypeCDO->SetItemNavLocation(It.GetItemData(), Workload[Idx].OutLocation); } It.SetScore(TestPurpose, FilterType, bProjected, bWantsProjected); } } } else if (ProjectionData.TraceMode == EEnvQueryTrace::Geometry) { TArray<FNavLocation> Workload; TArray<uint8> TraceHits; Workload.Reserve(QueryInstance.Items.Num()); for (int32 Idx = 0; Idx < QueryInstance.Items.Num(); Idx++) { if (QueryInstance.Items[Idx].IsValid()) { const FVector& ItemLocation = GetItemLocation(QueryInstance, Idx); Workload.Add(FNavLocation(ItemLocation)); } } FEQSHelpers::RunPhysProjection(QueryInstance.World, ProjectionData, Workload, TraceHits); int32 Idx = 0; for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It, Idx++) { const bool bProjected = TraceHits.IsValidIndex(Idx) && TraceHits[Idx]; if (bProjected) { ItemTypeCDO->SetItemNavLocation(It.GetItemData(), Workload[Idx]); } It.SetScore(TestPurpose, FilterType, bProjected, bWantsProjected); } } }
void UEnvQueryTest_PathfindingBatch::RunTest(FEnvQueryInstance& QueryInstance) const { UObject* QueryOwner = QueryInstance.Owner.Get(); BoolValue.BindData(QueryOwner, QueryInstance.QueryID); PathFromContext.BindData(QueryOwner, QueryInstance.QueryID); SkipUnreachable.BindData(QueryOwner, QueryInstance.QueryID); FloatValueMin.BindData(QueryOwner, QueryInstance.QueryID); FloatValueMax.BindData(QueryOwner, QueryInstance.QueryID); ScanRangeMultiplier.BindData(QueryOwner, QueryInstance.QueryID); bool bWantsPath = BoolValue.GetValue(); bool bPathToItem = PathFromContext.GetValue(); bool bDiscardFailed = SkipUnreachable.GetValue(); float MinThresholdValue = FloatValueMin.GetValue(); float MaxThresholdValue = FloatValueMax.GetValue(); float RangeMultiplierValue = ScanRangeMultiplier.GetValue(); UNavigationSystem* NavSys = QueryInstance.World->GetNavigationSystem(); if (NavSys == nullptr) { return; } ANavigationData* NavData = FindNavigationData(*NavSys, QueryOwner); ARecastNavMesh* NavMeshData = Cast<ARecastNavMesh>(NavData); if (NavMeshData == nullptr) { return; } TArray<FVector> ContextLocations; if (!QueryInstance.PrepareContext(Context, ContextLocations)) { return; } TArray<FNavigationProjectionWork> TestPoints; TArray<float> CollectDistanceSq; CollectDistanceSq.Init(0.0f, ContextLocations.Num()); FSharedNavQueryFilter NavigationFilter = FilterClass != nullptr ? UNavigationQueryFilter::GetQueryFilter(*NavMeshData, FilterClass)->GetCopy() : NavMeshData->GetDefaultQueryFilter()->GetCopy(); NavigationFilter->SetBacktrackingEnabled(!bPathToItem); const dtQueryFilter* NavQueryFilter = ((const FRecastQueryFilter*)NavigationFilter->GetImplementation())->GetAsDetourQueryFilter(); { // scope for perf timers // can't use FEnvQueryInstance::ItemIterator yet, since it has built in scoring functionality for (int32 ItemIdx = 0; ItemIdx < QueryInstance.Items.Num(); ItemIdx++) { if (QueryInstance.Items[ItemIdx].IsValid()) { const FVector ItemLocation = GetItemLocation(QueryInstance, ItemIdx); TestPoints.Add(FNavigationProjectionWork(ItemLocation)); for (int32 ContextIdx = 0; ContextIdx < ContextLocations.Num(); ContextIdx++) { const float TestDistanceSq = FVector::DistSquared(ItemLocation, ContextLocations[ContextIdx]); CollectDistanceSq[ContextIdx] = FMath::Max(CollectDistanceSq[ContextIdx], TestDistanceSq); } } } NavMeshData->BatchProjectPoints(TestPoints, NavMeshData->GetDefaultQueryExtent(), NavigationFilter); } TArray<FRecastDebugPathfindingData> NodePoolData; NodePoolData.SetNum(ContextLocations.Num()); { // scope for perf timer TArray<NavNodeRef> Polys; for (int32 ContextIdx = 0; ContextIdx < ContextLocations.Num(); ContextIdx++) { const float MaxPathDistance = FMath::Sqrt(CollectDistanceSq[ContextIdx]) * RangeMultiplierValue; Polys.Reset(); NodePoolData[ContextIdx].Flags = ERecastDebugPathfindingFlags::PathLength; NavMeshData->GetPolysWithinPathingDistance(ContextLocations[ContextIdx], MaxPathDistance, Polys, NavigationFilter, nullptr, &NodePoolData[ContextIdx]); } } int32 ProjectedItemIdx = 0; if (GetWorkOnFloatValues()) { NodePoolHelpers::PathParamFunc Func[] = { nullptr, NodePoolHelpers::GetPathCost, NodePoolHelpers::GetPathLength }; FEnvQueryInstance::ItemIterator It(this, QueryInstance); for (It.IgnoreTimeLimit(); It; ++It, ProjectedItemIdx++) { for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++) { const float PathValue = Func[TestMode](NodePoolData[ContextIndex], TestPoints[ProjectedItemIdx], NavQueryFilter); It.SetScore(TestPurpose, FilterType, PathValue, MinThresholdValue, MaxThresholdValue); if (bDiscardFailed && PathValue >= BIG_NUMBER) { It.ForceItemState(EEnvItemStatus::Failed); } } } } else { FEnvQueryInstance::ItemIterator It(this, QueryInstance); for (It.IgnoreTimeLimit(); It; ++It, ProjectedItemIdx++) { for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++) { const bool bFoundPath = NodePoolHelpers::HasPath(NodePoolData[ContextIndex], TestPoints[ProjectedItemIdx]); It.SetScore(TestPurpose, FilterType, bFoundPath, bWantsPath); } } } }