void UEnvQueryGenerator_SimpleGrid::GenerateItems(FEnvQueryInstance& QueryInstance) const
{
	UObject* BindOwner = QueryInstance.Owner.Get();
	GridSize.BindData(BindOwner, QueryInstance.QueryID);
	SpaceBetween.BindData(BindOwner, QueryInstance.QueryID);

	float RadiusValue = GridSize.GetValue();
	float DensityValue = SpaceBetween.GetValue();

	const int32 ItemCount = FPlatformMath::TruncToInt((RadiusValue * 2.0f / DensityValue) + 1);
	const int32 ItemCountHalf = ItemCount / 2;

	TArray<FVector> ContextLocations;
	QueryInstance.PrepareContext(GenerateAround, ContextLocations);

	TArray<FNavLocation> GridPoints;
	GridPoints.Reserve(ItemCount * ItemCount * ContextLocations.Num());

	for (int32 ContextIndex = 0; ContextIndex < ContextLocations.Num(); ContextIndex++)
	{
		for (int32 IndexX = 0; IndexX <= ItemCount; ++IndexX)
		{
			for (int32 IndexY = 0; IndexY <= ItemCount; ++IndexY)
			{
				const FNavLocation TestPoint = FNavLocation(ContextLocations[ContextIndex] - FVector(DensityValue * (IndexX - ItemCountHalf), DensityValue * (IndexY - ItemCountHalf), 0));
				GridPoints.Add(TestPoint);
			}
		}
	}

	ProjectAndFilterNavPoints(GridPoints, QueryInstance);
	StoreNavPoints(GridPoints, QueryInstance);
}
// execution
EBTNodeResult::Type UAIE_GoToRandom_BTTaskNode::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) {
	/*	call super 
	 *	should aquire refrences for our BehaviorTreeComp, BlackboardComp, AIController, and BotCharacter
	 *	will return EBTNodeResult::Succeeded if we have all of them
	 *	will return EBTNodeResult::Failed if it failed to grab any of them
	*/
	EBTNodeResult::Type resultFromSuperExecution = Super::ExecuteTask(OwnerComp, NodeMemory);
	// check that we successfully grabbed the BehaviorTreeComp, BlackboardComp, AIController, and BotCharacter
	if (resultFromSuperExecution == EBTNodeResult::Succeeded) {
		// check that we can get the World
		if (GetWorld()) {
			// get the current nav system from the world
			UNavigationSystem* navSystem = UNavigationSystem::GetCurrent(GetWorld());
			// check that we have a nav system
			if (navSystem) {
				// get our actors current location to pe used as our start position
				FVector startPosi = BotCharacter->GetActorLocation();
				// create a nav location to be used as our end position 
				// default will be set to our current position in case of failure to find a suitable end position
				FNavLocation endPosi = FNavLocation(startPosi);
				// attempt to get a random new position
				if (navSystem->GetRandomReachablePointInRadius(startPosi, searchRadius, endPosi)) {
					// if we were successfull in finding a new location get the MoveToLocation BlackboardKeyID
					FBlackboard::FKey BlackboardKey_MoveToLocation = Blackboard->GetKeyID("MoveToLocation");
					// check that we got the key
					if ( Blackboard->IsValidKey( BlackboardKey_MoveToLocation)) {
						// set the MoveToLocation BlackboardKeyID to our new location
						Blackboard->SetValue<UBlackboardKeyType_Vector>(BlackboardKey_MoveToLocation, endPosi.Location);
						// return succeeded now that we have set up our new loacation
						return EBTNodeResult::Succeeded;
					}
					else {
						// return Aborted if we can't find the Key as it will never succeed without a proper Key
						if (bForceSuccess) {
							return EBTNodeResult::Succeeded;
						}
						return EBTNodeResult::Aborted;
					}
				}
				// return in progress if their are currently no valid locations
				if (bForceSuccess) {
					return EBTNodeResult::Succeeded;
				}
				return EBTNodeResult::InProgress;
			}
		}
		 
		
	}
	// we will only get here if execution fails so we will check if force success is on
	if (bForceSuccess) {
		// if force success is on we will return Succeeded anyway
		return EBTNodeResult::Succeeded;
	}
	// we want to return Failed after the force success check
	return EBTNodeResult::Failed;
}
FNavLocation UNavigationComponent::GetRandomPointOnNavMesh() const
{
#if WITH_RECAST
	ARecastNavMesh* const Nav = (ARecastNavMesh*)GetWorld()->GetNavigationSystem()->GetMainNavData(NavigationSystem::Create);
	if (Nav)
	{
		return Nav->GetRandomPoint();
	}
#endif // WITH_RECAST
	return FNavLocation();
}
FNavLocation UNavigationComponent::ProjectPointToNavigation(const FVector& Location) const
{
	FNavLocation OutLocation(Location);
	
	if (GetNavData() != NULL)
	{
		if (!MyNavData->ProjectPoint(Location, OutLocation, MyNavData->GetDefaultQueryExtent()))
		{
			OutLocation = FNavLocation();
		}
	}

	return OutLocation;
}
void UEnvQueryGenerator_OnCircle::GenerateItemsForCircle(uint8* ContextRawData, UEnvQueryItemType* ContextItemType,
	const FVector& CenterLocation, const FVector& StartDirection, 
	int32 StepsCount, float AngleStep, FEnvQueryInstance& OutQueryInstance) const
{
	TArray<FNavLocation> ItemCandidates;
	ItemCandidates.AddZeroed(StepsCount);

	for (int32 Step = 0; Step < StepsCount; ++Step)
	{
		ItemCandidates[Step] = FNavLocation(CenterLocation + StartDirection.RotateAngleAxis(AngleStep*Step, FVector::UpVector));
	}

	switch (TraceData.TraceMode)
	{
		case EEnvQueryTrace::Navigation:
		{
			ANavigationData* NavData = const_cast<ANavigationData*>(FEQSHelpers::FindNavigationDataForQuery(OutQueryInstance));
			if (NavData)
			{
				FEQSHelpers::RunNavRaycasts(*NavData, TraceData, CenterLocation, ItemCandidates);
			}
		}
			break;

		case EEnvQueryTrace::Geometry:
			FEQSHelpers::RunPhysRaycasts(OutQueryInstance.World, TraceData, CenterLocation, ItemCandidates);
			break;

		case EEnvQueryTrace::None:
			// Just accept the ItemCandidates as they already are (points on a circle), without using navigation OR collision.
			break;

		default:
			UE_VLOG(Cast<AActor>(OutQueryInstance.Owner.Get()), LogEQS, Warning, TEXT("UEnvQueryGenerator_OnCircle::CalcDirection has invalid value for TraceData.TraceMode.  Query: %s"), *OutQueryInstance.QueryName);
			break;
	}

	ProjectAndFilterNavPoints(ItemCandidates, OutQueryInstance);
	AddItemDataForCircle(ContextRawData, ContextItemType, ItemCandidates, OutQueryInstance);
}
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 UEnvQueryGenerator_Donut::GenerateItems(FEnvQueryInstance& QueryInstance) const
{
	TArray<FVector> CenterPoints;
	QueryInstance.PrepareContext(Center, CenterPoints);

	if (CenterPoints.Num() <= 0)
	{
		return;
	}

	UObject* BindOwner = QueryInstance.Owner.Get();
	InnerRadius.BindData(BindOwner, QueryInstance.QueryID);
	OuterRadius.BindData(BindOwner, QueryInstance.QueryID);
	NumberOfRings.BindData(BindOwner, QueryInstance.QueryID);
	PointsPerRing.BindData(BindOwner, QueryInstance.QueryID);
	ArcAngle.BindData(BindOwner, QueryInstance.QueryID);

	float ArcAngleValue = ArcAngle.GetValue();
	float InnerRadiusValue = InnerRadius.GetValue();
	float OuterRadiusValue = OuterRadius.GetValue();
	int32 NumRings = NumberOfRings.GetValue();
	int32 NumPoints = PointsPerRing.GetValue();

	if ((InnerRadiusValue <= 0.f) || (OuterRadiusValue <= 0.f) ||
		(InnerRadiusValue > OuterRadiusValue) ||
		(NumRings < 1) || (NumPoints < 1))
	{
		return;
	}

	const float ArcBisectDeg = GetArcBisectorAngle(QueryInstance);
	const float ArcAngleDeg = FMath::Clamp(ArcAngleValue, 0.0f, 360.0f);

	const float RadiusDelta = (OuterRadiusValue - InnerRadiusValue) / (NumRings - 1);
	const float AngleDelta = 2.0 * PI / NumPoints;
	float SectionAngle = FMath::DegreesToRadians(ArcBisectDeg);

	TArray<FNavLocation> Points;
	Points.Reserve(NumPoints * NumRings);

	for (int32 SectionIdx = 0; SectionIdx < NumPoints; SectionIdx++, SectionAngle += AngleDelta)
	{
		if (IsAngleAllowed(SectionAngle, ArcBisectDeg, ArcAngleDeg, bDefineArc))
		{
			const float SinValue = FMath::Sin(SectionAngle);
			const float CosValue = FMath::Cos(SectionAngle);

			float RingRadius = InnerRadiusValue;
			for (int32 RingIdx = 0; RingIdx < NumRings; RingIdx++, RingRadius += RadiusDelta)
			{
				const FVector RingPos(RingRadius * CosValue, RingRadius * SinValue, 0.0f);
				for (int32 ContextIdx = 0; ContextIdx < CenterPoints.Num(); ContextIdx++)
				{
					const FNavLocation PointPos = FNavLocation(CenterPoints[ContextIdx] + RingPos);
					Points.Add(PointPos);
				}
			}
		}
	}

	ProjectAndFilterNavPoints(Points, QueryInstance);
	StoreNavPoints(Points, QueryInstance);
}