Files
UnrealEngine/Engine/Source/Runtime/AIModule/Classes/Navigation/PathFollowingComponent.h
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

758 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/WeakObjectPtr.h"
#include "Engine/EngineTypes.h"
#include "Components/ActorComponent.h"
#include "EngineDefines.h"
#include "AI/Navigation/NavigationTypes.h"
#include "NavigationData.h"
#include "AITypes.h"
#include "AIResourceInterface.h"
#include "GameFramework/NavMovementComponent.h"
#include "AI/Navigation/PathFollowingAgentInterface.h"
#include "PathFollowingComponent.generated.h"
class Error;
class FDebugDisplayInfo;
class INavLinkCustomInterface;
class UCanvas;
class ANavigationData;
AIMODULE_API DECLARE_LOG_CATEGORY_EXTERN(LogPathFollowing, Warning, All);
class UCanvas;
class AActor;
class INavLinkCustomInterface;
class INavAgentInterface;
class UNavigationComponent;
UENUM(BlueprintType)
namespace EPathFollowingStatus
{
enum Type : int
{
/** No requests */
Idle,
/** Request with incomplete path, will start after UpdateMove() */
Waiting,
/** Request paused, will continue after ResumeMove() */
Paused,
/** Following path */
Moving,
};
}
UENUM(BlueprintType)
namespace EPathFollowingResult
{
enum Type : int
{
/** Reached destination */
Success,
/** Movement was blocked */
Blocked,
/** Agent is not on path */
OffPath,
/** Aborted and stopped (failure) */
Aborted,
/** DEPRECATED, use Aborted result instead */
Skipped_DEPRECATED UMETA(Hidden),
/** Request was invalid */
Invalid,
};
}
namespace FPathFollowingResultFlags
{
typedef uint16 Type;
inline const Type None = 0;
/** Reached destination (EPathFollowingResult::Success) */
inline const Type Success = (1 << 0);
/** Movement was blocked (EPathFollowingResult::Blocked) */
inline const Type Blocked = (1 << 1);
/** Agent is not on path (EPathFollowingResult::OffPath) */
inline const Type OffPath = (1 << 2);
/** Aborted (EPathFollowingResult::Aborted) */
inline const Type UserAbort = (1 << 3);
/** Abort details: owner no longer wants to move */
inline const Type OwnerFinished = (1 << 4);
/** Abort details: path is no longer valid */
inline const Type InvalidPath = (1 << 5);
/** Abort details: unable to move */
inline const Type MovementStop = (1 << 6);
/** Abort details: new movement request was received */
inline const Type NewRequest = (1 << 7);
/** Abort details: blueprint MoveTo function was called */
inline const Type ForcedScript = (1 << 8);
/** Finish details: never started, agent was already at goal */
inline const Type AlreadyAtGoal = (1 << 9);
/** Can be used to create project specific reasons */
inline const Type FirstGameplayFlagShift = 10;
inline const Type UserAbortFlagMask = ~(Success | Blocked | OffPath);
FString ToString(uint16 Value);
}
struct FPathFollowingResult
{
FPathFollowingResultFlags::Type Flags;
TEnumAsByte<EPathFollowingResult::Type> Code;
FPathFollowingResult() : Flags(0), Code(EPathFollowingResult::Invalid) {}
AIMODULE_API FPathFollowingResult(FPathFollowingResultFlags::Type InFlags);
AIMODULE_API FPathFollowingResult(EPathFollowingResult::Type ResultCode, FPathFollowingResultFlags::Type ExtraFlags);
bool HasFlag(FPathFollowingResultFlags::Type Flag) const { return (Flags & Flag) != 0; }
bool IsSuccess() const { return HasFlag(FPathFollowingResultFlags::Success); }
bool IsFailure() const { return !HasFlag(FPathFollowingResultFlags::Success); }
bool IsInterrupted() const { return HasFlag(FPathFollowingResultFlags::UserAbort | FPathFollowingResultFlags::NewRequest); }
AIMODULE_API FString ToString() const;
};
// DEPRECATED, will be removed with GetPathActionType function
UENUM(BlueprintType)
namespace EPathFollowingAction
{
enum Type : int
{
Error,
NoMove,
DirectMove,
PartialPath,
PathToGoal,
};
}
UENUM(BlueprintType)
namespace EPathFollowingRequestResult
{
enum Type : int
{
Failed,
AlreadyAtGoal,
RequestSuccessful
};
}
struct FPathFollowingRequestResult
{
FAIRequestID MoveId;
TEnumAsByte<EPathFollowingRequestResult::Type> Code;
FPathFollowingRequestResult() : MoveId(FAIRequestID::InvalidRequest), Code(EPathFollowingRequestResult::Failed) {}
operator EPathFollowingRequestResult::Type() const { return Code; }
};
namespace EPathFollowingDebugTokens
{
enum Type : int
{
Description,
ParamName,
FailedValue,
PassedValue,
};
}
// DEPRECATED, please use EPathFollowingResultDetails instead, will be removed with deprecated override of AbortMove function
namespace EPathFollowingMessage
{
enum Type : int
{
NoPath,
OtherRequest,
};
}
enum class EPathFollowingVelocityMode : uint8
{
Reset,
Keep,
};
enum class EPathFollowingReachMode : uint8
{
/** reach test uses only AcceptanceRadius */
ExactLocation,
/** reach test uses AcceptanceRadius increased by modified agent radius */
OverlapAgent,
/** reach test uses AcceptanceRadius increased by goal actor radius */
OverlapGoal,
/** reach test uses AcceptanceRadius increased by modified agent radius AND goal actor radius */
OverlapAgentAndGoal,
};
UCLASS(config=Engine, MinimalAPI)
class UPathFollowingComponent : public UActorComponent, public IAIResourceInterface, public IPathFollowingAgentInterface
{
GENERATED_UCLASS_BODY()
DECLARE_DELEGATE_TwoParams(FPostProcessMoveSignature, UPathFollowingComponent* /*comp*/, FVector& /*velocity*/);
DECLARE_DELEGATE_OneParam(FRequestCompletedSignature, EPathFollowingResult::Type /*Result*/);
DECLARE_MULTICAST_DELEGATE_TwoParams(FMoveCompletedSignature, FAIRequestID /*RequestID*/, EPathFollowingResult::Type /*Result*/);
DECLARE_MULTICAST_DELEGATE_TwoParams(FMoveComplete, FAIRequestID /*RequestID*/, const FPathFollowingResult& /*Result*/);
/** delegate for modifying path following velocity */
FPostProcessMoveSignature PostProcessMove;
/** delegate for move completion notify */
FMoveComplete OnRequestFinished;
//~ Begin UActorComponent Interface
AIMODULE_API virtual void OnRegister() override;
AIMODULE_API virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
//~ End UActorComponent Interface
/** initialize component to use */
AIMODULE_API virtual void Initialize();
/** cleanup component before destroying */
AIMODULE_API virtual void Cleanup();
/** updates cached pointers to relevant owner's components */
AIMODULE_API virtual void UpdateCachedComponents();
/** start movement along path
* @return MoveId of requested move
*/
AIMODULE_API virtual FAIRequestID RequestMove(const FAIMoveRequest& RequestData, FNavPathSharedPtr InPath);
/** aborts following path */
AIMODULE_API virtual void AbortMove(const UObject& Instigator, FPathFollowingResultFlags::Type AbortFlags, FAIRequestID RequestID = FAIRequestID::CurrentRequest, EPathFollowingVelocityMode VelocityMode = EPathFollowingVelocityMode::Reset);
/** create new request and finish it immediately (e.g. already at goal)
* @return MoveId of requested (and already finished) move
*/
AIMODULE_API FAIRequestID RequestMoveWithImmediateFinish(EPathFollowingResult::Type Result, EPathFollowingVelocityMode VelocityMode = EPathFollowingVelocityMode::Reset);
/** pause path following
* @param RequestID - request to pause, FAIRequestID::CurrentRequest means pause current request, regardless of its ID */
AIMODULE_API virtual void PauseMove(FAIRequestID RequestID = FAIRequestID::CurrentRequest, EPathFollowingVelocityMode VelocityMode = EPathFollowingVelocityMode::Reset);
/** resume path following
* @param RequestID - request to resume, FAIRequestID::CurrentRequest means restor current request, regardless of its ID */
AIMODULE_API virtual void ResumeMove(FAIRequestID RequestID = FAIRequestID::CurrentRequest);
/** notify about finished movement */
AIMODULE_API virtual void OnPathFinished(const FPathFollowingResult& Result);
inline void OnPathFinished(EPathFollowingResult::Type ResultCode, uint16 ExtraResultFlags) { OnPathFinished(FPathFollowingResult(ResultCode, ExtraResultFlags)); }
/** notify about finishing move along current path segment */
AIMODULE_API virtual void OnSegmentFinished();
/** notify about changing current path: new pointer or update from path event */
AIMODULE_API virtual void OnPathUpdated();
/**
* set associated movement component.
* Note: This function is deprecated and was marked final to purposely alert users that this function should no longer be overriden
* Users should instead override SetNavMovementInterface(INavMovementInterface* NavMovementInterface)!
*/
UE_DEPRECATED(5.5, "SetMovementComponent(UNavMovementComponent* MoveComp) is deprecated, please use SetNavMoveInterface(INavMoveInterface* NavMoveInterface) instead.")
AIMODULE_API virtual void SetMovementComponent(UNavMovementComponent* MoveComp) final;
/** set associated nav movement interface */
AIMODULE_API virtual void SetNavMovementInterface(INavMovementInterface* NavMoveInterface);
/** get current focal point of movement */
AIMODULE_API virtual FVector GetMoveFocus(bool bAllowStrafe) const;
/** simple test for stationary agent (used as early finish condition), check if reached given point
* @param TestPoint - point to test
* @param AcceptanceRadius - allowed 2D distance
* @param ReachMode - modifiers for AcceptanceRadius
*/
AIMODULE_API bool HasReached(const FVector& TestPoint, EPathFollowingReachMode ReachMode, float AcceptanceRadius = UPathFollowingComponent::DefaultAcceptanceRadius) const;
/** simple test for stationary agent (used as early finish condition), check if reached given goal
* @param TestGoal - actor to test
* @param AcceptanceRadius - allowed 2D distance
* @param ReachMode - modifiers for AcceptanceRadius
* @param bUseNavAgentGoalLocation - true: if the goal is a nav agent, we will use their nav agent location rather than their actual location
*/
AIMODULE_API bool HasReached(const AActor& TestGoal, EPathFollowingReachMode ReachMode, float AcceptanceRadius = UPathFollowingComponent::DefaultAcceptanceRadius, bool bUseNavAgentGoalLocation = true) const;
/** simple test for stationary agent (used as early finish condition), check if reached target specified in move request */
AIMODULE_API bool HasReached(const FAIMoveRequest& MoveRequest) const;
/** update state of block detection */
AIMODULE_API void SetBlockDetectionState(bool bEnable);
/** @returns state of block detection */
bool IsBlockDetectionActive() const { return bUseBlockDetection; }
/** set block detection params */
AIMODULE_API void SetBlockDetection(float DistanceThreshold, float Interval, int32 NumSamples);
/** Returns true if pathfollowing is doing deceleration at the end of the path. */
bool IsDecelerating() const { return bIsDecelerating; };
/** @returns state of movement stopping on finish */
inline bool IsStopMovementOnFinishActive() const { return bStopMovementOnFinish; }
/** set whether movement is stopped on finish of move. */
inline void SetStopMovementOnFinish(bool bEnable) { bStopMovementOnFinish = bEnable; }
/** set threshold for precise reach tests in intermediate goals (minimal test radius) */
AIMODULE_API void SetPreciseReachThreshold(float AgentRadiusMultiplier, float AgentHalfHeightMultiplier);
/** set status of last requested move, works only in Idle state */
AIMODULE_API void SetLastMoveAtGoal(bool bFinishedAtGoal);
/** @returns estimated cost of unprocessed path segments
* @NOTE 0 means, that component is following final path segment or doesn't move */
AIMODULE_API FVector::FReal GetRemainingPathCost() const;
/** Returns current location on navigation data */
AIMODULE_API FNavLocation GetCurrentNavLocation() const;
inline EPathFollowingStatus::Type GetStatus() const
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return Status;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
inline float GetAcceptanceRadius() const { return AcceptanceRadius; }
inline float GetDefaultAcceptanceRadius() const { return MyDefaultAcceptanceRadius; }
AIMODULE_API void SetAcceptanceRadius(const float InAcceptanceRadius);
inline AActor* GetMoveGoal() const { return DestinationActor.Get(); }
inline bool HasPartialPath() const { return Path.IsValid() && Path->IsPartial(); }
inline bool DidMoveReachGoal() const
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return bLastMoveReachedGoal && (Status == EPathFollowingStatus::Idle);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
inline FAIRequestID GetCurrentRequestId() const { return CurrentRequestId; }
inline uint32 GetCurrentPathIndex() const { return MoveSegmentStartIndex; }
inline uint32 GetNextPathIndex() const { return MoveSegmentEndIndex; }
inline UObject* GetCurrentCustomLinkOb() const { return CurrentCustomLinkOb.Get(); }
inline FVector GetCurrentTargetLocation() const { return *CurrentDestination; }
inline FBasedPosition GetCurrentTargetLocationBased() const { return CurrentDestination; }
inline FVector GetMoveGoalLocationOffset() const { return MoveOffset; }
bool HasStartedNavLinkMove() const { return bWalkingNavLinkStart; }
AIMODULE_API bool IsCurrentSegmentNavigationLink() const;
AIMODULE_API FVector GetCurrentDirection() const;
/** note that CurrentMoveInput is only valid if MovementComp->UseAccelerationForPathFollowing() == true */
FVector GetCurrentMoveInput() const { return CurrentMoveInput; }
/** check if path following has authority over movement (e.g. not falling) and can update own state */
inline bool HasMovementAuthority() const { return (NavMovementInterface == nullptr) || NavMovementInterface->CanStopPathFollowing(); }
inline const FNavPathSharedPtr GetPath() const { return Path; }
inline bool HasValidPath() const { return Path.IsValid() && Path->IsValid(); }
AIMODULE_API bool HasDirectPath() const;
/** readable name of current status */
AIMODULE_API FString GetStatusDesc() const;
/** readable name of result enum */
AIMODULE_API FString GetResultDesc(EPathFollowingResult::Type Result) const;
AIMODULE_API void SetDestinationActor(const AActor* InDestinationActor);
/** returns index of the currently followed element of path. Depending on the actual
* path it may represent different things, like a path point or navigation corridor index */
virtual int32 GetCurrentPathElement() const { return MoveSegmentEndIndex; }
AIMODULE_API virtual void GetDebugStringTokens(TArray<FString>& Tokens, TArray<EPathFollowingDebugTokens::Type>& Flags) const;
AIMODULE_API virtual FString GetDebugString() const;
AIMODULE_API virtual void DisplayDebug(UCanvas* Canvas, const FDebugDisplayInfo& DebugDisplay, float& YL, float& YPos) const;
#if ENABLE_VISUAL_LOG
AIMODULE_API virtual void DescribeSelfToVisLog(struct FVisualLogEntry* Snapshot) const;
#endif // ENABLE_VISUAL_LOG
/** called when moving agent collides with another actor */
UFUNCTION()
AIMODULE_API virtual void OnActorBump(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit);
//~ IPathFollowingAgentInterface begin
AIMODULE_API virtual void OnUnableToMove(const UObject& Instigator) override;
AIMODULE_API virtual void OnStartedFalling() override;
virtual void OnLanded() override {}
AIMODULE_API virtual bool IsFollowingNavLink() const override;
//~ IPathFollowingAgentInterface end
/** Check if path following can be activated */
AIMODULE_API virtual bool IsPathFollowingAllowed() const;
/** call when moving agent finishes using custom nav link, returns control back to path following */
AIMODULE_API virtual void FinishUsingCustomLink(INavLinkCustomInterface* CustomNavLink);
/** called when owner is preparing new pathfinding request */
virtual void OnPathfindingQuery(FPathFindingQuery& Query) {}
//~ IAIResourceInterface begin
AIMODULE_API virtual void LockResource(EAIRequestPriority::Type LockSource) override;
AIMODULE_API virtual void ClearResourceLock(EAIRequestPriority::Type LockSource) override;
AIMODULE_API virtual void ForceUnlockResource() override;
AIMODULE_API virtual bool IsResourceLocked() const override;
//~ IAIResourceInterface end
/** path observer */
AIMODULE_API void OnPathEvent(FNavigationPath* InPath, ENavPathEvent::Type Event);
/** helper function for sending a path for visual log */
static AIMODULE_API void LogPathHelper(const AActor* LogOwner, FNavPathSharedPtr InLogPath, const AActor* LogGoalActor);
static AIMODULE_API void LogPathHelper(const AActor* LogOwner, FNavigationPath* InLogPath, const AActor* LogGoalActor);
UFUNCTION(BlueprintCallable, Category="AI|Components|PathFollowing", meta = (DeprecatedFunction, DeprecationMessage = "This function is now deprecated, please use AIController.GetMoveStatus instead"))
AIMODULE_API EPathFollowingAction::Type GetPathActionType() const;
UFUNCTION(BlueprintCallable, Category="AI|Components|PathFollowing", meta = (DeprecatedFunction, DeprecationMessage = "This function is now deprecated, please use AIController.GetImmediateMoveDestination instead"))
AIMODULE_API FVector GetPathDestination() const;
#if WITH_EDITORONLY_DATA
// This delegate is now deprecated, please use OnRequestFinished instead
FMoveCompletedSignature OnMoveFinished_DEPRECATED;
#endif
protected:
/** Sets the current status and activates/deactivates the component if necessary */
AIMODULE_API void SetStatus(EPathFollowingStatus::Type InStatus);
/** deprecated associated movement component */
UE_DEPRECATED(5.5, "MovementComp is deprecated, please use NavMovementComp and the INavMoveInterface instead.")
UPROPERTY(transient, meta = (DeprecatedProperty, DeprecationMessage = "MovementComp is deprecated, please use NavMovementInterface and the INavMoveInterface instead."))
TObjectPtr<UNavMovementComponent> MovementComp;
/** associated movement interface */
TWeakInterfacePtr<INavMovementInterface> NavMovementInterface;
/** currently traversed custom nav link */
FWeakObjectPtr CurrentCustomLinkOb;
/** the custom link for the next segment if there is one */
FWeakObjectPtr MoveSegmentCustomLinkOb;
/** navigation data for agent described in movement component */
UPROPERTY(transient)
TObjectPtr<ANavigationData> MyNavData;
/** requested path */
FNavPathSharedPtr Path;
/** Navigation query filter of the current move request */
FSharedConstNavQueryFilter NavigationFilter;
/** value based on navigation agent's properties that's used for AcceptanceRadius when DefaultAcceptanceRadius is requested */
float MyDefaultAcceptanceRadius;
/** min distance to destination to consider request successful.
* If following a partial path movement request will finish
* when the original goal gets within AcceptanceRadius or
* pathfollowing agent gets within MyDefaultAcceptanceRadius
* of the end of the path*/
float AcceptanceRadius;
/** min distance to end of current path segment to consider segment finished */
float CurrentAcceptanceRadius;
/** part of agent radius used as min acceptance radius */
float MinAgentRadiusPct;
/** part of agent height used as min acceptable height difference */
float MinAgentHalfHeightPct;
/** timeout for Waiting state, negative value = infinite */
float WaitingTimeout;
/** game specific data */
FCustomMoveSharedPtr GameData;
/** destination actor. Use SetDestinationActor to set this */
TWeakObjectPtr<AActor> DestinationActor;
/** cached DestinationActor cast to INavAgentInterface. Use SetDestinationActor to set this */
const INavAgentInterface* DestinationAgent;
/** destination for current path segment */
FBasedPosition CurrentDestination;
/** last MoveInput calculated and passed over to MovementComponent. Valid only if MovementComp->UseAccelerationForPathFollowing() == true */
FVector CurrentMoveInput;
/** relative offset from goal actor's location to end of path */
FVector MoveOffset;
/** agent location when movement was paused */
FVector LocationWhenPaused;
/** This is needed for partial paths when trying to figure out if following a path should finish
* before reaching path end, due to reaching requested acceptance radius away from original
* move goal
* Is being set for non-partial paths as well */
FVector OriginalMoveRequestGoalLocation;
/** timestamp of path update when movement was paused */
double PathTimeWhenPaused;
/** Indicates a path node index at which precise "is at goal"
* tests are going to be performed every frame, in regards
* to acceptance radius */
int32 PreciseAcceptanceRadiusCheckStartNodeIndex;
UE_DEPRECATED_FORGAME(5.6, "This member should no longer be accessed directly, please use GetStatus/SetStatus instead.")
/** current status */
TEnumAsByte<EPathFollowingStatus::Type> Status;
/** increase acceptance radius with agent's radius */
uint8 bReachTestIncludesAgentRadius : 1;
/** increase acceptance radius with goal's radius */
uint8 bReachTestIncludesGoalRadius : 1;
/** if set, target location will be constantly updated to match goal actor while following last segment of full path */
uint8 bMoveToGoalOnLastSegment : 1;
/** Whether to clamp the goal location to reachable navigation data when trying to track the goal actor (Only used when bMoveToGoalOnLastSegment is true)
* False: (default) while following the last segment, the path is allowed to adjust through obstacles and off navigation data without checks.
* True: the last segment's destination will be clamped at the furthest reachable location towards the goal actor. */
uint8 bMoveToGoalClampedToNavigation : 1;
/** if set, movement block detection will be used */
uint8 bUseBlockDetection : 1;
/** set when agent collides with goal actor */
uint8 bCollidedWithGoal : 1;
/** set when last move request was finished at goal */
uint8 bLastMoveReachedGoal : 1;
/** if set, movement will be stopped on finishing path */
uint8 bStopMovementOnFinish : 1;
/** if set, path following is using FMetaNavMeshPath */
uint8 bIsUsingMetaPath : 1;
/** gets set when agent starts following a navigation link. Cleared after agent starts falling or changes segment to a non-link one */
uint8 bWalkingNavLinkStart : 1;
/** True if pathfollowing is doing deceleration at the end of the path. @see FollowPathSegment(). */
uint8 bIsDecelerating : 1;
/** True if the next segment is a custom link that has its own reach conditions. */
uint8 bMoveSegmentIsUsingCustomLinkReachCondition : 1;
/**
* Indicates if the component activation/ticking is controlled by setting the Status (Moving --> Activated, other --> Deactivated)
* Note that this optimization is not used for any derived classes since those might need to tick in other cases.
*/
uint8 bTickComponentOnlyWhenMoving : 1;
/** detect blocked movement when distance between center of location samples and furthest one (centroid radius) is below threshold */
float BlockDetectionDistance;
/** interval for collecting location samples */
float BlockDetectionInterval;
/** number of samples required for block detection */
int32 BlockDetectionSampleCount;
/** timestamp of last location sample */
double LastSampleTime;
/** index of next location sample in array */
int32 NextSampleIdx;
/** location samples for stuck detection */
TArray<FBasedPosition> LocationSamples;
/** index of path point being current move beginning */
int32 MoveSegmentStartIndex;
/** index of path point being current move target */
int32 MoveSegmentEndIndex;
/** reference of node at segment start */
NavNodeRef MoveSegmentStartRef;
/** reference of node at segment end */
NavNodeRef MoveSegmentEndRef;
/** direction of current move segment */
FVector MoveSegmentDirection;
/** braking distance for acceleration driven path following */
float CachedBrakingDistance;
/** max speed used for CachedBrakingDistance */
float CachedBrakingMaxSpeed;
/** index of path point for starting deceleration */
int32 DecelerationSegmentIndex;
/** extract the navigation filter that should be used based on the provided MoveRequest and NavPath */
AIMODULE_API FSharedConstNavQueryFilter ExtractNavigationFilter(const FAIMoveRequest& RequestData, FNavPathSharedPtr InPath) const;
/** reset path following data */
AIMODULE_API virtual void Reset();
/** Called if owning Controller possesses new pawn or ends up pawn-less.
* Doesn't get called if owner is not an AContoller */
AIMODULE_API virtual void OnNewPawn(APawn* NewPawn);
/** should verify if agent if still on path ater movement has been resumed? */
AIMODULE_API virtual bool ShouldCheckPathOnResume() const;
/** sets variables related to current move segment */
AIMODULE_API virtual void SetMoveSegment(int32 SegmentStartIndex);
/** follow current path segment */
AIMODULE_API virtual void FollowPathSegment(float DeltaTime);
/** check state of path following, update move segment if needed */
AIMODULE_API virtual void UpdatePathSegment();
/** next path segment if custom nav link, try passing control to it */
AIMODULE_API virtual void StartUsingCustomLink(INavLinkCustomInterface* CustomNavLink, const FVector& DestPoint);
/** update blocked movement detection, @returns true if new sample was added */
AIMODULE_API virtual bool UpdateBlockDetection();
/** updates braking distance and deceleration segment */
AIMODULE_API virtual void UpdateDecelerationData();
/** check if move is completed */
AIMODULE_API virtual bool HasReachedDestination(const FVector& CurrentLocation) const;
/** check if segment is completed */
AIMODULE_API virtual bool HasReachedCurrentTarget(const FVector& CurrentLocation) const;
/** check if moving agent has reached goal defined by cylinder */
AIMODULE_API bool HasReachedInternal(const FVector& GoalLocation, float GoalRadius, float GoalHalfHeight, const FVector& AgentLocation, float RadiusThreshold, float AgentRadiusMultiplier) const;
/** reset the cached information about CustomLinks on the next MoveSegment */
AIMODULE_API void ResetMoveSegmentCustomLinkCache();
/** check if agent is on path */
AIMODULE_API virtual bool IsOnPath() const;
/** check if movement is blocked */
AIMODULE_API bool IsBlocked() const;
/** switch to next segment on path */
inline void SetNextMoveSegment() { SetMoveSegment(GetNextPathIndex()); }
/** assign new request Id */
inline void StoreRequestId() { CurrentRequestId = UPathFollowingComponent::GetNextRequestId(); }
inline static uint32 GetNextRequestId() { return NextRequestId++; }
/** Checks if this PathFollowingComponent is already on path, and
* if so determines index of next path point
* @return what PathFollowingComponent thinks should be next path point. INDEX_NONE if given path is invalid
* @note this function does not set MoveSegmentEndIndex */
AIMODULE_API virtual int32 DetermineStartingPathPoint(const FNavigationPath* ConsideredPath) const;
/** @return index of path point, that should be target of current move segment */
AIMODULE_API virtual int32 DetermineCurrentTargetPathPoint(int32 StartIndex);
/** check if movement component is valid or tries to grab one from owner
* @param bForce results in looking for owner's movement component even if pointer to one is already cached */
AIMODULE_API virtual bool UpdateMovementComponent(bool bForce = false);
/** called after receiving update event from current path
* @return false if path was not accepted and move request needs to be aborted */
AIMODULE_API virtual bool HandlePathUpdateEvent();
/** called from timer if component spends too much time in Waiting state */
AIMODULE_API virtual void OnWaitingPathTimeout();
/** clears Block Detection stored data effectively resetting the mechanism */
AIMODULE_API void ResetBlockDetectionData();
/** force creating new location sample for block detection */
AIMODULE_API void ForceBlockDetectionUpdate();
/** set move focus in AI owner */
AIMODULE_API virtual void UpdateMoveFocus();
/** defines if the agent should reset his velocity when the path is finished*/
AIMODULE_API virtual bool ShouldStopMovementOnPathFinished() const;
/** For given path finds a path node at which
* PathfollowingComponent should start doing
* precise is-goal-in-acceptance-radius tests */
AIMODULE_API int32 FindPreciseAcceptanceRadiusTestsStartNodeIndex(const FNavigationPath& PathInstance, const FVector& GoalLocation) const;
/** Based on Path's properties, original move goal location and requested AcceptanceRadius
* this function calculates actual acceptance radius to apply when testing if the agent
* has successfully reached requested goal's vicinity */
AIMODULE_API float GetFinalAcceptanceRadius(const FNavigationPath& PathInstance, const FVector OriginalGoalLocation, const FVector* PathEndOverride = nullptr) const;
/** debug point reach test values */
AIMODULE_API void DebugReachTest(float& CurrentDot, float& CurrentDistance, float& CurrentHeight, uint8& bDotFailed, uint8& bDistanceFailed, uint8& bHeightFailed) const;
/** called when NavigationSystem finishes initial navigation data registration.
* This is usually required by AI agents hand-placed on levels to find MyNavData */
AIMODULE_API virtual void OnNavigationInitDone();
/** called when NavigationSystem registers new navigation data type while this component
* instance has empty MyNavData. This is usually the case for AI agents hand-placed
* on levels. */
UFUNCTION()
AIMODULE_API void OnNavDataRegistered(ANavigationData* NavData);
/** used to keep track of which subsystem requested this AI resource be locked */
FAIResourceLock ResourceLock;
/** timer handle for OnWaitingPathTimeout function */
FTimerHandle WaitingForPathTimer;
private:
/** used for debugging purposes to be able to identify which logged information
* results from which request, if there was multiple ones during one frame */
static AIMODULE_API uint32 NextRequestId;
FAIRequestID CurrentRequestId;
/** Current location on navigation data. Lazy-updated, so read this via GetCurrentNavLocation().
* Since it makes conceptual sense for GetCurrentNavLocation() to be const but we may
* need to update the cached value, CurrentNavLocation is mutable. */
mutable FNavLocation CurrentNavLocation;
public:
/** special float constant to symbolize "use default value". This does not contain
* value to be used, it's used to detect the fact that it's requested, and
* appropriate value from querier/doer will be pulled */
static AIMODULE_API const float DefaultAcceptanceRadius;
#if !UE_BUILD_SHIPPING
uint8 DEBUG_bMovingDirectlyToGoal : 1;
#endif // !UE_BUILD_SHIPPING
};