Moving on from the above post;
I overrode AIController::MoveTo as well as AIController::FindPathForMoveRequest (so I could utilize FindPathForMoveRequest mainly, I don’t change anything in MoveTo)
With FindPathForMoveRequest, I find a path like regular. Using the path points, I figure out the length of the path, then I find the middlepoint along the path. I ignore every path point before the middlepoint then I move the location of the first path point after the middlepoint to the middlepoint. I then remove the last two path points of the path.
The idea is that I will find a middle point of the path and move the target AI and targeting AI to that middle point, thereby not needing MoveToActor, as well as utilizing the pathmodifier system I created above to respect other AI paths.
The problem:
Even with the updated path and goal location, the AI who found the path still moves towards the original location and not the middlepoint. I checked PathResult.Path->GetGoalLocation() and it is the updated location. Still digging into it, but any devs with intimate knowledge of the nav system that can help?
Here are my overloaded functions. You can see that after finding the path, MoveTo calls RequestMove(MoveRequest, Path) (which I know is successful as I checked the validity)
AAIController_Base::MoveToTarget
[SPOILER]
FPathFollowingRequestResult AAIController_Base::MoveToTarget(const FAIMoveRequest & MoveRequest, FNavPathSharedPtr * OutPath)
{
// Only overriden to provide pathing logic specific to custom moving to target
// is not the override of MoveTo, therefore not the entry point of all moves
// rather than build a path directly to target, the series of functions used here get a path from caller to target, then find the middle point, which they will path to
SCOPE_CYCLE_COUNTER(STAT_MoveToTarget);
// UE_VLOG(this, LogAIControllerBase, Log, TEXT("MoveTo: %s"), *MoveRequest.ToString());
FPathFollowingRequestResult ResultData;
ResultData.Code = EPathFollowingRequestResult::Failed;
if (MoveRequest.IsValid() == false)
{
// UE_VLOG(this, LogAINavigation, Error, TEXT("MoveTo request failed due MoveRequest not being valid. Most probably desireg Goal Actor not longer exists"), *MoveRequest.ToString());
return ResultData;
}
if (GetPathFollowingComponent() == nullptr)
{
// UE_VLOG(this, LogAINavigation, Error, TEXT("MoveTo request failed due missing PathFollowingComponent"));
return ResultData;
}
ensure(MoveRequest.GetNavigationFilter() || !DefaultNavigationFilterClass);
bool bCanRequestMove = true;
bool bAlreadyAtGoal = false;
//this will never be a move to actor request
if (MoveRequest.GetGoalLocation().ContainsNaN() || FAISystem::IsValidLocation(MoveRequest.GetGoalLocation()) == false)
{
// UE_VLOG(this, LogAINavigation, Error, TEXT("AAIController::MoveTo: Destination is not valid! Goal(%s)"), TEXT_AI_LOCATION(MoveRequest.GetGoalLocation()));
bCanRequestMove = false;
}
// fail if projection to navigation is required but it failed
if (bCanRequestMove && MoveRequest.IsProjectingGoal())
{
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
const FNavAgentProperties& AgentProps = GetNavAgentPropertiesRef();
FNavLocation ProjectedLocation;
if (NavSys && !NavSys->ProjectPointToNavigation(MoveRequest.GetGoalLocation(), ProjectedLocation, INVALID_NAVEXTENT, &AgentProps))
{
// UE_VLOG_LOCATION(this, LogAINavigation, Error, MoveRequest.GetGoalLocation(), 30.f, FColor::Red, TEXT("AAIController::MoveTo failed to project destination location to navmesh"));
bCanRequestMove = false;
}
MoveRequest.UpdateGoalLocation(ProjectedLocation.Location);
}
bAlreadyAtGoal = bCanRequestMove && GetPathFollowingComponent()->HasReached(MoveRequest);
if (bAlreadyAtGoal)
{
// UE_VLOG(this, LogAINavigation, Log, TEXT("MoveTo: already at goal!"));
ResultData.MoveId = GetPathFollowingComponent()->RequestMoveWithImmediateFinish(EPathFollowingResult::Success);
ResultData.Code = EPathFollowingRequestResult::AlreadyAtGoal;
}
else if (bCanRequestMove)
{
FPathFindingQuery PFQuery;
const bool bValidQuery = BuildPathfindingQuery(MoveRequest, PFQuery);
if (bValidQuery)
{
FNavPathSharedPtr Path;
FindPathForMoveRequestToTarget(MoveRequest, PFQuery, Path);
const FAIRequestID RequestID = Path.IsValid() ? RequestMove(MoveRequest, Path) : FAIRequestID::InvalidRequest;
UE_LOG(LogTemp, Log, TEXT("Path length is %d. AIController_Base::MoveToTarget()"), Path->GetPathPoints().Num());
if (RequestID.IsValid())
{
bAllowStrafe = MoveRequest.CanStrafe();
ResultData.MoveId = RequestID;
ResultData.Code = EPathFollowingRequestResult::RequestSuccessful;
if (OutPath)
{
*OutPath = Path;
}
}
}
}
if (ResultData.Code == EPathFollowingRequestResult::Failed)
{
ResultData.MoveId = GetPathFollowingComponent()->RequestMoveWithImmediateFinish(EPathFollowingResult::Invalid);
}
return ResultData;
}
[/SPOILER]
AAIController_Base::FindPathForMoveRequestToTarget
[SPOILER]
void AAIController_Base::FindPathForMoveRequestToTarget(const FAIMoveRequest & MoveRequest, FPathFindingQuery & Query, FNavPathSharedPtr & OutPath) const
{
SCOPE_CYCLE_COUNTER(STAT_MoveToTarget);
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
if (NavSys)
{
FPathFindingResult PathResult = NavSys->FindPathSync(Query);
if (PathResult.Result != ENavigationQueryResult::Error)
{
if (PathResult.IsSuccessful() && PathResult.Path.IsValid())
{
PathResult.Path->EnableRecalculationOnInvalidation(true);
/*
Get total length of path
get half length
pathLength
add distance from first navpoint to second navpoint
if less than half length
add to pathLength
continue
else
distanceLeft = halfLength - pathLength
add distanceLeft to previous navpoint location
set location of next navpoint at that location
destroy all other points
*/
float pathLength = 0.0f;
//Get the total length of the resulting path
for (int i = 0; i < PathResult.Path->GetPathPoints().Num(); i++)
{
FVector location = PathResult.Path->GetPathPoints()*.Location;
FVector nextLocation;
//Get distance to next location in array so long as it is within array
if ((i + 1) != PathResult.Path->GetPathPoints().Num())
{
//Get the next location on path
nextLocation = PathResult.Path->GetPathPoints()[i + 1].Location;
//increase the total length of the path
pathLength += FMath::Abs(FVector::Distance(location, nextLocation));
}
}
UE_LOG(LogAIControllerBase, Log, TEXT("PathLength is %f, with %d path points. AAIController_Base::FindPathforMoveRequestToTarget()"), pathLength, PathResult.Path->GetPathPoints().Num());
//The distance along path we have calculated so far
float distance = 0.0f;
int i = 0;
//Now to go from point to point along path until we reach the middle of the path
for (i; i < PathResult.Path->GetPathPoints().Num(); i++)
{
// UE_LOG(LogAIControllerBase, Log, TEXT("Checking Points. AAIController_Base::FindPathforMoveRequestToTarget()"));
FVector location = PathResult.Path->GetPathPoints()*.Location;
FVector nextLocation;
//Get distance to next location in array so long as it is within array
if ((i + 1) != PathResult.Path->GetPathPoints().Num())
{
//Get the next location on path
nextLocation = PathResult.Path->GetPathPoints()[i + 1].Location;
//increase the distance checked along path
float nextPointDistance = FMath::Abs(FVector::Distance(location, nextLocation));
distance += nextPointDistance;
// UE_LOG(LogAIControllerBase, Log, TEXT("Distance from %d to %d is %f, total distance covered is %f. AAIController_Base::FindPathforMoveRequestToTarget()"), i, i + 1, nextPointDistance, distance);
//if from the current point to the next point is past the middle point of the path
if (distance >= (pathLength / 2))
{
//How much does the distance go past the half length of the path?
float distancePastMiddle = distance - (pathLength / 2);
//Using the difference above, find out how much will be traveled from current point to next point
float percentageOfDistance = FMath::Abs(distancePastMiddle / FVector::Distance(location, nextLocation));
/*
Finding a point along a line a certain distance away from another point!
https://math.stackexchange.com/questions/175896/finding-a-point-along-a-line-a-certain-distance-away-from-another-point/175906
solving for FVector( a, b)
currLocation is FVector(c,d)
NextLocation is FVector(e,f)
p = percentage
a = (1-p)c + pe
b = (1-p)d + pf
*/
FVector point;
point.X = ((1 - percentageOfDistance) * location.X) + (percentageOfDistance * nextLocation.X);
point.Y = ((1 - percentageOfDistance) * location.Y) + (percentageOfDistance * nextLocation.Y);
point.Z = 0;
//Set the location of the next point to the middle point of the total path
PathResult.Path->GetPathPoints()[i + 1].Location = point;
//Set battlepoint of AI for manager to pass on to target
AI->BattlePoint = point;
UE_LOG(LogAIControllerBase, Log, TEXT("Current Location: %s; Next Location: %s; Percentage of distance: %f; Middle Point: %s, last index in path is %d. AAIController_Base::FindPathforMoveRequestToTarget()"), *location.ToString(), *nextLocation.ToString(), percentageOfDistance, *point.ToString(), (i + 1));
break;
}
}
}
//Now remove all other points in path
int num = PathResult.Path->GetPathPoints().Num();
//Remove pathpoints from last index in array down to the last index used + 1
for (int d = num - 1; d > i + 1; d--)
{
PathResult.Path->GetPathPoints().RemoveAt(d);
// UE_LOG(LogAIControllerBase, Log, TEXT("Removing at %d, last index is %d. AAIController_Base::FindPathforMoveRequestToTarget()"), d, num - 1);
}
// OutPath = FNavigationPath(*PathResult.Path.Get());
OutPath = PathResult.Path;
UE_LOG(LogAIControllerBase, Log, TEXT("OutPath length is %d, location of goal: %s. AAIController_Base::FindPathforMoveRequestToTarget()"), OutPath.Get() ? OutPath.Get()->GetPathPoints().Num() : 0, *PathResult.Path->GetGoalLocation().ToString());
}
}
else
{
/* UE_VLOG(this, LogAINavigation, Error, TEXT("Trying to find path to %s resulted in Error")
, MoveRequest.IsMoveToActorRequest() ? *GetNameSafe(MoveRequest.GetGoalActor()) : *MoveRequest.GetGoalLocation().ToString());
UE_VLOG_SEGMENT(this, LogAINavigation, Error, GetPawn() ? GetPawn()->GetActorLocation() : FAISystem::InvalidLocation
, MoveRequest.GetGoalLocation(), FColor::Red, TEXT("Failed move to %s"), *GetNameSafe(MoveRequest.GetGoalActor()));
*/ }
}
}
[/SPOILER]