AEyeXActorBase* AEyeXPlayerController::FindByBoxedLineTrace(FHitResult& OutHit, const FSceneView* const View, const FVector2D& GazePoint,
	const FCollisionQueryParams& TraceParams, const FCollisionObjectQueryParams& ObjectParams)
{
	UWorld* World = GetWorld();
	if (!World) return nullptr;

	// Set up a box around the gaze point
	FVector2D Corners[4];
	GetBoxCorners(GazePoint, BoxSize * GetApproximatePixelsPerMillimeter(), Corners);

	// First check center point
	AEyeXActorBase* EyeXActor = nullptr;
	FVector Start, End;
	FEyeXUtils::GetStartAndEndOfLineTrace(View, MaxDistance, GazePoint, /*out*/ Start, /*out*/ End);
	if (World->LineTraceSingle(OutHit, Start, End, TraceParams, ObjectParams))
	{
		EyeXActor = Cast<AEyeXActorBase>(OutHit.GetActor());
	}
	else
	{
		// If center point missed we perform traces in a box around the gaze point
		// and choose the closest EyeXActor hit by the traces
		TArray<AEyeXActorBase*> EyeXActors;
		for (int i = 0; i < 4; ++i)
		{
			FVector BoxStart, BoxEnd;
			FEyeXUtils::GetStartAndEndOfLineTrace(View, MaxDistance, Corners[i], /*out*/ BoxStart, /*out*/ BoxEnd);
			if (World->LineTraceSingle(OutHit, BoxStart, BoxEnd, TraceParams, ObjectParams))
			{
				AEyeXActorBase* Actor = Cast<AEyeXActorBase>(OutHit.GetActor());
				if (!Actor) continue;
				EyeXActors.Add(Actor);
			}

			VisualizeHitTestPoint(bVisualizeDetection, World, BoxStart);
		}

		if (EyeXActors.Num() > 0)
		{
			FEyeXUtils::ActorDistanceComparer Comparer(PlayerCameraManager);
			EyeXActors.Sort(Comparer);
			EyeXActor = EyeXActors[0];
		}
	}

	VisualizeHit(bVisualizeDetection, World, OutHit);
	VisualizeGazePoint(bVisualizeDetection, World, Start);

	return EyeXActor;
}
int32 UTB_AimComponent::CoverModifier(ATB_Character *Target)
{
	UWorld *World = GetWorld();

	// Ignore collisions with the aiming character and its weapon
	FCollisionQueryParams Params;
	Params.bTraceComplex = true;
	Params.AddIgnoredActor(Character);
	if (Weapon)
	{
		Params.AddIgnoredActor(Weapon);
	}
	if (Target->Weapon)
	{
		Params.AddIgnoredActor(Target->Weapon);
	}

	// uncomment to draw debug lines
	/*
	FName TraceTag("CoverTrace");
	World->DebugDrawTraceTag = TraceTag;
	Params.TraceTag = TraceTag;
	*/
	FCollisionObjectQueryParams ObjectParams;

	FHitResult HitResult;
	TArray<FVector> HitLocations;
	Target->GetHitLocations(HitLocations);
	FVector StartLocation = GetComponentLocation();

	int Hidden = 0;
	for (auto HitLocation : HitLocations)
	{
		bool HitSomething = World->LineTraceSingle(HitResult, StartLocation, HitLocation, Params, ObjectParams);
		if (HitSomething && Target->GetUniqueID() != HitResult.Actor->GetUniqueID())
		{
			Hidden++;
		}
	}

	if (Hidden < HitLocations.Num())
	{
		// reduce cover by half if we can see the enemy at all
		// a penalty above 60 makes an enemy virtually impossible to hit
		Hidden -= (Hidden / 3);
	}
	return (Hidden * -100) / std::max(HitLocations.Num(), 1);
}
FVector ASpawningVolume::returnRandomLocation()
{
	FVector PossibleSpawnPoint;
	UWorld* World = GetWorld();
	FHitResult HitResult;
	FCollisionQueryParams Params;
	Params.bFindInitialOverlaps = true;
	if (World){
		do{
			PossibleSpawnPoint = GetRandomPointInVolume();
			if (!World->LineTraceSingle(HitResult, PossibleSpawnPoint, FVector(PossibleSpawnPoint.X, PossibleSpawnPoint.Y, -100), Params, FCollisionObjectQueryParams())){
				break;
			}
			AActor* Actor = HitResult.Actor.Get();
			FString name = Actor->GetActorLabel();
		} while (!HitResult.Actor.Get()->GetActorLabel().StartsWith("Floor"));
	}
	return PossibleSpawnPoint;
}
AEyeXActorBase* AEyeXPlayerController::FindByFrustumIntersection(FHitResult& OutHit, const FSceneView* const View, const FVector2D& GazePoint,
	const FCollisionQueryParams& TraceParams, const FCollisionObjectQueryParams& ObjectParams)
{
	UWorld* World = GetWorld();
	if (!World) return nullptr;

	FVector2D Corners[4];
	GetBoxCorners(GazePoint, BoxSize * GetApproximatePixelsPerMillimeter(), Corners);

	// First do a ray cast from the gaze point to determine if something is blocking.
	// If we happen to find an AEyeXActorBase, we're done
	FVector Start, End;
	FEyeXUtils::GetStartAndEndOfLineTrace(View, MaxDistance, GazePoint, /*out*/ Start, /*out*/ End);

	AEyeXActorBase* EyeXActor = nullptr;
	if (World->LineTraceSingle(OutHit, Start, End, TraceParams, ObjectParams))
	{
		EyeXActor = Cast<AEyeXActorBase>(OutHit.GetActor());
	}
	else
	{
		// Calculate frustum using the SceneView
		FConvexVolume Frustum;
		FEyeXMathHelpers::CalculateFrustum(Corners, View, Frustum);

		// Check frustum intersection with EyeX Actors
		TArray<AEyeXActorBase*> EyeXActors;
		GetEyeXActorsSortedByDistance(EyeXActors);
		for (AEyeXActorBase* Actor : EyeXActors)
		{
			if (FEyeXMathHelpers::IntersectsFrustum(OutHit, Actor, Frustum))
			{
				EyeXActor = Actor;
				break;
			}
		}
	}

	VisualizeHit(bVisualizeDetection, World, OutHit);
	VisualizeGazePoint(bVisualizeDetection, World, Start);

	return EyeXActor;
}
AEyeXActorBase* AEyeXPlayerController::FindByLineTrace(FHitResult& OutHit, const FSceneView* const View, const FVector2D& GazePoint,
	const FCollisionQueryParams& TraceParams, const FCollisionObjectQueryParams& ObjectParams)
{
	UWorld* World = GetWorld();
	if (!World) return nullptr;

	AEyeXActorBase* EyeXActor = nullptr;
	FVector Start, End;
	FEyeXUtils::GetStartAndEndOfLineTrace(View, MaxDistance, GazePoint, /*out*/ Start, /*out*/ End);
	if (World->LineTraceSingle(OutHit, Start, End, TraceParams, ObjectParams))
	{
		EyeXActor = Cast<AEyeXActorBase>(OutHit.GetActor());
	}

	VisualizeHit(bVisualizeDetection, World, OutHit);
	VisualizeGazePoint(bVisualizeDetection, World, Start);

	return EyeXActor;
}
bool ATotemCharacter::RayCastOnGround()
{
	UWorld *world = GetWorld();
	

	FVector StartTrace = GetActorLocation();
	FVector EndTrace = StartTrace - FVector(0, 0, 150); 

	if (world)
	{
		FHitResult Hit(ForceInit);
		FCollisionQueryParams collisionParams(FName(TEXT("EARTH_SHAMAN_TRACE")), true, this);
		world->LineTraceSingle(Hit, StartTrace, EndTrace, ECC_WorldStatic, collisionParams);

		if (Hit.bBlockingHit && Hit.GetActor())
		{
			//DrawDebugLine(world, StartTrace, Hit.ImpactPoint, FColor::Green, false, 5.0f);
			return true; 
		}
	}
	//DrawDebugLine(world, StartTrace, EndTrace, FColor::Red, false, 5.0f);

	return false;
}
	FORCEINLINE_DEBUGGABLE FVector RunLineTrace(const FVector& StartPos, const FVector& EndPos)
	{
		FHitResult OutHit;
		const bool bHit = World->LineTraceSingle(OutHit, StartPos, EndPos, Channel, Params);
		return bHit ? OutHit.ImpactPoint : EndPos;
	}