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

592 lines
21 KiB
Ucode

//=============================================================================
// NavigationPoint.
//
// NavigationPoints are organized into a network to provide AIControllers
// the capability of determining paths to arbitrary destinations in a level
//
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
//=============================================================================
class NavigationPoint extends Actor
hidecategories(Lighting,LightColor,Force)
dependson(ReachSpec)
ClassGroup(Navigation)
native;
const INFINITE_PATH_COST = 10000000;
//------------------------------------------------------------------------------
// NavigationPoint variables
var transient bool bEndPoint; // used by C++ navigation code
var transient bool bTransientEndPoint; // set right before a path finding attempt, cleared afterward.
var transient bool bHideEditorPaths; // don't show paths to this node in the editor
var transient bool bCanReach; // used during paths review in editor
/** structure for inserting things into the navigation octree */
struct native NavigationOctreeObject
{
/** the bounding box to use */
var Box BoundingBox;
/** cached center of that box */
var vector BoxCenter;
/** if this object is in the octree, pointer to the node it's in, otherwise NULL */
var native transient const pointer OctreeNode{class FNavigationOctreeNode};
/** UObject that owns the entry in the octree */
var noexport const Object Owner;
/** bitfield representing common classes of Owner so we can avoid casts */
var noexport const byte OwnerType;
structcpptext
{
enum ENavOctreeObjectType
{
NAV_NavigationPoint = 0x01,
NAV_ReachSpec = 0x02,
};
private:
UObject* Owner;
BYTE OwnerType;
public:
/** constructor, makes sure OctreeNode is NULL */
FNavigationOctreeObject()
: OctreeNode(NULL), Owner(NULL), OwnerType(0)
{}
/** destructor, removes us from the octree if we're still there */
~FNavigationOctreeObject();
/** sets the object's owner and initializes the OwnerType for fast cast to common types */
void SetOwner(UObject* InOwner);
/** sets the object's bounding box
* if the object is currently in the octree, re-adds it
* @param InBoundingBox the new bounding box to use
*/
void SetBox(const FBox& InBoundingBox);
/** overlap check function called after the axis aligned bounding box check succeeds
* allows for more precise checks for certain object types
* @param TestBox the box to check
* @return true if the box doesn't overlap this object, false if it does
*/
UBOOL OverlapCheck(const FBox& TestBox);
/** templated accessor to Owner, to avoid casting for common cases
* @note T must be UObject or a subclass, or this function will not compile
*/
template<class T> FORCEINLINE T* GetOwner()
{
return Cast<T>(Owner);
}
//@note the specializations for this template are in UnPath.h because they must be outside the struct definition
void Serialize(FArchive& Ar);
}
};
var native transient const NavigationOctreeObject NavOctreeObject;
var() bool bBlocked; // this node is currently unuseable
var() bool bOneWayPath; // reachspecs from this path only in the direction the path is facing (180 degrees)
var bool bNeverUseStrafing; // shouldn't use bAdvancedTactics going to this point
var bool bAlwaysUseStrafing; // shouldn't use bAdvancedTactics going to this point
var const bool bForceNoStrafing;// override any LD changes to bNeverUseStrafing
var const bool bAutoBuilt; // placed during execution of "PATHS BUILD"
var bool bSpecialMove; // if true, pawn will call SuggestMovePreparation() when moving toward this node
`if(`__TW_PATHFINDING_)
var() bool bAllowPathConnections;
var() editconst bool bWallNode;
/** Brightness of light(s) affecting this navigation point (calculated when building paths) */
var() editconst float Luminance;
var LinearColor Intensity;
var() bool bNoAutoConnect; // don't connect this path to others except with special conditions (used by LiftCenter, for example)
/** Tag identifier that can be used when debugging AI. For example, the 'AIPathTo <DebugTag>' will force a debug NPC to path to the NavigatioNPoint with a matching DebugTag */
var(KFPathnode) duplicatetransient name DebugTag;
/** Notification will be sent to pawn when/if this node is added to its RouteCache, to allow early special handling */
var(KFPathnode) duplicatetransient bool bNotifyOnAddToRouteCache;
`else
var bool bNoAutoConnect; // don't connect this path to others except with special conditions (used by LiftCenter, for example)
`endif
var const bool bNotBased; // used by path builder - if true, no error reported if node doesn't have a valid base
var const bool bPathsChanged; // used for incremental path rebuilding in the editor
var() bool bDestinationOnly; // used by path building - means no automatically generated paths are sourced from this node
var bool bSourceOnly; // used by path building - means this node is not the destination of any automatically generated path
var bool bSpecialForced; // paths that are forced should call the SpecialCost() and SuggestMovePreparation() functions
var bool bMustBeReachable; // used for PathReview code
var bool bBlockable; // true if path can become blocked (used by pruning during path building)
var bool bFlyingPreferred; // preferred by flying creatures
var bool bMayCausePain; // set in C++ if in PhysicsVolume that may cause pain
var transient bool bAlreadyVisited; // internal use
var() bool bVehicleDestination; // if true, forced paths to this node will have max width to accomodate vehicles
var() bool bMakeSourceOnly;
var bool bMustTouchToReach; // if true. reach tests are based on whether pawn can move to overlap this NavigationPoint (only valid if bCollideActors=true)
/** whether walking on (being based on) this NavigationPoint counts as reaching it */
var bool bCanWalkOnToReach;
/** if true, attempt to build long range (> MAXPATHDIST) paths to/from this node */
var bool bBuildLongPaths;
/** indicates vehicles cannot use this node */
var(VehicleUsage) bool bBlockedForVehicles;
/** vehicles with bUsePreferredVehiclePaths set (large vehicles, usually) will prioritize using these nodes */
var(VehicleUsage) bool bPreferredVehiclePath;
var() editinline const editconst duplicatetransient array<ReachSpec> PathList; //index of reachspecs (used by C++ Navigation code)
/** List of navigation points to prevent paths being built to */
var() editoronly duplicatetransient array<ActorReference> EditorProscribedPaths;
/** List of navigation points to force paths to be built to */
var() editoronly duplicatetransient array<ActorReference> EditorForcedPaths;
/** List of volumes containing this navigation point relevant for gameplay */
var() const editconst array<ActorReference> Volumes;
var int visitedWeight;
var const int bestPathWeight;
var const private NavigationPoint nextNavigationPoint;
var const NavigationPoint nextOrdered; // for internal use during route searches
var const NavigationPoint prevOrdered; // for internal use during route searches
var const NavigationPoint previousPath;
var int Cost; // added cost to visit this pathnode
var() int ExtraCost; // Extra weight added by level designer
var transient int TransientCost; // added right before a path finding attempt, cleared afterward.
var transient int FearCost; // extra weight diminishing over time (used for example, to mark path where bot died)
/** Mapping of Cost/Description for costs of this node */
struct native DebugNavCost
{
var string Desc;
var int Cost;
structcpptext
{
/** constructors */
FDebugNavCost() {}
FDebugNavCost(EEventParm)
{
appMemzero(this, sizeof(FDebugNavCost));
}
UBOOL operator==(const FDebugNavCost& Other)
{
return (Other.Cost == Cost && Other.Desc == Desc);
}
}
};
var transient array<DebugNavCost> CostArray;
var DroppedPickup InventoryCache; // used to point to dropped weapons
var float InventoryDist;
var const float LastDetourWeight;
var CylinderComponent CylinderComponent;
/** path size of the largest ReachSpec in this node's PathList */
var() editconst const Cylinder MaxPathSize;
/** GUID used for linking paths across levels */
var() editconst const duplicatetransient guid NavGuid;
/** Normal editor sprite */
var const transient SpriteComponent GoodSprite;
/** Used to draw bad collision intersection in editor */
var const transient SpriteComponent BadSprite;
/** Does this nav point point to others in separate levels? */
var const bool bHasCrossLevelPaths;
/** Which navigation network does this navigation point connect to? */
var() editconst const int NetworkID;
/** Pawn that is currently anchor to this navigation point */
var transient Pawn AnchoredPawn;
/** Last time a pawn was anchored to this navigation point - set when Pawn chooses a new anchor */
var transient float LastAnchoredPawnTime;
/** whether we need to save this in checkpoints because it has been modified by Kismet */
var transient bool bShouldSaveForCheckpoint;
struct CheckpointRecord
{
var bool bDisabled;
var bool bBlocked;
};
`if(`__TW_PATHFINDING_)
var(KFPathNode) bool bConnectToSameFloorOnly;
/** When true, this NavigationPoint will not allow other NavigationPoints to connect to it, and it will not
allow itself to connect to other NavigationPoints - unless it is a forced path connection. */
var() bool bNoAutoConnectBiDirectional;
/** Flagged during pathbuilding for navigation points with no reachspecs. */
var() editconst bool bBadPlacement;
/** Flagged during pathbuilding for nodes that are considered unnecessary. */
var() editconst bool bUnnecessaryNavPoint;
`endif
cpptext
{
virtual UClass* GetReachSpecClass( ANavigationPoint* Nav, UClass* DefaultReachSpecClass ) { return DefaultReachSpecClass; }
virtual void ClearPaths();
virtual void FindBase();
virtual void PostScriptDestroyed();
protected:
virtual void UpdateComponentsInternal(UBOOL bCollisionUpdate = FALSE);
public:
void PostEditMove(UBOOL bFinished);
void Spawned();
void UpdateMaxPathSize();
UBOOL FindAlternatePath(UReachSpec* StraightPath, INT AccumulatedDistance);
virtual UBOOL ShouldBeBased();
/** Checks to make sure the navigation is at a valid point */
virtual void Validate();
virtual void TogglePathRendering(UBOOL bShouldDrawPaths);
#if WITH_EDITOR
virtual void CheckForErrors();
/**
* Sets the network ID for this nav and all connected navs.
*/
virtual void SetNetworkID(INT InNetworkID);
static void BuildNetworkIDs();
virtual void ReviewPath(APawn* Scout);
virtual UBOOL CheckSatisfactoryConnection(ANavigationPoint* Other);
void CleanUpPruned();
INT PrunePaths();
// more aggressive (and expensive) path pruning routine ( should only be called from editor )
INT AggressivePrunePaths();
INT SecondPassAggressivePrunePaths();
virtual UBOOL CanPrunePath(INT index) { return TRUE; }
virtual void AddForcedSpecs( AScout *Scout );
#if __TW_PATHFINDING_
virtual UReachSpec* ManualForcePathTo( ANavigationPoint *Nav, AScout *Scout = NULL, UClass* ReachSpecClass = NULL, UBOOL bJump = FALSE );
#endif
virtual UReachSpec* ForcePathTo(ANavigationPoint *Nav, AScout *Scout = NULL, UClass* ReachSpecClass = NULL );
virtual UBOOL ProscribePathTo(ANavigationPoint *Nav, AScout *Scout = NULL);
/** builds long range paths (> MAXPATHDIST) between this node and all other reachable nodes
* for which a straight path would be significantly shorter or the only way to reach that node
* done in a separate pass at the end because it's expensive and so we want to early out in the maximum number
* of cases (e.g. if suitable short range paths already get there)
*/
void AddLongPaths(AScout* Scout, UBOOL bOnlyChanged);
virtual void addReachSpecs(class AScout *Scout, UBOOL bOnlyChanged=0);
virtual INT AddMyMarker(AActor *S);
/** returns whether a ReachSpec can be built from this node to Nav
* @param Nav the NavigationPoint to check if we can build a path to
* @param bCheckDistance whether or not we should check if Nav is close enough (MAXPATHDIST)
* @return true if a ReachSpec can be built from this node to Nav, false otherwise
*/
virtual UBOOL CanConnectTo(ANavigationPoint* Nav, UBOOL bCheckDistance);
virtual void OnAddToPrefab();
#if __TW_PATHFINDING_
virtual UBOOL PreserveForcedPath( ANavigationPoint* DestNav );
virtual UBOOL IsNecessaryForPath()
{
return FALSE;
}
#endif //__TW_PATHFINDING_
#endif //WITH_EDITOR
virtual void InitForPathFinding() {};
virtual void ClearForPathFinding();
UBOOL CanReach(ANavigationPoint *Dest, FLOAT Dist, UBOOL bUseFlag, UBOOL bAllowFlying);
virtual class APickupFactory* GetAPickupFactory() { return NULL; }
virtual void SetVolumes(const TArray<class AVolume*>& Volumes);
virtual void SetVolumes();
virtual UBOOL ReachedBy(APawn* P, const FVector& TestPosition, const FVector& Dest);
virtual UBOOL TouchReachSucceeded(APawn *P, const FVector& TestPosition);
virtual UBOOL GetUpDir( FVector &V ) { return 0; }
virtual void AddToNavigationOctree();
virtual void RemoveFromNavigationOctree();
virtual UBOOL PlaceScout(class AScout *Scout);
/** returns the position the AI should move toward to reach this actor */
FVector GetDestination(AController* C);
/** sorts the PathList by distance, shortest first */
void SortPathList();
/**
* Fills the array of any nav references needing to be fixed up.
*/
virtual void GetActorReferences(TArray<FActorReference*> &ActorRefs, UBOOL bIsRemovingLevel);
virtual void ClearCrossLevelReferences();
virtual FGuid* GetGuid() { return &NavGuid; }
virtual ANavigationPoint* SpecifyEndAnchor(APawn* RouteFinder);
/**
* Works through the component arrays marking entries as pending kill so references to them
* will be NULL'ed.
*
* @param bAllowComponentOverride Whether to allow component to override marking the setting
*/
virtual void MarkComponentsAsPendingKill(UBOOL bAllowComponentOverride = FALSE);
#if __TW_PATHFINDING_
virtual ANavigationPoint* GetANavigationPoint() { return this; }
virtual const ANavigationPoint* GetANavigationPoint() const { return this; }
#endif
}
native function GetBoundingCylinder(out float CollisionRadius, out float CollisionHeight) const;
`if(`__TW_PATHFINDING_)
native final function ReachSpec GetReachSpecTo( NavigationPoint Nav, optional class<ReachSpec> SpecClass, optional Pawn CheckPawn );
`else
native final function ReachSpec GetReachSpecTo( NavigationPoint Nav, optional class<ReachSpec> SpecClass );
`endif
/** returns whether this NavigationPoint is valid to be considered as an Anchor (start or end) for pathfinding by the given Pawn
* @param P the Pawn doing pathfinding
* @return whether or not we can be an anchor
*/
native function bool IsUsableAnchorFor( Pawn P );
/** returns whether this NavigationPoint is a teleporter that can teleport the given Actor */
native function bool CanTeleport(Actor A);
event int SpecialCost(Pawn Seeker, ReachSpec Path);
// Accept an actor that has teleported in.
// used for random spawning and initial placement of creatures
event bool Accept( actor Incoming, actor Source )
{
local bool bResult;
// Move the actor here.
bResult = Incoming.SetLocation( Location );
if (bResult)
{
Incoming.Velocity = vect(0,0,0);
Incoming.SetRotation(Rotation);
}
Incoming.PlayTeleportEffect(true, false);
return bResult;
}
/* DetourWeight()
value of this path to take a quick detour (usually 0, used when on route to distant objective, but want to grab inventory for example)
*/
event float DetourWeight(Pawn Other,float PathWeight);
/* SuggestMovePreparation()
Optionally tell Pawn any special instructions to prepare for moving to this goal
(called by Pawn.PrepareForMove() if this node's bSpecialMove==true
*/
event bool SuggestMovePreparation( Pawn Other )
{
// If special move was taken to get to this link
return Other.SpecialMoveTo(Other.Anchor, self, Other.Controller.MoveTarget);
}
/* ProceedWithMove()
Called by Controller to see if move is now possible when a mover reports to the waiting
pawn that it has completed its move
*/
function bool ProceedWithMove(Pawn Other)
{
return true;
}
/**
* Returns the nearest valid navigation point to the given actor.
*/
static final function NavigationPoint GetNearestNavToActor(Actor ChkActor, optional class<NavigationPoint> RequiredClass,optional array<NavigationPoint> ExcludeList,optional float MinDist)
{
local NavigationPoint Nav, BestNav;
local float Dist, BestDist;
if (ChkActor != None)
{
// iterate through all points in the level
foreach ChkActor.WorldInfo.AllNavigationPoints(class'NavigationPoint',Nav)
{
// if no filter class specified, and
// if nav is available to the check actor, and
// if the nav isn't part of the excluded list,
if ((RequiredClass == None || Nav.class == RequiredClass) && ExcludeList.Find(Nav) == INDEX_NONE)
{
// pick the closest
Dist = VSize(Nav.Location-ChkActor.Location);
if (Dist > MinDist)
{
if (BestNav == None ||
Dist < BestDist)
{
BestNav = Nav;
BestDist = Dist;
}
}
}
}
}
return BestNav;
}
/**
* Returns the nearest valid navigation point to the given point.
*/
static final function NavigationPoint GetNearestNavToPoint(Actor ChkActor,vector ChkPoint, optional class<NavigationPoint> RequiredClass,optional array<NavigationPoint> ExcludeList)
{
local NavigationPoint Nav, BestNav;
local float Dist, BestDist;
if (ChkActor != None)
{
// iterate through all points in the level
foreach ChkActor.WorldInfo.AllNavigationPoints(class'NavigationPoint',Nav)
{
// if no filter class specified, and
// if nav is available to the check actor, and
// if the nav isn't part of the excluded list,
if ((RequiredClass == None || Nav.class == RequiredClass) && ExcludeList.Find(Nav) == INDEX_NONE)
{
// pick the closest
Dist = VSize(Nav.Location-ChkPoint);
if (BestNav == None ||
Dist < BestDist)
{
BestNav = Nav;
BestDist = Dist;
}
}
}
}
return BestNav;
}
/**
* Returns all navigation points near the ChkPoint specified by Radius.
*/
static native final function bool GetAllNavInRadius( Actor ChkActor, Vector ChkPoint, float Radius, out array<NavigationPoint> out_NavList, optional bool bSkipBlocked, optional int inNetworkID=-1, optional Cylinder MinSize );
/** Returns if this navigation point is on a different network than the given */
native final function bool IsOnDifferentNetwork( NavigationPoint Nav );
/**
* Toggle the blocked state of a navigation point.
*/
function OnToggle(SeqAct_Toggle inAction)
{
if (inAction.InputLinks[0].bHasImpulse)
{
bBlocked = false;
}
else if (inAction.InputLinks[1].bHasImpulse)
{
bBlocked = true;
}
else if (inAction.InputLinks[2].bHasImpulse)
{
bBlocked = !bBlocked;
}
WorldInfo.Game.NotifyNavigationChanged(self);
bShouldSaveForCheckpoint = true;
}
simulated event ShutDown()
{
Super.ShutDown();
bBlocked = TRUE;
WorldInfo.Game.NotifyNavigationChanged(self);
bShouldSaveForCheckpoint = true;
}
function bool ShouldSaveForCheckpoint()
{
return bShouldSaveForCheckpoint;
}
function CreateCheckpointRecord(out CheckpointRecord Record)
{
Record.bBlocked = bBlocked;
}
function ApplyCheckpointRecord(const out CheckpointRecord Record)
{
bBlocked = Record.bBlocked;
bShouldSaveForCheckpoint = true;
}
/** @return Debug abbrev for hud printing */
simulated event string GetDebugAbbrev()
{
return "NP?";
}
defaultproperties
{
Begin Object Class=SpriteComponent Name=Sprite
Sprite=Texture2D'EditorResources.S_NavP'
HiddenGame=true
HiddenEditor=false
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
SpriteCategoryName="Navigation"
End Object
Components.Add(Sprite)
GoodSprite=Sprite
Begin Object Class=SpriteComponent Name=Sprite2
Sprite=Texture2D'EditorResources.Bad'
HiddenGame=true
HiddenEditor=true
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
SpriteCategoryName="Navigation"
Scale=0.25
End Object
Components.Add(Sprite2)
BadSprite=Sprite2
Begin Object Class=ArrowComponent Name=Arrow
ArrowColor=(R=150,G=200,B=255)
ArrowSize=1
bTreatAsASprite=True
HiddenGame=true
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
SpriteCategoryName="Navigation"
End Object
Components.Add(Arrow)
Begin Object Class=CylinderComponent Name=CollisionCylinder LegacyClassName=NavigationPoint_NavigationPointCylinderComponent_Class
CollisionRadius=+0050.000000
CollisionHeight=+0050.000000
End Object
CollisionComponent=CollisionCylinder
CylinderComponent=CollisionCylinder
Components.Add(CollisionCylinder)
Begin Object Class=PathRenderingComponent Name=PathRenderer
End Object
Components.Add(PathRenderer)
bMayCausePain=true
bStatic=true
bNoDelete=true
bHidden=FALSE
bCollideWhenPlacing=true
bMustTouchToReach=true
// Long range reachspecs are the source of all evil
bBuildLongPaths=false
bCollideActors=false
// default to no network id
NetworkID=-1
// NavigationPoints are generally server side only so we don't need to worry about client simulation
bForceAllowKismetModification=true
bAllowPathConnections=true
}