MoveTo task: How to move to player's location at any given location they are at

Hope following codes can help somebody

MoveActorToLocationAndWait.h

#pragma once

#include "CoreMinimal.h"
#include "GameplayTask.h"
#include "Navigation/PathFollowingComponent.h"
#include "AbilitySystemComponent.h"
#include "MoveActorToLocationAndWait.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMoveActorToLocationDelegate);

UCLASS()
class CRISISINKARNO_API UMoveActorToLocationAndWait : public UGameplayTask
{
	GENERATED_BODY()
	
public:
	UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "TRUE"))
	static UMoveActorToLocationAndWait*  moveActorToLocationAndWait(UAbilitySystemComponent* abilitySystemComponent, AController* controller,
		const FVector& goalLocation, float AgentRadiusMultiplier = 1, float AgentHalfHeightMultiplier = 1.1);

	virtual void Activate() override;
	virtual void ExternalCancel() override;
	virtual void OnDestroy(bool AbilityEnded) override;

private:
	virtual void OnRequestFinished(FAIRequestID RequestID, const FPathFollowingResult& Result);
	UPathFollowingComponent* initNavigationController(AController& Controller);

public:
	UPROPERTY(BlueprintAssignable)
	FMoveActorToLocationDelegate  onCompleted;

	UPROPERTY(BlueprintAssignable)
	FMoveActorToLocationDelegate  onFailed;

private:
	AController* _controller = nullptr;
	FVector _goalLocation;
	float _agentRadiusMultiplier;
	float _agentHalfHeightMultiplier;
	UPathFollowingComponent* _pathFollowingComponent = nullptr;
	FDelegateHandle _callbackHandle;
};

MoveActorToLocationAndWait.cpp

#include "MoveActorToLocationAndWait.h"
#include "NavigationPath.h"
#include "NavigationData.h"
#include "NavigationSystem.h"
#include "NavMesh/NavMeshPath.h"
#include "Navigation/PathFollowingComponent.h"
#include "AIController.h"

UMoveActorToLocationAndWait* UMoveActorToLocationAndWait::moveActorToLocationAndWait(UAbilitySystemComponent* abilitySystemComponent, AController* controller, const FVector& goalLocation,
	float AgentRadiusMultiplier, float AgentHalfHeightMultiplier)
{
	UMoveActorToLocationAndWait* ret = NewObject<UMoveActorToLocationAndWait>();
	ret->_controller = controller;
	ret->_goalLocation = goalLocation;
	ret->_agentHalfHeightMultiplier = AgentHalfHeightMultiplier;
	ret->_agentRadiusMultiplier = AgentRadiusMultiplier;
	ret->InitTask(*abilitySystemComponent, abilitySystemComponent->GetGameplayTaskDefaultPriority());
	return ret;
}

UPathFollowingComponent* UMoveActorToLocationAndWait::initNavigationController(AController& Controller)
{
	AAIController* AsAIController = Cast<AAIController>(&Controller);
	UPathFollowingComponent* PathFollowingComp = nullptr;

	if (AsAIController)
	{
		PathFollowingComp = AsAIController->GetPathFollowingComponent();
	}
	else
	{
		PathFollowingComp = Controller.FindComponentByClass<UPathFollowingComponent>();
		if (PathFollowingComp == nullptr)
		{
			PathFollowingComp = NewObject<UPathFollowingComponent>(&Controller);
			PathFollowingComp->RegisterComponentWithWorld(Controller.GetWorld());
			PathFollowingComp->Initialize();
		}
	}
	
	return PathFollowingComp;
}

