1
0
KF2-Dev-Scripts/Engine/Classes/NavigationHandle.uc
2020-12-13 18:01:13 +03:00

955 lines
44 KiB
Ucode

//=============================================================================
// NavigationHandle
//
// Component that encapsulates navigation behavior. Attach this to your actor of choice to
// enable that actor to pathfind
//
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
//=============================================================================
class NavigationHandle extends Object within Actor
native(AI);
struct native PolySegmentSpan
{
var native pointer Poly{FNavMeshPolyBase};
var Vector P1, P2;
structcpptext
{
explicit FPolySegmentSpan( struct FNavMeshPolyBase* inPoly, FVector inP1, FVector inP2 )
{
Poly = inPoly;
P1 = inP1;
P2 = inP2;
}
}
};
/** Current pylon AI is anchored to */
var Pylon AnchorPylon;
var native pointer AnchorPoly{FNavMeshPolyBase};
/** dummy struct used to match alignment in pathcache array */
struct {FNavMeshEdgeBase*} EdgePointer
{
var native const pointer Dummy{FNavMeshEdgeBase};
};
// struct containing the pathcache aray. Used so that
// pathcaches can easily be stored and copied around in script
struct native PathStore
{
structcpptext
{
FORCEINLINE FNavMeshEdgeBase*& operator()( INT i )
{
return EdgeList(i);
}
FORCEINLINE INT Num()
{
return EdgeList.Num();
}
FNavMeshEdgeBase*& Last( INT c=0 )
{
return EdgeList.Last(c);
}
FNavMeshEdgeBase*& Top()
{
return Last();
}
}
var native array<EdgePointer> EdgeList;
};
var PathStore PathCache;
/**
* This points to the BestUnfinishedPathPoint. Which will usually be set by some EvaluateGoal or DetermineFinalGoal function/
* In some cases it is not possible to get a full path, but having the best unfinished path is good enough (e.g. ai on top
* of a crevice, or on a navmesh island disconnected from everyone else)
**/
var transient native pointer BestUnfinishedPathPoint{FNavMeshPolyBase};
/** List of polys to move through */
var const native pointer CurrentEdge{FNavMeshEdgeBase};
/** the poly we're currently trying to get inside */
var const native pointer SubGoal_DestPoly{FNavMeshPolyBase};
/** Final destination */
var BasedPosition FinalDestination;
/** AI should not update route cache - flag to prevent cache from being changed when pathing is used to evaluate squad location */
var bool bSkipRouteCacheUpdates;
const LINECHECK_GRANULARITY = 768.f;
/** List of search constraints for pathing */
var NavMeshPathConstraint PathConstraintList;
var NavMeshPathGoalEvaluator PathGoalList;
/** when this is TRUE the goal evaluator chain will be treated as an OR chain instead of an AND chain */
var bool bUseORforEvaluateGoal;
/** this is a handy way of ensuring everyone is setting the necessary parameters.. this should always reflect the number of
* parameters in the NavMeshPathParams struct, and then in SetupPathingParams a check will be inserted with the
* number of params in existence at the time of writing the function, so if the number of params changes and the implementations
* are not updated an assert will fire
*/
const NUM_PATHFINDING_PARAMS = 9;
// this struct is where all the non-volatile pathing params are cached at the beginning of a path search.
// Populated from Interface_NavigationHandle::SetupPathfindingParams()
struct native NavMeshPathParams
{
/** the navhandle interface for the pathing entity */
var native pointer Interface{IInterface_NavigationHandle};
/** can this entity use mantle edges? */
var bool bCanMantle;
/** do we need to perform extra checks when determining if an edge supports the entiy? */
var bool bNeedsMantleValidityTest;
/** is this entity valid to pathfind (does it have a pawn, etc..) */
var bool bAbleToSearch;
/** the size of the entity looking for a path */
/* @NOTE: this will use the LARGEST of the X/Y dimensions. Pathfinding extents must be symmetrical, so if the extent is not,
it will be made to be symmetric. (for long train-like objects path with the extent of the leader, and the rest will follow)
@see FNavMeshEdgeBase::Supports()
*/
var Vector SearchExtent;
var float SearchLaneMultiplier;
/** the starting location for the path search */
var vector SearchStart;
/** the maximum valid height for this entity to 'drop down' (e.g. max height to use on dropdown edges) */
var float MaxDropHeight;
/** the minimum value for the Z component of walkable surfaces */
var float MinWalkableZ;
/** max hover distance -- the maximum distance this entity can hover above the surface of a polygon. (-1 means arbitrarily high) */
var float MaxHoverDistance;
};
// the cached path params for the current search
var NavMeshPathParams CachedPathParams;
/** when this bool is TRUE, statistics about which constraints are doing what will be printed following
* path searches
*/
var(PathDebug) bool bDebugConstraintsAndGoalEvals;
/**
* when true TONS of information will be printed to the log, as well as a bunch of stuff drawn to the screen.
* debug lines will be drawn indicating the progress of the path traversal, and whenever a log message is printed related
* to an edge on the navmesh a number will be printed to the screen above it indexing into the log messages to tell you
* what that message is.
* RED lines indicate expansion was stopped at that step, other colors will change depending on the expansion generation
* (e.g. all edges traversed in the first step will be of the same color, second step a different color etc..
*/
var(PathDebug) bool bUltraVerbosePathDebugging;
/** If true, only adds the visual parts of verbose path debugging, without the log spew */
var(PathDebug) bool bVisualPathDebugging;
/**
* Relevant error code set by FindPath when a path search fails.
* Allows decision on how to resolve a failed search by providing more information on the failure cause .
* Only valid if FindPath returns FALSE. Safe to ignore otherwise.
* This value is not updated until the next search fails.
*/
var(PathDebug) EPathFindingError LastPathError;
var(PathDebug) float LastPathFailTime;
/** max breadcrumbs - number of breadcrumbs to keep track of */
const NumBreadCrumbs = 10;
/** ring buffer of breadcrumb positions */
var vector Breadcrumbs[NumBreadCrumbs];
/** index that represents the most recent breadcrumb */
var int BreadCrumbMostRecentIdx;
/** bread crumb interval (how far we need to move before laying a new breadcrumb) */
var float BreadCrumbDistanceInterval;
/** draw breadcrumb debug info? */
var() bool bDebug_Breadcrumbs;
cpptext
{
public:
UNavigationHandle()
{
if(!IsTemplate())
{
FNavMeshWorld::RegisterActiveHandle(this);
}
}
// use this in SetupPathingParams and pass the number of params you have populated to ensure when new properties
// are added to the struct that you are setting them all
#define VERIFY_NAVMESH_PARAMS(NUM) \
typedef char ERROR_Missing_NavMesh_param_please_Set_all_Params[( NUM != UCONST_NUM_PATHFINDING_PARAMS ) ? 0 : 1];
// returns TRUE if the pylon and poly associated with the interface's current location can be found
static UBOOL GetPylonAndPolyFromActorPos( AActor* Actor, APylon*& out_Pylon, struct FNavMeshPolyBase*& out_Poly);
/**
* GetPylonANdPolyFromPos
* - will search for the pylon and polygon that contain this point
* @param Pos - position to get pylon and poly from
* @param out_Pylon - output var for pylon this position is within
* @param out_Poly - output var for poly this position is within
* @param PylonsToConsider - only check these pylons (useful for perf)
* @return - TRUE if the pylon and poly were found succesfully
*/
static UBOOL GetPylonAndPolyFromPos(const FVector& Pos, FLOAT MinWalkableFloorZ, APylon*& out_Pylon, struct FNavMeshPolyBase*& out_Poly, TArray<APylon*>* PylonsToConsider=NULL);
/**
* GetAllPylonsFromPos
* - will populate a list of all pylons which are valid (in terms of can a pawn walk from the possible pylon) for the given position
* @param Pos - position to test
* @param out_Pylons - list of pylons to be populated with results
* @param bWalkable - whether or not this pylon's polys need to be "walkable" FALSE for looking for disconnected pylons
* @return TRUE if any pylons were found
*/
static UBOOL GetAllPylonsFromPos(const FVector& Pos, const FVector& Extent, TArray<APylon*>& out_Pylons, UBOOL bWalkable = TRUE );
/**
* GetPylonAndPolyFromBox
* - will search for the pylon and polygon that contain this box
* @param Box - the box to use to find a poly for
* @param out_Pylon - output var for pylon this position is within
* @param out_Poly - output var for poly this position is within
* @return - TRUE if the pylon and poly were found succesfully
*/
static UBOOL GetPylonAndPolyFromBox(const FBox& Box, FLOAT MinWalkableZ, APylon*& out_Pylon, struct FNavMeshPolyBase*& out_Poly);
/**
* GetAnchorPoly
* - will find a suitable anchor (start) poly for this handle
* @return - the suitable poly (if any)
*/
FNavMeshPolyBase* GetAnchorPoly();
/**
* GetAllPolysFromPos
* will return all polys in any mesh which are within the passed extent
* @param Pos - Center of extent to check
* @param Extent - extent of box to check
* @param out_PolyList - output array of polys to check
* @param bIgnoreDynamic - if TRUE, dynamically created submeshes will be ignored
* @param bReturnBothDynamicAndStatic - if TRUE, BOTH dynamic and static polys will be returned.. using this is *DANGEROUS*! most of the time you should use dynamic polys if they exist
* as they are the 'correct' representation of the mesh at that point
* @param PylonsToConsider - list of pylons to consider for this check, defauls to doing an octree check to determine this list
* @param TraceFlags - flags for trace dilineation
* @return TRUE if polys were found
*/
static UBOOL GetAllPolysFromPos( const FVector& Pos, const FVector& Extent, TArray<struct FNavMeshPolyBase*>& out_PolyList, UBOOL bIgnoreDynamic, UBOOL bReturnBothDynamicAndStatic=FALSE, TArray<APylon*>* PylonsToConsider=NULL, DWORD TraceFlags=0);
/**
* GetAllObstaclePolysFromPos
* will return all obstacle polys in any mesh which are within the passed extent
* @param Pos - Center of extent to check
* @param Extent - extent of box to check
* @param out_PolyList - output array of polys to check
* @param PylonsToCheck - OPTIONAL param indicating the lsit of pylons we should check instead of hitting the pylon octree
* @param bSkipDynamicObstacleMesh - OPTIONAL param, when true only static obstacle mesh polys will be returned
* @param TraceFlags - flags for trace dilineation
* @return TRUE if polys were found
*/
static void GetAllObstaclePolysFromPos( const FVector& Pos,
const FVector& Extent,
TArray<struct FNavMeshPolyBase*>& out_PolyList,
const TArray<APylon*>* PylonsToCheck=NULL,
UBOOL bSkipDynamicObstacleMesh=FALSE,
DWORD TraceFlags=0);
// returns TRUE if the AABB provided intersects a loaded portion of the mesh
static UBOOL BoxIntersectsMesh( const FVector& Center, const FVector& Extent, APylon*& out_Pylon, struct FNavMeshPolyBase*& out_Poly, DWORD TraceFlags=0);
/**
* returns TRUE if the poly described by the passed list of vectors intersects a loaded portion of the mesh
* @param Poly - vertexlist representing the poly we want to query against the mesh
* @param out_Pylon - pylon we collided with
* @param out_Poly - poly we collided with
* @arapm ExclusionPolys - optional list of polys we want to exclude from the search
* @param bIgnoreImportedMeshes - when TRUE meshes which unwalkable surfaces will be ignored for overlap testing
* @param IgnorePylons - optional pylons to ignore collisions from
* @return TRUE if poly intersects
*/
static UBOOL PolyIntersectsMesh( TArray<FVector>& Poly, APylon*& out_Pylon, struct FNavMeshPolyBase*& out_Poly, TArray<FNavMeshPolyBase*>* ExclusionPolys=NULL, UBOOL bIgnoreImportedMeshes=FALSE, TArray<APylon*>* IgnorePylons=NULL, DWORD TraceFlags=0);
// queries the pylon octree and returns a list of pylons that intersect the given AABB
static void GetIntersectingPylons(const FVector& Loc, const FVector& Extent, TArray<APylon*>& out_Pylons,class AActor* SrcActor=NULL);
/**
* Given a line segment, walks along the segment returning all polys that it crosses as entry and exit points of that segment
* (will find spans from any navmesh in the world)
* @param Start - Start point of span to check
* @param End - end point of span
* @Param out_Spans - out array of spans found and the polys they link to
*/
static void GetPolySegmentSpanList( FVector& Start, FVector& End, TArray<struct FPolySegmentSpan>& out_Spans );
/**
* static function that will do an obstacle line check against any pylon's meshes colliding with the line passed
* @param InOuter - The Outer which owns this NavHandle. Can be used for debugging
* @param Hit - Hitresult struct for line check
* @param Start - start of line check
* @param End - end of line check
* @param Extent - extent of box to sweep
* @param bIgnoreNormalMesh - OPTIONAL - default:FALSE - when TRUE no checks against the walkable mesh will be performed
* @param out_HitPoly - optional output param stuffed with the poly we collided with (if any)
* @param PylonsToCheck - OPTIONAL, if present only these pylons' meshes will be linecheck'd
* @param TraceFlags - bitfield to control tracing options
* @return TRUE if nothing hit
*/
static UBOOL StaticObstacleLineCheck( const UObject* const InOuter,
FCheckResult& Hit,
FVector Start,
FVector End,
FVector Extent,
UBOOL bIgnoreNormalMesh=FALSE,
FNavMeshPolyBase** out_HitPoly=NULL,
const TArray<APylon*>* PylonsToCheck=NULL,
DWORD TraceFlags=0);
/**
* static function that will do a point check agains the obstacle mesh
* @param Hit - hitresult struct for point check
* @param Pt - centroid of extent box to point check
* @param Extent - extent of box to point check
* @param out_HitPoly - optional output param stuffed with the poly we collided with (if any)
* @param PylonsToCheck - OPTIONAL, if present only these pylons' meshes will be linecheck'd
* @param bSkipPointInMeshCheck - OPTIONAL, if TRUE ONLY a pointcheck against the obstacle mesh will be done, no verification that the point is on the mesh somewhere will be done (be careful with this one!)
* @return TRUE if nothing hit
*/
static UBOOL StaticObstaclePointCheck(FCheckResult& Hit,FVector Pt,FVector Extent, FNavMeshPolyBase** out_HitPoly=NULL, const TArray<APylon*>* PylonsToCheck=NULL, UBOOL bSkipPointInMeshCheck=FALSE, DWORD TraceFlags=0);
/**
* static function that will do a line check against any pylon's (walkable) meshes colliding with the line passed
* @param Hit - Hitresult struct for line check
* @param Start - start of line check
* @param End - end of line check
* @param Extent - extent of box to sweep
* @param out_HitPoly - OPTIONAL, output param for hit poly
* @param PylonsToCheck - OPTIONAL, if present only these pylons' meshes will be linecheck'd
* @param TraceFlags - bitfield to control tracing options
* @return TRUE if nothing hit
*/
static UBOOL StaticLineCheck(FCheckResult& Hit, FVector Start,FVector End,FVector Extent, FNavMeshPolyBase** out_HitPoly=NULL, const TArray<APylon*>* PylonsToCheck=NULL, DWORD TraceFlags=0);
/**
* static function that will do a point check agains the walkable
* @param Hit - hitresult struct for point check
* @param Pt - centroid of extent box to point check
* @param Extent - extent of box to point check
* @param out_HitPoly - OPTIONAL, poly the pointcheck hit
* @param PylonsToCheck - OPTIONAL, if present only these pylons' meshes will be linecheck'd
* @return TRUE of nothing hit
*/
static UBOOL StaticPointCheck(FCheckResult& Hit,FVector Pt,FVector Extent, FNavMeshPolyBase** out_HitPoly=NULL, const TArray<APylon*>* PylonsToCheck=NULL, DWORD TraceFlags=0);
static APylon* StaticGetPylonFromPos( FVector Position );
UBOOL PathCache_Empty( FPathStore* PCache );
UBOOL PathCache_AddEdge( FNavMeshEdgeBase* Edge, FPathStore* PCache = NULL );
UBOOL PathCache_InsertEdge( FNavMeshEdgeBase* Edge, int Idx=0, FPathStore* PCache = NULL );
UBOOL PathCache_RemoveEdge( FNavMeshEdgeBase* Edge, FPathStore* PCache = NULL );
UBOOL PathCache_RemoveIndex( int InIdx, int Count, FPathStore* PCache );
FVector PathCache_GetGoalPoint( FPathStore* PCache );
// Pathing functions
/**
* internal function which does the heavy lifting for A* searches (typically called from FindPath()
* @param out_DestActor - output param goal evals can set if a particular actor was the result of the search
* @param out_DestItem - output param goal evans can set if they need an index into something (e.g. cover slot)
* @return - TRUE If search found a goal
*/
virtual UBOOL GeneratePath( class AActor** out_DestActor, INT* out_DestItem );
/**
* Adds successor edges from the given poly to the A* search
* @param CurPoly - poly to add sucessor edges for
* @param PathParams - path params being used to search currently
* @param PredecessorEdge - edge we got to this poly from
* @param PathSessionID - SessionID for this pathfind
* @param OpenList - first edge on the open list
*/
void AddSuccessorEdgesForPoly(FNavMeshPolyBase* CurPoly,
const FNavMeshPathParams& PathParams,
FNavMeshEdgeBase* PredecessorEdge,
INT PathSessionID,
PathOpenList& OpenList,
INT OverrideVisitedCost=-1,
INT OverrideHeuristicCost=-1);
/**
* finds the best node in the list, and pulls it out and returns it
* (assumes list is sorted)
* @param OpenList - list to find best node from
* @return the best node in the list
*/
PathCardinalType PopBestNode( PathOpenList& OpenList );
/**
* InsertSorted
* inserts the passed node into the passed list at the proper spot to maintain sort order
* @param NodeForInsertion - node to insert into the list
* @param OpenList - list ot insert into
* @return TRUE if succesful
*/
UBOOL InsertSorted( PathCardinalType NodeForInsertion, PathOpenList& OpenList );
UBOOL AddNodeToOpen( PathOpenList& OpenList,
PathCardinalType NodeToAdd,
INT EdgeCost,
INT HeuristicCost,
PathCardinalType Predecessor,
const FVector& PrevPos,
FNavMeshPolyBase* DestinationPolyForEdge);
void RemoveNodeFromOpen( PathCardinalType NodeToRemove, PathOpenList& OpenList );
/**
* will loop through all constraints in the constraint list and let them have their say on the current cost of the edge being considered
* @param Edge - the edge being considered
* @param SrcPoly - the poly we're coming from
* @param DestPoly - the poly we're going to!
* @param EdgeCost - output param with current edge cost, and should be updated cost after this function is called
* @param HeuristicCost - output param with current heuristiccost, and should be updated heuristic cost (h) after this function is called
* @param EdgePoint - the point on the edge being used for cost calculations ( a good place to do heuristic weighting )
* @return TRUE if this edge is fit at all, FALSE if it should be skipped
*/
UBOOL ApplyConstraints( FNavMeshEdgeBase* Edge, FNavMeshEdgeBase* PredecessorEdge, FNavMeshPolyBase* SrcPoly, FNavMeshPolyBase* DestPoly, INT& EdgeCost, INT& HeuristicCost, const FVector& EdgePoint );
/**
* EvaluateGoal handles composition of goal evaluators, and will loop through the goaleval list
* calling EvaluateGoal on each one to determine if the possibleGoal is the node we're looking for
* @param PossibleGoal - the goal to be evaluated!
* @param out_GeneratedGoal - the poly that we have chosen as our successful goal (if any)
* @NOTE: this will be NULL'd if the collective goals say no to PossibleGOal
* @return TRUE if PossibleGoal is a valid node to stop on (search stops once this happens)
*/
UBOOL EvaluateGoal( PathCardinalType PossibleGoal, PathCardinalType& out_GeneratedGoal );
void ClearCrossLevelRefs(ULevel* Level);
/**
* will clear all references to any navmeshes
*/
void ClearAllMeshRefs();
/**
* PostEdgeCleanup
* this function is called after an edge has been cleaned up, but before it has been deleted. Whatever triggerd
* the edge deletion is finished, so it's safe to call other code that might affect the mesh
* @param Edge - the edge that is being cleaned up
*/
void PostEdgeCleanup(FNavMeshEdgeBase* Edge);
// UObject Interface - overidden to clear pathcache on destruction
virtual void BeginDestroy();
/**
* will operate on the pathcache to generate a set of points to run through.. this is based on the edges in the path
* and a 'stringpull' method applied to the edges to find the best route through the edges
* @param Interface - the interface of the entity we're computing for
* @param PathIdx - the index of the edge we are computing
* @param out_EdgePos - the output of the computation
* @param ArrivalDist - the radius around points which the entity will consider itself arrived (used to offset points to make sure the bot moves far enough forward)
* @param bConstrainedToCurrentEdge - skip compensating if the edge requires special movement, rely solely upon GetEdgeDestination()
* @param out_EdgePoints - optional pointer to an array to fill with all the computed edge movement points
*/
void ComputeOptimalEdgePosition(INT PathIdx, FVector& out_EdgePos, FLOAT ArrivalDistance, UBOOL bConstrainedToCurrentEdge = FALSE, TArray<FVector>* out_EdgePoints=NULL);
/**
* This function will generate a move point which will get the bot into the next polygon
* by compensating for early-arrival if needed
* @param PathIdx - the index of the pathedge position we're trying to resolve (usually 0)
* @param out_movePosition - the position we determined to be best to move to (should be set with the current desired location to move to)
* @param NextMovePoitn - the next move point in the path
* @param HandleExtent - the extent of the handle we're resolving for
* @param CurHandlePos - the current world position of the handle we're resolving for
* @param ArrivalDistance - how close to a point we have ot be before moveto() will return
*/
void CompensateForEarlyArrivals(INT PathIdx, FVector& out_MovePosition, const FVector& NextMovePoint, const FVector& CurHandlePos, FLOAT ArrivalDistance);
/**
* This function is called from GetNextMoveLocation when it is detected that the entity is not within its path
* and it tries to recover from this happening
* @param Interface - the handle interface that's walking this path
* @param SearchStart - the location of the entity searching (saves on interface vf calls)
* @param Extent - extent of the entity searching (saves on interface vf calls)
* @param ArrivalDistance - how clsoe to a point we have to get before moveto() will return
* @param out_Dest - out_param dictating what our destination should be
* @return - whether we were succesful in finding a valid point to move to
*/
UBOOL HandleNotOnPath(FLOAT ArrivalDistance, FVector& out_Dest );
/**
* This function is called to give the Handle a chance to handled the adjustment instead of the controller fallback.
* @param HitNoraml - Normal of the wall at point of collision
* @param HitActor - Actor that we hit
* @return - TRUE if we handled the adjustment, FALSE means allow Outer (usually the AIController)
*/
UBOOL HandleWallAdjust( FVector HitNormal, AActor* HitActor );
/**
* This function is called after an adjust to the wall is complete (usually from execPollMoveTo/ward)
* @return - TRUE if we handled the adjustment and no other move should occur, FALSE means allow regular movement to continue
*/
UBOOL HandleFinishedAdjustMove();
/**
* This function is called by APawn::ReachedDestination and is used to coordinate when to stop moving to a point during
* path following (e.g. once we are inside the next poly, stop moving rather than trying to hit an exact point)
* @param Destination - destination we're trying to move to
* @param out_bReached - whether or not we have reached this destination
* @param HandleOuterActor - the actor which implements the navhandle interface for this test
* @param ArrivalTreshold - the radius within which code elsewhere is going to be doing arrival checks, so we can match in this function without breaking parity
* @return - returns TRUE If this function was able to determien if we've arrived (FALSE means keep checking elsewhere)
*/
UBOOL ReachedDestination(const FVector& Destination, AActor* HandleOuterActor, FLOAT ArrivalThreshold, UBOOL& out_bReached);
// don't let navmeshes whose edges we are reffing be deleted before we are
void AddReferencedObjects( TArray<UObject*>& ObjectArray );
void Serialize( FArchive& Ar );
/**
* do an octree check and return all pylons whose bounds overlap the passed center/extent
* @param Ctr - center of box to check for overlap
* @param Extent - extent of box to check for overlap
* @param out_OverlappingPylons - out param stuffed with pylons
*/
static void GetAllOverlappingPylonsFromBox(const FVector& Ctr, const FVector& Extent, TArray<APylon*>& out_OverlappingPylons);
/**
* called from PointReachable, and is recursive to split the cast into several that conform to the mesh
* @param InOuter - The Outer which owns this NavHandle. Can be used for debugging
* @param Hit - Hitresult struct for line check
* @param Start - start of line check
* @param End - end of line check
* @param Extent - extent of box to sweep
* @param bIgnoreNormalMesh - OPTIONAL - default:FALSE - when TRUE no checks against the walkable mesh will be performed
* @param out_HitPoly - optional output param stuffed with the poly we collided with (if any)
* @param bComparePolyNormalZs - optional bool dictating whether this function should return a collision when any two polys found along
* the way have very different Normal.Z values
* @param TraceFlags - bitfield to control tracing options
* @return TRUE of nothing hit
*/
static UBOOL PointReachableLineCheck( const UObject* const InOuter,
FCheckResult& Hit,
FVector Start,
FVector End,
FVector Extent,
UBOOL bIgnoreNormalMesh=FALSE,
FNavMeshPolyBase** out_HitPoly=NULL,
UBOOL bComparePolyNormalZs=FALSE,
DWORD TraceFlags=0,
UINT StackDepth=0);
/**
* called when a path is searched for and not found
* sets the lastpatherror and saves off the time of the failure
* @param ErrorType - the type of path error that just occurred
*/
void SetPathError(EPathFindingError ErrorType);
struct FFitNessFuncParams
{
FFitNessFuncParams( UNavigationHandle* InAskingHandle,
const FVector& InStartPt,
const FVector& InExtent,
const FVector& InPoint,
FNavMeshPolyBase* InPolyContainingPoint,
const TArray<APylon*>* InPylonsWeCareAbout)
:
AskingHandle(InAskingHandle),
StartPt(InStartPt),
Extent(InExtent),
Point(InPoint),
PolyContainingPoint(InPolyContainingPoint),
PylonsWeCareAbout(InPylonsWeCareAbout){}
UNavigationHandle* AskingHandle;
FVector StartPt;
FVector Extent;
FVector Point;
FNavMeshPolyBase* PolyContainingPoint;
const TArray<APylon*>* PylonsWeCareAbout;
};
// typedef for getvalidpositionsforbox acceptability function pointer
typedef UBOOL (*ValidBoxPositionFunc)(const FFitNessFuncParams& Params);
/**
* will return a list of valid spots on the mesh which fit the passed extent and are within radius to Pos
* @param Pos - Center of bounds to check for polys
* @param Radius - radius from Pos to find valid positions within
* @param Extent - Extent of entity we're finding a spot for
* @param bMustBeReachableFromStartPos - if TRUE, only positions which are directly reachable from the starting position will be returned
* @param ValidPositions - out var of valid positions for the passed entity size
* @param MaxPositions - the maximum positions needed (e.g. the search for valid positions will stop after this many have been found)
* @param MinRadius - minimum distance from center position to potential spots (default 0)
* @param ValidBoxAroundStartPos - when bMustBeReachableFromStartPos is TRUE, all hits that are within this AABB of the start pos will be considered valid
* @param ValidBoxPositionFunc - function pointer which can be supplied to filter out potential points from the result list
*/
void GetValidPositionsForBoxEx(FVector pos,
FLOAT Radius,
FVector Extent,
UBOOL bMustBeReachableFromStartPos,
TArray<FVector>& out_ValidPositions,
INT MaxPositions=-1,
FLOAT MinRadius=0,
FVector ValidBoxAroundStartPos=FVector(0.000000,0.000000,0.000000),
ValidBoxPositionFunc FitnessFunction=NULL);
// macros to support debuglog, should call these instead of debuglog directly so that it gets compiled out in release builds
#if !DO_AI_LOGGING
#define NAVHANDLE_DEBUG_LOG(TXT){}
#else
#define NAVHANDLE_DEBUG_LOG(TXT){\
if(RUNTIME_DO_AI_LOGGING)\
{\
IInterface_NavigationHandle* Interface = InterfaceCast<IInterface_NavigationHandle>(GetOuter());\
if(Interface != NULL)\
{\
Interface->DebugLogInternal(TXT);\
}\
}\
}
#endif
};
/**
* sets the pathcache to a copy of the passed path store
* @param PathStore - path store to copy over pathcache
*/
native function CopyPathStoreToPathCache(const out PathStore InStore);
/**
* checks if we've moved far enough, and if so updates the breadcrumb trail
* @param Location - current location
*/
native function UpdateBreadCrumbs(vector InLocation);
/**
* will return the most recent breadcrumb, and pop it off the list
*/
native function bool GetNextBreadCrumb(out vector out_BreadCrumbLoc);
/**
* Path constraint operations
* Allows the user to push a list of constraints which affect pathing heuristics, as well as determine when the path traversal is finished
*/
native function ClearConstraints();
native function AddPathConstraint( NavMeshPathConstraint Constraint );
native function AddGoalEvaluator( NavMeshPathGoalEvaluator Evaluator );
/**
* returns whether or not pylon A has any path to Pylon B (useful for high level early outs)
*/
native function Pylon BuildFromPylonAToPylonB(Pylon A, Pylon B);
/**
* returns whether or not pylon A has any path to Pylon B (useful for high level early outs)
*/
native function bool DoesPylonAHaveAPathToPylonB(Pylon A, Pylon B);
/**
* Path shaping creation functions...
* these functions by default will just new the class, but this offers a handy
* interface to override for to do things like pool the constraints
*/
function NavMeshPathConstraint CreatePathConstraint( class<NavMeshPathConstraint> ConstraintClass )
{
return WorldInfo.GetNavMeshPathConstraintFromCache(ConstraintClass,self);
}
function NavMeshPathGoalEvaluator CreatePathGoalEvaluator( class<NavMeshPathGoalEvaluator> GoalEvalClass )
{
return WorldInfo.GetNavMeshPathGoalEvaluatorFromCache(GoalEvalClass,self);
}
function int GetPathCacheLength()
{
return PathCache.EdgeList.Length;
}
/** Path Cache Operations
* Allows operations on nodes in the route while modifying route (ie before emptying the cache)
* Should override in subclasses as needed
*/
native function bool PathCache_Empty();
/**
* After FindPath has been called this will return the location in the world that the pathfind found based on the NavMeshGoals
* the FindPath used.
**/
native function vector PathCache_GetGoalPoint();
native function bool PathCache_RemoveIndex(int InIdx, int Count = 1);
/**
* This will return the best "unfinished path". We need this for things where we are using the navmesh to find locations which
* are not connected (pathable) to the originating NavHandle but are still valid world positions.
**/
native function vector GetBestUnfinishedPathPoint() const;
// finds the the pylon the AI attached to this handle is within
native function bool FindPylon();
// finds the pylon (if any) assoicated with the position passed
native static function Pylon GetPylonFromPos( vector Position );
/**
* will return the actual point that we should move to right now to walk along our path
* this will usually be a point along our current edge, but sometimes will
* be something else in special situations (e.g. right on top of the edge)
* @param out_MoveDest - output movement destination we have determined
* @param ArrivalDistance - this tells getnextmovelocation how close to a point we have to be before MoveTo() returns
* necessary so we can compesnate for early arrivals in some situations
*/
native function bool GetNextMoveLocation( out Vector out_MoveDest, float ArrivalDistance );
/**
* lets the navigation handle know what the ultimate goal of the current move is
* @param FinalDest - the destination desired
* @return - whether or not the final destination is reachable
*/
native function bool SetFinalDestination(Vector FinalDest);
/**
* ComputeValidFinalDestination
* will find a valid, pathable point near the passed desired destination
*/
native function bool ComputeValidFinalDestination(out vector out_ComputedPosition);
/**
* this will set up a path search, and ultimately call GeneratePath to do the A* path search
* Note: it's up to your constraints to determine what it is you're doing.. if you're trying to
* path to a particular point you probably want to add a NavmeshGoal_At goal evaluator
* and supply it with the position you're pathing toward so the goal evaluator can stop the path search
* once the destination is found. You also need a path constraint to provide a heuristic for the search,
* which typically is going to consist of at least a NavMeshPath_Toward which will weight based on
* euclidian distance to the goal.
* @param out_DestActor - output variable which goal evaluators can use to supply the 'found' actor at path finish
* @param out_DestItem - output variable which goal evaluators can use to supply extra data to path search clients
* @return - whether the path search was successful or not
*/
native function bool FindPath( optional out Actor out_DestActor, optional out int out_DestItem );
/**
* this will notify our curretn edge we're about to traverse it, and allow that edge to perform custom actions for traversal
* @param MovePt - the point we're about to move to
* @param C - controller we're suggesting move prep for
* @return TRUE if the edge is handling getting the bot to the proper position for the move, FALSE if
* calling code is responsible for getting th bot to movept
*/
native function bool SuggestMovePreparation( out Vector MovePt, Controller C );
/**
* does a line check against the obstacle mesh
* @param Start - start of the line segment to check
* @param End - end position of the line segment to check
* @param Extent - extent of box to be swept along line segment
* @param out_HitLoc - hit location of obstacle line check (if any)
* @param out_hitNorm - hit normal of surface we hit during obstacle line check (if any)
* @return - TRUE if nothing was hit (note: only collides against the obstacle mesh, not the normal mesh)
*/
static native final function bool ObstacleLineCheck( vector Start, vector End, vector Extent, optional out vector out_HitLoc, optional out vector out_HitNorm );
/**
* Does a point check against the obstacle mesh
* @param Pt - centroid of box to check aginast obstacle mesh
* @param Extent - Extent of box to check against obstacl mesh
* @return - TRUE if didn't hit anything
*/
static native final function bool ObstaclePointCheck(vector Pt, vector Extent);
/**
* does a line check against the Walkable mesh
* @param Start - start of the line segment to check
* @param End - end position of the line segment to check
* @param Extent - extent of box to be swept along line segment
* @return - TRUE if nothing was hit
*/
native function bool LineCheck( vector Start, vector End, vector Extent, optional out vector out_HitLocation, optional out vector out_HitNormal );
/**
* Does a point check against the Walkable mesh
* @param Pt - centroid of box to check against obstacle mesh
* @param Extent - Extent of box to check against obstacle mesh
* @return - TRUE if didn't hit anything
*/
native function bool PointCheck( vector Pt, vector Extent );
/**
* returns TRUE if Point/Actor is directly reachable
* @param Point - point we want to test to
* @param OverrideStartPoint (optional) - optional override for starting position of AI (default uses bot location)
* @param bAllowHitsInEndCollisionBox (optional) - optional.. (defaults to ON) if this is true and a hit is detected that falls within the collision cylinder of the entity, let the hit pass
* @return TRUE if the point is reachable
*/
native function bool PointReachable( Vector Point, optional Vector OverrideStartPoint, optional bool bAllowHitsInEndCollisionBox=true);
native function bool ActorReachable( Actor A );
// debug function for drawing cache polys
native function DrawPathCache(optional Vector DrawOffset, optional bool bPersistent, optional color DrawColor);
// debug function which prints out info about the current path cache
native function PrintPathCacheDebugText();
/**
* for debugging.. will return descriptive text about the current edge
*/
native function string GetCurrentEdgeDebugText();
/**
* NULLs the currentedge reference
*/
native function ClearCurrentEdge();
/**
* @returns the edge type for the current edge (if any)
*/
native function ENavMeshEdgeType GetCurrentEdgeType();
/**
* returns the center points of all polys within the specefied area
* @param Pos - Center of bounds to check for polys
* @param Extent - Extent of area to return
* @param out_PolyCtrs - out var of poly centers within the specefied area
*/
native static function GetAllPolyCentersWithinBounds(Vector Pos, Vector Extent, out Array<Vector> out_PolyCtrs);
/**
* will return a list of valid spots on the mesh which fit the passed extent and are within radius to Pos
* @param Pos - Center of bounds to check for polys
* @param Radius - radius from Pos to find valid positions within
* @param Extent - Extent of entity we're finding a spot for
* @param bMustBeReachableFromStartPos - if TRUE, only positions which are directly reachable from the starting position will be returned
* @param ValidPositions - out var of valid positions for the passed entity size
* @param MaxPositions - the maximum positions needed (e.g. the search for valid positions will stop after this many have been found)
* @param MinRadius - minimum distance from center position to potential spots (default 0)
* @param ValidBoxAroundStartPos - when bMustBeReachableFromStartPos is TRUE, all hits that are within this AABB of the start pos will be considered valid
*/
native static function GetValidPositionsForBox(Vector Pos, float Radius, Vector Extent, bool bMustBeReachableFromStartPos, out Array<Vector> out_ValidPositions, optional int MaxPositions=-1, optional float MinRadius, optional vector ValidBoxAroundStartPos=vect(0,0,0));
/**
* will clip off edges from the pathcache which are greater than the specified distance from the start of the path
* @param MaxDist - the maximum distance for the path
*/
native function LimitPathCacheDistance(float MaxDist);
/**
* this function will determine if the poly this entity is currently in is inescapable by that entity
* @return TRUE If the poly this handle is in isn't escapable
*/
native function bool IsAnchorInescapable();
/**
* this will a good point on the first edge in the pathcache (or the finaldest if there is no pathcache)
*/
native function vector GetFirstMoveLocation();
/**
* this will calculate the optimal edge positions along the pathcache, and add up the distances
* to generate an accurate distance that will be travelled along the current path
* Note: includes distance to final destination
* @param FinalDest - optional finaldest override (if not passed will use NavigationHandle.FinalDestination)
* @return - the path distance calculated
*/
native function float CalculatePathDistance(optional Vector FinalDest);
/**
* Copies over move points into the passed vector array
* @param FinalDest -
* @param out_MovePoints - array to be stuffed with move points
*/
native function CopyMovePointsFromPathCache(Vector FinalDest, out array<vector> out_MovePoints);
/**
* this will take the given position and attempt to move it the passed height above the poly that point is in (along a cardinal axis)
* @param Point - point to adjust
* @param Height - height above mesh you would like
* @return Adjusted point
*/
static native function Vector MoveToDesiredHeightAboveMesh(vector Point, float Height);
/**
* This will attempt to grab an interface_navigationhandle from outer, and have that interface populate
* our cached pathing params.
* @return TRUE if cache population was succesful
*/
native final function bool PopulatePathfindingParamCache();
/**
* Gather all cover slot info within radius of the given point
* @param FromLoc - location at center of sphere to check
* @param Radius - radius of sphere within which to gather cover
* @param out_CoverList - out array filled with cover infos within radius
* @return TRUE if found any cover
*/
static native final function bool GetAllCoverSlotsInRadius( Vector FromLoc, FLOAT Radius, out array<CoverInfo> out_CoverList );
/**
* will get a point nearby which is in a poly that has edges outbound that support this AI
* @param out_NewAnchorLoc - out param stuffed with the position we found
* @param OverrideStartLoc - optional param to override the starting location for this query (if none is given this AI's searchstart will be used)
* @return - TRUE if we found a spot
*/
native final function bool GetValidatedAnchorPosition(out vector out_NewAnchorLoc, optional vector OverrideStartLoc );
/**
* will get a point nearby which is in a poly that has edges outbound that support this AI
* @param out_NewAnchorLoc - out param stuffed with the position we found
* @param StartCheckBaseLocation - location to start looking (to find poitns near)
* @param Extent - extent of the AI we're trying to find a spot for
* @return - TRUE if we found a spot
*/
static native final function bool StaticGetValidatedAnchorPosition(out vector out_NewAnchorLoc, Vector StartCheckBaseLocation, Vector Extent );
function DrawBreadCrumbs(bool bPersistent=false)
{
`if(`notdefined(FINAL_RELEASE))
local int i,count;
local vector lastPt,curPt;
if( bDebug_Breadcrumbs )
{
if( bPersistent) FlushPersistentDebugLines();
for(i=BreadCrumbMostRecentIdx;count < NumBreadCrumbs; ++count)
{
curPt = Breadcrumbs[i];
if( curPt == vect(0,0,0) )
{
break;
}
if( lastPt != vect(0,0,0) && count < NumBreadCrumbs-1)
{
DrawDebugLine(curPt,LastPt,0,255,0,bPersistent);
}
DrawDebugBox(curPt,vect(5,5,5),0,0,255,bPersistent);
--i;
if( i<0 )
{
i=NumBreadCrumbs-1;
}
lastPt=CurPt;
}
}
`endif
}
defaultproperties
{
bDebugConstraintsAndGoalEvals=FALSE
BreadCrumbDistanceInterval=75
bDebug_Breadcrumbs=false
}