void UMoveActorToLocationAndWait::Activate()
{
	UNavigationSystemV1* NavSys = _controller ? FNavigationSystem::GetCurrent<UNavigationSystemV1>(_controller->GetWorld()) : nullptr;
	if (NavSys == nullptr || _controller == nullptr || _controller->GetPawn() == nullptr)
	{
		EndTask();
		onFailed.Broadcast();
		return;
	}

	if (_pathFollowingComponent == nullptr)
	{
		_pathFollowingComponent = initNavigationController(*_controller);
		if (_pathFollowingComponent == nullptr)
		{
			EndTask();
			onFailed.Broadcast();
			return;
		}
	}

	if (!_pathFollowingComponent->IsPathFollowingAllowed())
	{
		EndTask();
		onFailed.Broadcast();
		return;
	}

	const bool bAlreadyAtGoal = _pathFollowingComponent->HasReached(_goalLocation, EPathFollowingReachMode::OverlapGoal);

	// script source, keep only one move request at time
	if (_pathFollowingComponent->GetStatus() != EPathFollowingStatus::Idle)
	{
		_pathFollowingComponent->AbortMove(*NavSys, FPathFollowingResultFlags::ForcedScript | FPathFollowingResultFlags::NewRequest
			, FAIRequestID::AnyRequest, bAlreadyAtGoal ? EPathFollowingVelocityMode::Reset : EPathFollowingVelocityMode::Keep);
	}

	// script source, keep only one move request at time
	if (_pathFollowingComponent->GetStatus() != EPathFollowingStatus::Idle)
	{
		_pathFollowingComponent->AbortMove(*NavSys, FPathFollowingResultFlags::ForcedScript | FPathFollowingResultFlags::NewRequest);
	}
	do
	{
		if (bAlreadyAtGoal)
		{
			_callbackHandle = _pathFollowingComponent->OnRequestFinished.AddUObject(this, &UMoveActorToLocationAndWait::OnRequestFinished);
			_pathFollowingComponent->RequestMoveWithImmediateFinish(EPathFollowingResult::Success);
		}
		else
		{
			const FVector AgentNavLocation = _controller->GetNavAgentLocation();
			const ANavigationData* NavData = NavSys->GetNavDataForProps(_controller->GetNavAgentPropertiesRef(), AgentNavLocation);
			if (!NavData)
				break;
			
			FPathFindingQuery Query(_controller, *NavData, AgentNavLocation, _goalLocation);
			FPathFindingResult Result = NavSys->FindPathSync(Query);
			if (Result.IsSuccessful())
			{
				//Result.Path->DebugDraw(NavData, FColor(255, 0, 0, 255), nullptr, true, 10, 0);	//debug
				_callbackHandle = _pathFollowingComponent->OnRequestFinished.AddUObject(this, &UMoveActorToLocationAndWait::OnRequestFinished);

				FAIMoveRequest requestData(_goalLocation);
				_pathFollowingComponent->SetPreciseReachThreshold(_agentRadiusMultiplier, _agentHalfHeightMultiplier);
				_pathFollowingComponent->RequestMove(requestData, Result.Path);
			}
			else if(_pathFollowingComponent->GetStatus() != EPathFollowingStatus::Idle)
			{
				_callbackHandle = _pathFollowingComponent->OnRequestFinished.AddUObject(this, &UMoveActorToLocationAndWait::OnRequestFinished);
				_pathFollowingComponent->RequestMoveWithImmediateFinish(EPathFollowingResult::Invalid);
			}
			else {
				break;
			}
			
		}
		return;
	} while (false);

	EndTask();
	onFailed.Broadcast();
}

void UMoveActorToLocationAndWait::ExternalCancel()
{

}

void UMoveActorToLocationAndWait::OnDestroy(bool AbilityEnded)
{
	if (_pathFollowingComponent && _callbackHandle.IsValid())
		_pathFollowingComponent->OnRequestFinished.Remove(_callbackHandle);
	Super::OnDestroy(AbilityEnded);
}

void UMoveActorToLocationAndWait::OnRequestFinished(FAIRequestID requestID, const FPathFollowingResult& result)
{
	EndTask();
	onCompleted.Broadcast();
}