Files
GTASource/game/pathserver/PathServer.h

1234 lines
57 KiB
C
Raw Normal View History

2025-02-23 17:40:52 +08:00
#ifndef PATHSERVER_H
#define PATHSERVER_H
#include "ai/navmesh/datatypes.h"
#include "ai/navmesh/requests.h"
#include "PathServer\PathServerThread.h"
#include "PathServer\NavGenParam.h"
#ifdef GTA_ENGINE
#include "atl/binheap.h"
#include "control/population.h" // For CPopGenShape
#include "PathServer/PathServer_Store.h"
#include "PathServer/PathServer_Ped.h"
#include "task/Combat/Cover/cover.h" // For CCoverBoundingArea and CCover::MAX_BOUNDING_AREAS.
#else
#include "viewer_dummystore.h"
#include "GTATypes.h"
#endif
#include "ai/navmesh/pathserverbase.h"
#include "bank/bank.h"
class CEntity;
class CPed;
//************************************************************************************
//
// Filename : PathServer.h
// Author : James Broad
// RockstarNorth (c) 2005
//
//************************************************************************************
//
// Overview:
// ---------
//
// This implementes the CPathServer class, and related classes.
// The idea is that path requests are made to the CPathServer class by anyone who
// wants to find a path from A to B in the world. The CPathServer then returns a
// handle, and queues the request. The queued requests are processed by a
// separate thread encapsulated in the CPathServerThread class, whose sole purpose
// is to process path requests and store the results until they are retrieved.
// Anyone using the CPathServer will need to call the IsRequestReady() function
// each frame of processing, and if this returns true they can retrieve the points
// for the path (and some other associated data) with a Lock()/Unlock() syntax.
// Other request types are possible : a line-of-sight can be tested across the
// navmeshes (this is actually a line-of-movement) to see if it is possible to
// get from A to B without obstruction, and an axis-aligned grid can be requested,
// which describing which areas are walkable or not surrounding a point.
// The CPathServer class also stores any cover-points which were found during the
// map analysis - the CCover class interfaces with the path-server to allow these
// points to be retrieved.
// Ped generation functions are also contained in the class, and allow suitable
// coordinates to be found for ped generation - based upon a required 'density'
// value. Areas of the map's navmeshes can also be switched on & off as required
// by missions. These features mirror the functionality provided by the ped-nodes.
//
//************************************************************************************
class CPathServer : public fwPathServer
{
friend class CPathServerThread;
friend class CNavGenApp;
friend class CNavGen;
friend class aiNavMeshStoreInterfaceGta;
friend class CDynamicObjectsContainer;
friend class CCachedPedGenCoords;
friend class CNavMeshDataExporter;
friend class CPathServerAmbientPedGen;
friend class CPathServerOpponentPedGen;
public:
CPathServer();
~CPathServer();
enum EProcessingMode
{
EUndefined,
ESingleThreaded, // The Process() function will call the CPathServerThread::Run() function
EMultiThreaded // The CPathServerThread will run in the background
};
enum EObjectAvoidanceMode
{
ENoObjectAvoidance, // Don't bother testing for dynamic objects
EPolyTessellation, // Tessellate polygons intersecting dynamic objects
EPolyClipping // Clip polygons intersecting dynamic objects
};
enum EPedGenProcessing
{
EPedGen_AmbientPeds, // Ambient peds in the world
EPedGen_OpponentSpawning // Enemy AI peds for multiplayer
};
static bool ms_bInitialised;
static bool ms_bGameInSession;
static bool ms_bStreamingDisabled;
// Completely disables pathfinding by making every request complete instantly & consist of only the start & end point
static bool m_bDisablePathFinding;
static s32 ms_iTimeToNextRequestAndEvict;
static bool ms_bHaveAnyDynamicObjectsChanged;
static bool ms_bNoNeedToCheckObjectsForThisPoly;
static EObjectAvoidanceMode m_eObjectAvoidanceMode;
static float ms_fDefaultDynamicObjectPlaneEpsilon;
static bank_float ms_fDynamicObjectVelocityThreshold;
static bank_bool ms_bTestConnectionPolyExit;
static bank_bool ms_bDisallowClimbObjectLinks;
// DEBUGGING TOGGLES ONLY (TODO: change to bank_vars)
static bank_s32 ms_iRequestAndEvictFreqMS;
static bank_bool ms_bRefinePaths;
static bank_bool ms_bSmoothRoutesUsingSplines;
static bank_bool ms_bCutCornersOffAllPaths;
static bank_bool ms_bMinimisePathDistance;
static bank_bool ms_bMinimiseBeforeRefine;
static bank_bool ms_bPullPathOutFromEdges;
static bank_bool ms_bPullPathOutFromEdgesTwice;
static bank_bool ms_bPullPathOutFromEdgesStringPull;
static bank_bool ms_bDoPolyTessellation;
static bank_bool ms_bDoPolyUnTessellation;
static bank_bool ms_bDoPreemptiveTessellation;
static bank_bool ms_bUseGridCellCache;
static bank_bool ms_bUseTessellatedPolyObjectCache;
static bank_bool ms_bAlwaysUseMorePointsInPolys;
//static bank_bool ms_bSphereRayEarlyOutTestOnObjects;
static bank_bool ms_bUseLosToEarlyOutPathRequests;
static bank_bool ms_bDontRevisitOpenNodes; // If set, this means the pathsearch can never revisit any poly once visited
static bank_bool ms_bAllowTessellationOfOpenNodes;
static bank_bool ms_bOutputDetailsOfPaths;
static bank_bool ms_bTestObjectsForEveryPoly;
static bank_bool ms_bUseOptimisedPolyCentroids;
static bank_bool ms_bUseGridToCullObjectLOS;
static bank_bool ms_bUseNewPathPriorityScoring;
// END DEBUGGING TOGGLES
// Initialise the path-server, and create the path server thread on the specified processor
// The 'pPathForNavMeshes' parameter is used for debugging purposes when streaming is not active
static bool Init(const fwPathServerGameInterface &gameInterface, EProcessingMode eProcessingMode = EMultiThreaded, u32 iProcessorIndex = 0, const char * pRelativePathAndFilenameForNavMeshes = NULL, const char * pPathForDatFile = NULL, const char * pDebugPathForNavFiles = NULL);
static void RegisterStreamingModule(const char* pPathForDatFile = NULL);
static void DisableStreaming(bool b) { ms_bStreamingDisabled = b; }
// Resets the navmesh system, unloads navmeshes, etc.
static void Reset(const bool bLoadingNewMap=false);
static void Shutdown();
static void InitBeforeMapLoaded(unsigned iInitMode);
static void InitSession(unsigned iInitMode);
static void ShutdownSession(unsigned iShutdownMode);
static void ReadIndexMappingFiles();
static bool ReadDatFile(const char * pGameDataPath, CNavDatInfo & navMeshesInfo, CNavDatInfo & navNodesInfo);
// Sets where the navigation system streams its navmeshes from.
static bool SetNavMeshesImageFile(char * pRelativePath, char * pFilename);
// Called per-frame to update the player's/viewer's origin
static void Process(void);
static void Process(const Vector3 & vOrigin);
#if __HIERARCHICAL_NODES_ENABLED
static aiNavNodesStore * GetNavNodesStore() { return m_pNavNodesStore; }
#endif
#ifdef GTA_ENGINE
static void FloodFillNodesForPedDeficit(const Vector3 & vCentrePos, CHierarchicalNavNode * pNode, CHierarchicalNavData * pNavData);
static void ForcePerformThreadHousekeeping(bool b);
#endif
//*******************************************************************************
// Functions to control extracting water-edges from navmeshes, for use by audio
// Set the origin of the position to scan for water-edges
static void SetWaterEdgeParams(const Vector3 & vOrigin);
// Retrieve the water edges which we have found.
// pOutPts must point to an array no less than SIZE_OF_WATEREDGES_BUFFER in size.
// This function may return false if the pathfinding thread was busy at the time of querying.
static bool GetWaterEdgePoints(int & iOutNumPts, Vector3 * pOutPoints, u32 * pOutPerPolyAudioProperties=NULL);
// Set/get the distance from the current origin within which navmeshes are streamed into memory
static inline void SetNavMeshLoadDistance(float fDist) { m_fNavMeshLoadProximity = fDist; }
static inline float GetNavMeshLoadDistance(void) { return m_fNavMeshLoadProximity; }
// Called to add cover points near the origin, to the global CCover class
static void AddCoverPoints(const Vector3 & vOrigin, float fMaxDistance, int maxNumPointsToAdd);
#ifdef GTA_ENGINE
static CPathServerAmbientPedGen & GetAmbientPedGen() { return m_AmbientPedGeneration; }
static CPathServerOpponentPedGen & GetOpponentPedGen() { return m_OpponentPedGeneration; }
#endif
// TODO: remove this once we have a fwPathServerThread to contain the OnFirstVisitingPoly() function
static bool OnFirstVisitingPolyCallback(TNavMeshPoly * pPoly);
//***************************************************************************************
// Functions to do with requesting path or other queries from the path sever. Clients
// keep a handle to the query, and can then poll for completion in subsequent frames.
// General purpose RequestPath() function
static TPathHandle RequestPath(const TRequestPathStruct & reqStruct);
// (NB: This multi-parameter version will be removed shortly..)
static TPathHandle RequestPath(
const Vector3 & vPathStart, // The start point of the path
const Vector3 & vPathEnd, // The end point of the path
const Vector3 & vReferenceVector, // reference vector (not always used)
float fReferenceDistance, // reference distance (not always used)
u64 iFlags, // path flags
float fCompletionRadius, // if exact path cannot be found, try to get within this range of target
u32 iNumInfluenceSpheres, // num influence spheres
TInfluenceSphere * pInfluenceSpheres, // pointer to an array of influence spheres
fwEntity * pPed, // context - for debugging (typically use the ped pointer)
const fwEntity * pEntityPathIsOn // pointer to the entity this path is known to be on (if it has a dynamic navmesh attached)
);
// Simplified interface for basic paths
static TPathHandle RequestPath(const Vector3 & vPathStart, const Vector3 & vPathEnd, u64 iPathStyleFlags, float fCompletionRadius = 0.0f, fwEntity * pPed = NULL);
// Requests a path-search which starts at vStartPos, and spreads out attempting to find a position which has a clear navmesh
// line-of-sight to vVantagePos. Will favour spreading out in vPreferredDirection, and will not spread out further than fMaxDistToLook.
static TPathHandle RequestVantagePoint(const Vector3 & vStartPos, const Vector3 & vVantagePos, const Vector3 & vPreferredDirection, float fMaxDistToLook);
// The method for getting the result path of the path request
static EPathServerErrorCode LockPathResult(TPathHandle hPath, int * iNumPoints, Vector3 *& pPoints, TNavMeshWaypointFlag *& pWaypointFlags)
{
return LockPathResult(hPath, iNumPoints, pPoints, pWaypointFlags, NULL);
}
static EPathServerErrorCode LockPathResult(TPathHandle hPath, int * iNumPoints, Vector3 *& pPoints, TNavMeshWaypointFlag *& pWaypointFlags, TPathResultInfo * pPathInfo);
static bool UnlockPathResultAndClear(TPathHandle hPath);
// General function to see if a request result is ready yet
static EPathServerRequestResult IsRequestResultReady(TPathHandle hPath);
// Function to see if a request result is ready, when the type of the request is known
static EPathServerRequestResult IsRequestResultReady(TPathHandle hPath, EPathServerRequestType eType);
// Cancels a pending/active/completed path request
static bool CancelRequest(TPathHandle handle);
// Requests a navmesh line-of-sight query from vStart to vEnd, for an entity of fRadius. NB: the fRadius parameter is *currently ignored*
static TPathHandle RequestLineOfSight(const Vector3 & vStart, const Vector3 & vEnd, float fRadius, bool bDynamicObjects = true, bool bNoLosAcrossWaterBoundary = false, bool bStartInWater = false, int iNumExcludeObjects = 0, CEntity ** ppExcludeObjects = NULL, const float fMaxSlopeAngle=0.0f, void * pContext=NULL, aiNavDomain domain = kNavDomainRegular);
static TPathHandle RequestLineOfSight(const Vector3 * vPts, int iNumPts, float fRadius, bool bDynamicObjects = true, bool bQuitAtFirstLosFail = true, bool bNoLosAcrossWaterBoundary = false, bool bStartInWater = false, int iNumExcludeObjects = 0, CEntity ** ppExcludeObjects = NULL, const float fMaxSlopeAngle=0.0f, void * pContext=NULL, aiNavDomain domain = kNavDomainRegular);
// Request the audio properties of the navmesh poly underneath the input position, or the closest nearby navmesh poly found
static TPathHandle RequestAudioProperties(const Vector3 & vPosition, TNavMeshAndPoly * pKnownNavmeshPosition = NULL, const bool bPriorityRequest = false, fwEntity * pPed = NULL, aiNavDomain domain = kNavDomainRegular)
{
return RequestAudioProperties(vPosition, pKnownNavmeshPosition, 0.0f, bPriorityRequest, pPed, domain);
}
static TPathHandle RequestAudioProperties(const Vector3 & vPosition, TNavMeshAndPoly * pKnownNavmeshPosition, float fRadius, const bool bPriorityRequest = false, fwEntity * pPed = NULL, aiNavDomain domain = kNavDomainRegular)
{
return RequestAudioProperties(vPosition, pKnownNavmeshPosition, fRadius, Vector3(0.0f, 0.0f, 0.0f), bPriorityRequest, pPed, domain);
}
static TPathHandle RequestAudioProperties(const Vector3 & vPosition, TNavMeshAndPoly * pKnownNavmeshPosition, float fRadius, const Vector3 & vDirection, const bool bPriorityRequest = false, void * pContext = NULL, aiNavDomain domain = kNavDomainRegular);
// Request a grid sampling the walkable regions around the origin. (Not currently used for anything in-game)
static TPathHandle RequestGrid(const Vector3 & vOrigin, u32 iSize, float fResolution, void * pContext = NULL, aiNavDomain domain = kNavDomainRegular);
// Copies the data into the 'destGrid', and thereafter hPath is invalid.
static EPathServerErrorCode GetGridResultAndClear(TPathHandle hPath, CWalkRndObjGrid & destGrid);
// Gets the result of a LineOfSight query, and clears the handle after
static EPathServerErrorCode GetLineOfSightResult(TPathHandle handle, bool & bLineOfSightIsClear);
// Get the results of a LineOfSight query which consisted of multiple line-segments (ie. a polyline)
// The overall result for all segments is returned in bLineOfSightIsClear, and individual results copied into bLineOfSightResults.
static EPathServerErrorCode GetLineOfSightResult(TPathHandle handle, bool & bLineOfSightIsClear, bool * bLineOfSightResults, int iNumPts);
// Copies the result of the audio properties query into iAudioProperties, and clears the request
static EPathServerErrorCode GetAudioPropertiesResult(TPathHandle handle, u32 & iAudioProperties);
// Copies an array of audio properties & poly areas. The input pAudioProperties & pPolyAreas *must* point to arrays of MAX_SURROUNDING_POLYS_FOR_AUDIO_PROPERTIES in size!
static EPathServerErrorCode GetAudioPropertiesResult(TPathHandle handle, u32 & iNumProperties, u32 * pAudioProperties, float * pPolyAreas, Vector3 * pPolyCentroids, u8 * pAdditionalFlags);
// Requests a flood-fill search, to find the closest accessible instance of "eFloodFillType" within the given radius
static TPathHandle RequestClosestViaFloodFill(const Vector3 & vStartPos, const float fMaxRadius, CFloodFillRequest::EType eFloodFillType, const bool bCheckDynamicObjects, const bool bUseClimbsAndDrops, const bool bUseLadders, void * DEV_ONLY(pContext), aiNavDomain domain = kNavDomainRegular);
// Gets the result of a floodfill search
static EPathServerErrorCode GetClosestFloodFillResultAndClear(const TPathHandle hPath, Vector3 & vClosest, float & fValue, const CFloodFillRequest::EType eType);
// Requests a flood-fill search, to find the closest accessible carnode within the given radius
static TPathHandle RequestClosestCarNodeSearch(const Vector3 & vStartPos, const float fMaxRadius, void * pContext=NULL);
// Gets the result of a search for the closest car node
static EPathServerErrorCode GetClosestCarNodeSearchResultAndClear(const TPathHandle hPath, Vector3 & vClosestCarNode);
// Requests a flood-fill search, to find the closest accessible sheltered navmesh poly within the given radius
static TPathHandle RequestClosestShelteredPolySearch(const Vector3 & vStartPos, const float fMaxRadius, void * pContext=NULL);
// Gets the result of a search for a sheltered poly
static EPathServerErrorCode GetClosestShelteredPolySearchResultAndClear(const TPathHandle hPath, Vector3 & vClosestShelteredPoly);
// Requests a flood-fill search, to find the closest accessible unsheltered navmesh poly within the given radius
static TPathHandle RequestClosestUnshelteredPolySearch(const Vector3 & vStartPos, const float fMaxRadius, void * pContext=NULL);
// Gets the result of a search for a unsheltered poly
static EPathServerErrorCode GetClosestUnshelteredPolySearchResultAndClear(const TPathHandle hPath, float & vClosestShelteredPoly);
// Requests a flood-fill to calculate the area of connected navmesh which is under the input position (using the same
// methods to determine the starting-poly as the regular pathserach does)
static TPathHandle RequestCalcAreaUnderfootSearch(const Vector3 & vStartPos, const float fMaxRadius, void * pContext);
// Retrieves the area found by the above search
static EPathServerErrorCode GetAreaUnderfootSearchResultAndClear(const TPathHandle hPath, float & fArea);
static TPathHandle RequestClearArea(const Vector3 & vSearchOrigin, const float fSearchRadiusXY, const float fSearchDistZ, const float fDesiredClearRadius, const float fOptionalMinimumRadius, const bool bConsiderDynamicObjects, const bool bSearchInteriors, const bool bSearchExterior, const bool bConsiderWater, const bool bConsidereSheltered, void * DEV_ONLY(pContext), aiNavDomain domain);
static EPathServerErrorCode GetClearAreaResultAndClear(const TPathHandle hPath, Vector3 & vResultOrigin);
// Request a flood-fill search to find the closest pavement navmesh poly within a given radius.
static TPathHandle RequestHasNearbyPavementSearch(const Vector3& vStartPos, const float fMaxRadius, void* pContext = NULL);
static EPathServerErrorCode GetHasNearbyPavementSearchResultAndClear(const TPathHandle hPath);
static TPathHandle RequestClosestPosition(const Vector3 & vSearchOrigin, const float fSearchRadius, const u32 iFlags, const float fZWeightingAbove, const float fZWeightingAtOrBelow, const float fMinimumSpacing, const s32 iNumAvoidSpheres, const spdSphere * pAvoidSpheres, const s32 iMaxNumResults, void * pContext, aiNavDomain domain);
static EPathServerErrorCode GetClosestPositionResultAndClear(const TPathHandle hPath, CClosestPositionRequest::TResults & results);
// Tests a line-of-sight against the navmesh immediately, bypassing the processing thread (ie. this function is intended to be called from the
// main game thread - and musn't be used by the pathfinder). The LOS must be short, and will fail if over SHORT_LINE_OF_SIGHT_MAXDIST in
// length. This function does not consider dynamic objects.
static TNavMeshPoly * TestShortLineOfSightImmediate(const Vector3 & vStart, const Vector3 & vEnd, Vector3 & vIsectPos, aiNavDomain domain);
static TNavMeshPoly * TestShortLineOfSightImmediate(const Vector3 & vStartPos, const Vector2 & vLosDir, TNavMeshPoly * pStartPoly, Vector3 * pvOut_IntersectionPos, Vector3 * pvOut_HitEdgeVec, int * pOut_iEdgeHitIndex, aiNavDomain domain);
static TNavMeshPoly * TestShortLineOfSightImmediate_R(const Vector3 & vStartPos, const Vector2 & vDir, TNavMeshPoly * pTestPoly, TNavMeshPoly * pLastPoly, const TShortMinMax & endMinMax, Vector3 & vOut_IsectPos, aiNavDomain domain);
static bool TestShortLineOfSightImmediate_RG(Vector3& o_Vertex1, Vector3& o_Vertex2, const Vector3& vStartPos, const Vector3& vEndPos, TNavMeshPoly& testPoly, aiNavDomain domain);
static TNavMeshPoly * SlidePointAlongNavMeshEdgeImmediate(const Vector3 & vStartPos, const Vector2 & vLosDir, TNavMeshPoly * pPoly, int & iInOut_HitEdge, Vector3 & vOutPos, aiNavDomain domain);
enum eImmediatePathResult
{
// Everything was fine
IMPath_NoError,
// There was no navmesh underneath the input coordinates
IMPath_ENoNavMeshAtCoords,
// No path could be found. This could mean there is nowhere to go.
IMPath_ENoPathFound,
// A flee path has become stuck and cannot find its way out of a dead-end
IMPath_EStuckInDeadEnd
};
#if __TRACK_PEDS_IN_NAVMESH
// Updates the tracking of all the CPeds in the game
static void UpdatePedTracking();
static void InvalidateTrackers(const u32 iNavMesh=NAVMESH_NAVMESH_INDEX_NONE);
#endif
// Switched ped generation & wandering on/off for the given region
static void SwitchPedsOnInArea(const Vector3 & vMin, const Vector3 & vMax, scrThreadId iScriptUID);
static void SwitchPedsOffInArea(const Vector3 & vMin, const Vector3 & vMax, scrThreadId iScriptUID);
static void DisableNavMeshInArea(const Vector3 & vMin, const Vector3 & vMax, scrThreadId iScriptUID);
static void ReEnableNavMeshInArea(const Vector3 & vMin, const Vector3 & vMax, scrThreadId iScriptUID);
// Removes ped switch areas within region, and resets all polygons to ok for ped generation & wandering
static void ClearPedSwitchAreas(const Vector3 & vMin, const Vector3 & vMax);
// Removes all the ped switch areas which were originally created by the specified script (for use during mission cleanup)
static void ClearPedSwitchAreasForScript(scrThreadId iScriptUID);
// Removes all ped switch areas, and resets all polygons to ok for ped generation & wandering
static void ClearAllPedSwitchAreas(void);
static bool IsCoordInPedSwitchedOffArea(const Vector3 & vPos);
// Defines a sphere within which will be the only area that peds can be created (provided other pedgen criteria are satisifed)
static void DefinePedGenConstraintArea(const Vector3 & vPos, const float fRadius);
// Destroy a constraint area, and go back to normal ped generation
static void DestroyPedGenConstraintArea();
// Adds a blocking object, which will block pathfind for the given types of path
static TDynamicObjectIndex AddBlockingObject(const Vector3 & vPosition, const Vector3 & vSize, const float fHeading, const s32 iBlockingFlags=TDynamicObject::BLOCKINGOBJECT_ALL_PATH_TYPES);
// Update a blocking object with new position/orientation
static void UpdateBlockingObject(const TDynamicObjectIndex iObjIndex, const Vector3 & vPosition, const Vector3 & vSize, const float fHeading, bool bForceUpdate, u32 * pBlockingFlags=NULL);
// Removes a previously added object
static bool RemoveBlockingObject(const TDynamicObjectIndex iObjIndex);
// Schedule the climb at the given position to be disabled asap. In practice this will be the next time that
// the CPathServerThread runs its DoHousekeeping() function during idle time between requests.
// Climb type must be one or both of the supplied booleans, but not neither.
static void DeferredDisableClimbAtPosition(const Vector3 & vPos, const bool bNavmeshClimb, const bool bClimbableObject);
// Disables a climb at the given position. If a ped is repeatedly unable to do a climb whilst following a navmesh
// route, then we will have to disable the climb which will force them (and other) to try an alternative route.
// "bClimbableObject" indicates a cimbable-object climb (eg. fence), otherwise this is a navmesh climb.
static bool DisableClimbAtPosition(const Vector3 & vPos, const bool bClimbableObject);
// Finds a safe position to place a ped, which is on the navmesh. If bOnlyOnPavement is set, then
// only positions on pavements are considered & the function may fail if there are no pavements anywhere.
static EGetClosestPosRet GetClosestPositionForPed(const Vector3 & vNearThisPosition, Vector3 & vecOut, const float fMaxSearchRadius=15.0f, const u32 iFlags=GetClosestPos_ClearOfObjects, const bool bFailIfNoThreadAccess=false, const int iNumAvoidSpheres=0, const spdSphere * pAvoidSpheresArray=NULL, aiNavDomain domain = kNavDomainRegular);
// Finds a car node close to the input position which is clear of nearby objects, vehicles, etc.
static bool GetClosestClearCarNodeForPed(const Vector3 & vNearThisPosition, Vector3 & vecOut, const float fMaxSearchRadius=15.0f);
static bool TestNavMeshPolyUnderPosition(const Vector3 & vPosition, Vector3& pOutPos, const bool bNotIsolated, const bool bClearOfDynamicObjects, aiNavDomain domain = kNavDomainRegular);
// Requests navmeshes to be loaded in the specified area
static bool AddNavMeshRegion( const NavMeshRequiredRegion region, const scrThreadId iThreadId, const float fOriginX, const float fOriginY, const float fRadius );
static bool RemoveNavMeshRegion( const NavMeshRequiredRegion region, const scrThreadId iThreadId );
static scrThreadId GetNavmeshMeshRegionScriptID();
static bool GetIsNavMeshRegionRequired( const NavMeshRequiredRegion region );
static void RemoveAllNavMeshRegions();
static void CountScriptMemoryUsage(u32& nVirtualSize, u32& nPhysicalSize);
// Returns whether the navmeshes around the given area are loaded
static bool AreAllNavMeshRegionsLoaded(aiNavDomain domain = kNavDomainRegular);
static bool UnloadAllMeshes(bool bForceRemove);
static bool LoadAllHierarchicalData(const char * pPathForHierarchicalData);
#ifdef GTA_ENGINE
static s32 GetNavMeshStreamingModuleId(aiNavDomain domain)
{
if(ms_bStreamingDisabled)
return -1;
return m_pNavMeshStores[domain]->GetStreamingModuleId();
}
#if __HIERARCHICAL_NODES_ENABLED
static s32 GetHierarchicalNodesStreamingModuleId() { return m_pNavNodesStore->GetStreamingModuleId(); }
#endif
static void SuspendThread(void);
static void ResumeThread(void);
#else
static bool LoadAllMeshes(const char * pPathForNavMeshes);
#endif
static bool m_bGameRunning;
static u32 ms_iBlockRequestsFlags;
enum
{
BLOCK_REQUESTS_ON_REQUEST_AND_EVICT = 0x01,
BLOCK_REQUESTS_ON_ADD_DYNAMIC_OBJECTS = 0x02,
BLOCK_REQUESTS_ON_DEFRAG_NAVMESHES = 0x04
};
static void ApplyPedAreaSwitchesToNewlyLoadedNavMesh(CNavMesh * pNavMesh, aiNavDomain domain);
static const fwPathServerGameInterface& GetGameInterface()
{ Assert(m_GameInterface);
return *m_GameInterface;
}
#if !__FINAL && __BANK
// Outputs a text ".prob" file with the path request & dynamic objects' positions
static bool OutputPathRequestProblem(u32 iPathRequestIndex, const char * pFilename=NULL);
static bool OutputPathRequestProblem(CPathRequest * pRequest, const char * pFilename=NULL);
#ifndef GTA_ENGINE
static bool LoadPathRequestProblem(void);
static bool LoadPathRequestProblem(char * filename);
#endif
#endif
#if !__FINAL
static void InitWidgets();
static void Visualise(void);
static void VisualiseNavMesh(CNavMesh * pNavMesh, const Vector3 & vOrigin, const float fHeightAboveMesh, const bool bIsMainNavMeshUnderFoot, aiNavDomain domain);
static void VisualiseHierarchicalNavData(CHierarchicalNavData * pHierNav, const Vector3 & vOrigin, const float fVisDist);
static void VisualiseAdjacency(const Vector3 & vPosStart, const Vector3 & vPosEnd, eNavMeshPolyAdjacencyType adjacencyType, bool bIsHighDrop, bool bIsDisabled, s32 iAlpha);
static void VisualiseSpecialLinks(CNavMesh * pNavMesh, aiNavDomain domain);
static void RenderMiscThings();
static bool TransformWorldPosToScreenPos(const Vector3 & vWorldPos, Vector2 & vScreenPos);
static int VisualisePathServerCommon(aiNavDomain domain, int ypos);
static int VisualiseCurrentNavMeshDetails(int ypos, CNavMesh * pNavMesh);
static void VisualiseText(int ypos, aiNavDomain domain);
static void VisualisePathRequests(int ypos, aiNavDomain domain);
static void VisualisePathDetails(CPathRequest * pPathReq, int ypos);
static void VisualiseLineOfSightRequests(int ypos, aiNavDomain domain);
static void VisualiseAudioPropertiesRequests(int ypos, aiNavDomain domain);
static void VisualiseFloodFillRequests(int ypos, aiNavDomain domain);
static void VisualiseClearAreaRequests(int ypos, aiNavDomain domain);
static void VisualiseClosestPositionRequests(int ypos, aiNavDomain domain);
static void VisualiseMemoryUsage(int ypos, aiNavDomain domain);
static void VisualisePolygonInfo(int ypos, CNavMesh * pNavMesh, const Vector3 & vOrigin, aiNavDomain domain);
static void VisualiseTestPathEndPoints();
static void DrawPolyDebug(CNavMesh * pNavMesh, u32 iPolyIndex, Color32 iCol, float fAddHeight, bool bOutline, int filledAlpha = 255, bool bDrawCentroidQuick=false);
static void DrawPolyVolumeDebug(CNavMesh * pNavMesh, int iPolyIndex, Color32 iCol1, Color32 iCol2, float fSpaceAbove);
static void DebugPolyText(CNavMesh * pNavMesh, u32 iPolyIndex);
#if __BANK
static void DebugOutPathRequestResult(CPathRequest * pPathRequest);
static void PathServer_TestCalcPolyAreas();
#endif
static float ms_fDebugVisPolysMaxDist;
static float ms_fDebugVisNodesMaxDist;
static bool m_bDebugPolyUnderfoot;
static bool ms_bDebugPathFinding;
static bool ms_bMarkVisitedPolys;
static bool ms_bUnMarkVisitedPolys;
static bool ms_bDrawDynamicObjectGrids;
static bool ms_bDrawDynamicObjectMinMaxs;
static bool ms_bDrawDynamicObjectAxes;
static bool ms_bRenderMiscThings;
static bool ms_bEnsureLosBeforeEnding;
enum eNavMeshVisMode
{
NavMeshVis_Off,
NavMeshVis_NavMeshWireframe,
NavMeshVis_NavMeshTransparent,
NavMeshVis_NavMeshSolid,
NavMeshVis_Pavements,
NavMeshVis_Roads,
NavMeshVis_TrainTracks,
NavMeshVis_PedDensity,
NavMeshVis_Disabled,
NavMeshVis_Shelter,
NavMeshVis_HasSpecialLinks,
NavMeshVis_TooSteep,
NavMeshVis_WaterSurface,
NavMeshVis_AudioProperties,
NavMeshVis_CoverDirections,
NavMeshVis_CarNodes,
NavMeshVis_Interior,
NavMeshVis_Isolated,
NavMeshVis_NetworkSpawnCandidates,
NavMeshVis_NoWander,
NavMeshVis_PavementCheckingMode,
NavMeshVis_NumModes
};
static const char * ms_pNavMeshVisModeTxt[NavMeshVis_NumModes];
static s32 m_iVisualiseNavMeshes;
static bool m_bVisualiseHierarchicalNodes;
static bool m_bVisualiseLinkWidths;
static bool m_bVisualisePaths;
static bool m_bVisualiseQuadTrees;
static bool m_bVisualiseAllCoverPoints;
static float m_fVisNavMeshVertexShiftAmount;
static int m_iVisualiseDataSet;
enum ePathServerVisMode
{
PathServerVis_Off,
PathServerVis_PathRequests,
PathServerVis_LineOfSightRequests,
PathServerVis_AudioRequests,
PathServerVis_FloodFillRequests,
PathServerVis_ClearAreaRequests,
PathServerVis_ClosestPositionRequests,
PathServerVis_Text,
PathServerVis_MemoryUsage,
PathServerVis_CurrentNavMesh,
PathServerVis_PolygonInfo,
PathServerVis_NumModes
};
static s32 m_iVisualisePathServerInfo;
static s32 m_iObjAvoidanceModeComboIndex;
#if __BANK
static bkCombo * ms_pObjAvoidanceModeCombo;
#endif // __BANK
static sysPerformanceTimer * m_RequestTimer;
static sysPerformanceTimer * m_PedGenTimer;
static sysPerformanceTimer * m_NewPedGenTimer;
static sysPerformanceTimer * m_MainGameThreadStallTimer;
static sysPerformanceTimer * m_MiscTimer;
static sysPerformanceTimer * m_ImmediateModeTimer;
static float m_fTimeTakenToIssueRequestsInMSecs;
static float m_fTimeTakenToAddRemoveUpdateObjects;
static float m_fTimeTakenToDoPedGenInMSecs;
static bool m_bDebugShowLowClimbOvers;
static bool m_bDebugShowHighClimbOvers;
static bool m_bDebugShowDropDowns;
static bool m_bDebugShowSpecialLinks;
static bool m_bDebugShowPolyVolumesAbove;
static bool m_bDebugShowPolyVolumesBelow;
static bool m_bVerifyAdjacencies;
static bool m_bRepeatPathQuery;
static bool ms_bUseXTraceOnTheNextPathRequest;
static s32 m_iSelectedPathRequest;
static s32 m_iSelectedLosRequest;
static bool ms_bOnlyDisplaySelectedRoute;
static bool ms_bShowSearchExtents;
// Toggles
static bool m_bDisableObjectAvoidance;
static bool m_bDisableAudioRequests;
static bool m_bDisableGetClosestPositionForPed;
static bool ms_bAllowObjectClimbing;
static bool ms_bAllowNavMeshClimbs;
static bool ms_bAllowObjectPushing;
// Stress-test pathfinding, by requesting 10 paths every frame
static bool m_bStressTestPathFinding;
static bool m_bStressTestGetClosestPos;
static bool m_bVisualisePolygonRequests;
static TPathHandle m_iStressTestPathHandles[NUM_STRESS_TEST_PATHS];
static int m_iDebugThreadRunMode;
static Vector3 ms_vPathTestStartPos;
static Vector3 ms_vPathTestEndPos;
static Vector3 ms_vPathTestCoverOrigin;
static Vector3 ms_vPathTestReferenceVector;
static float ms_fPathTestReferenceDist;
static float ms_fPathTestCompletionRadius;
static float ms_fPathTestEntityRadius;
static int ms_iPathTestNumInfluenceSpheres;
static TInfluenceSphere ms_PathTestInfluenceSpheres[MAX_NUM_INFLUENCE_SPHERES];
static float ms_fPathTestInfluenceSphereRadius;
static float ms_fPathTestInfluenceMin;
static float ms_fPathTestInfluenceMax;
static inline CPathRequest * GetPathRequest(s32 iIndex)
{
Assert(iIndex >= 0 && iIndex < MAX_NUM_PATH_REQUESTS);
return &m_PathRequests[iIndex];
}
static void SpewOutCoverAreasRequired();
#endif // !__FINAL
public:
static void RequestAndEvictNextFrame();
static bool IsModelIndexConsideredAnObstacle(u32 iModelIndex);
// A running total of the memory used by navmeshes *only*
// static s32 m_iTotalMemoryUsedByNavMeshes;
static inline CPathServerThread * GetPathServerThread(void) { return &m_PathServerThread; }
static u32 GetNavMeshIndexFromPosition(const Vector3 & vPos, aiNavDomain domain);
static u32 NavMeshIndexToNavNodesIndex(const TNavMeshIndex iNavMesh);
static u32 NavNodesIndexToNavMeshIndex(const TNavMeshIndex iNavNodes);
static CHierarchicalNavData * GetHierarchicalNavFromNavMeshIndex(const u32 index);
static u32 GetAdjacentNavMeshIndex(u32 iCurrentNavMeshIndex, eNavMeshEdge iDir, aiNavDomain domain);
static bool GetDoNavMeshesAdjoin(const u32 iNavMesh1, const u32 iNavMesh2, aiNavDomain domain);
static s32 GetNavMeshesIntersectingPosition(const Vector3 & vPos, float fRadius, TNavMeshIndex * pIndices, aiNavDomain domain);
static CNavMesh * FindClosestLoadedNavMeshToPosition(const Vector3 & vPos, aiNavDomain domain);
// Thread-safe function to tell whether a navmesh is loaded at a position
static bool IsNavMeshLoadedAtPosition(const Vector3 & vPos, aiNavDomain meshDataSet);
// This dynamic navmesh function is ONLY safe to be run from the main game thread
// static void UpdateDynamicNavMeshMatrix(CDynamicNavMeshEntry & entry);
#if __TRACK_PEDS_IN_NAVMESH
static void UpdateTrackedObject(CNavMeshTrackedObject & obj, const Vector3 & vObjectPos, const float rescanProbeLength = CNavMeshTrackedObject::DEFAULT_RESCAN_PROBE_LENGTH, bool in_bNeedsToReScan = false);
static bool TrackedObjectNeedsRescan(const CNavMeshTrackedObject& obj, const Vector3& vObjectPos);
#endif // __TRACK_PEDS_IN_NAVMESH
protected: // Was private, now protected, so CPathServerGta can access the internals.
// Cancels a pending/active/completed path request
static bool CancelRequestInternal(TPathHandle handle, bool bCancelledByClient);
static bool FlagDynamicObjectForRemoval(const TDynamicObjectIndex iDynObjIndex);
static bool TestPolyIntersectionAgainstObjectPlanes(const TDynamicObject * pObj, const TNavMeshPoly * pPoly, const Vector3 * pPolyVerts);
//*******************************************************************************************************
// Immediate-mode private pathfinding functions & members
static bool TestShortLineOfSightImmediateR(const Vector3 & vStartPos, const Vector3 & vEndPos, const TNavMeshPoly * pToPoly, TNavMeshPoly * pTestPoly, TNavMeshPoly * pLastPoly, aiNavDomain domain);
static CPathSearchPriorityQueue * m_pImmediateModePrioriryQueue;
static TNavMeshPoly * m_pImmediateModeVisitedPolys[IMMEDIATE_MODE_QUERY_MAXNUMVISITEDPOLYS];
static int m_iImmediateModeNumVisitedPolys;
static inline void ResetImmediateModeVisitedPolys()
{
for(int p=0; p<m_iImmediateModeNumVisitedPolys; p++)
{
Assert(m_pImmediateModeVisitedPolys[p]);
m_pImmediateModeVisitedPolys[p]->m_iImmediateModeFlags = 0;
}
m_iImmediateModeNumVisitedPolys = 0;
}
static int CreateInfluenceSpheresForPotentialExplosions(const Vector3 & vPathStart, TInfluenceSphere * influenceSpheres, const int iMaxNumInfluenceSpheres);
static int CreateInfluenceSpheresForTearGas(const Vector3 & vPathStart, TInfluenceSphere* influenceSpheres, const int iMaxNumInfluenceSpheres);
static void ValidateInfluenceSpheres(CPathRequest * pPathRequest);
static Vector3 m_vImmediateModeLosIsectPos;
static Vector3 m_vImmediateModeWanderOrigin;
static Vector3 m_vImmediateModeWanderDir;
static TTestLosStack m_ImmediateModeTestLosStack[SIZE_TEST_LOS_STACK];
static int m_iImmediateModeTestLosStackNumEntries;
static TNavMeshPoly * GetClosestNavMeshPolyImmediate(const Vector3 & vPos, const bool bMustHavePedDensityOrPavement, const bool bMustNotBeIsolated, const float fSearchRadius/*=8.0f*/, aiNavDomain domain);
static EGetClosestPosRet GetClosestPositionForPedNoLock(aiNavDomain domain, const Vector3 & vNearThisPosition, Vector3 & vecOut, const float fMaxSearchRadius, const u32 iFlags, const int iNumAvoidSpheres=0, const spdSphere * pAvoidSpheresArray=NULL);
static EGetClosestPosRet FloodFillForClosestPosition(const Vector3 & vNearThisPosition, Vector3 & vecOut, const float fMaxSearchRadius, const u32 iFlags, const int iNumAvoidSpheres, const spdSphere * pAvoidSpheresArray, aiNavDomain domain);
static void FloodFillForClosestPositionNonRecursive(aiNavDomain domain);
#if __TRACK_PEDS_IN_NAVMESH
static Vector3 UpdateTrackedObjectConstrainedToNavMesh(const Vector3 & vLastPos, const Vector3 & vMoveSpeed, CNavMeshTrackedObject & obj);
#endif
static void ModifyMovementCosts(CPathFindMovementCosts* pMovementCosts, bool bWander, bool bFlee);
#ifdef GTA_ENGINE
static void MaybeExtractCoverPointsFromNavMeshes(void);
static void ExtractCoverPoints_StartNewTimeslice(const Vector3 & vOrigin, float fMaxDistance);
static void ExtractCoverPoints_ContinueTimeslice(const Vector3 & vOrigin, float fMaxDistance);
static bool ExtractCoverPointsFromQuadtree(CNavMeshQuadTree * pTree, const Vector3 & vMin, const Vector3 & vMax, const Vector3 & vNavMeshMin, const Vector3 & vNavMeshSize);
// These members are used to timeslice the algorithm which extracts coverpoints from the navmeshes.
static bool m_bFindCover_CompletedTimeslice;
static TNavMeshIndex m_iFindCover_CurrentlyExtractingNavMeshIndex; // used for calculating coverpoint UIDS
static CNavMesh * m_pFindCoverCurrentNavMesh;
static TNavMeshIndex m_iFindCover_NavMeshesIndices[MAX_NUM_NAVMESHES_FOR_COVERAREAS];
static u32 m_iFindCover_NumNavMeshesIndices;
static u32 m_iFindCover_NavMeshProgress;
static u32 m_iFindCover_NavMeshPolyProgress;
static CNavMeshQuadTree * m_pFindCover_ContinueFromThisQuadTreeLeaf;
static u32 m_iFindCover_NumIterationsRemainingThisTimeslice;
static u32 m_iFindCover_NumIterationsPerTimeslice;
// Nice catchy name! What this function does is convert the 3-bit value stored in every
// TLinkedCoverPoint structure, into the index of an adjacent navmesh.
static inline TNavMeshIndex GetNavMeshIndexFromCoverPointAdjNavMeshCode(aiNavDomain domain, TNavMeshIndex iNavMesh, u32 iAdjCode)
{
switch(iAdjCode)
{
case 1 : { return iNavMesh; }
case 2 : { return iNavMesh + m_pNavMeshStores[domain]->GetNumMeshesInX(); }
case 3 : { return iNavMesh - m_pNavMeshStores[domain]->GetNumMeshesInX(); }
case 4 : { return iNavMesh + 1; }
case 5 : { return iNavMesh - 1; }
}
Assert(0);
return NAVMESH_NAVMESH_INDEX_NONE;
}
// How often to run the cover-points extraction code
static u32 m_iFrequencyOfCoverPointTimeslices_Millisecs;
// The last time at which we ran the cover-points extraction code
static u32 m_iTimeOfLastCoverPointTimeslice_Millisecs;
static u32 m_iFrequencyOfWaterEdgeExtraction_Millisecs;
static u32 m_iTimeOfLastWaterEdgeTimeslice_Millisecs;
// A local buffer is maintained, into which the CNavMeshCoverPoint's are placed. The CCover class
// then calls the AddCoverPoints() function, which can traverse this list. In this way we can
// avoid stalling the main game loop when coverpoints need to be added from navmeshes.
static bool m_bCoverPointsBufferInUse;
static s32 m_iNumCoverPointsInBuffer;
static TCachedCoverPoint m_CoverPointsBuffer[SIZE_OF_COVERPOINTS_BUFFER];
static CCoverBoundingArea m_CoverBoundingAreas[CCover::MAX_BOUNDING_AREAS];
static u32 m_iCoverNumberAreas;
static bool m_bWaterEdgesBufferInUse;
static bool m_bExtractWaterEdgesThisTimeslice;
static s32 m_iNumWaterEdgesInBuffer;
static const float ms_fMinDistSqrBetweenWaterEdgePoints;
static const float ms_fFindWaterEdgesMaxDist;
static TShortMinMax m_FindWaterEdgesMinMax;
static Vector3 m_vFindWaterEdgesOrigin;
static Vector3 m_vFindWaterEdgesLastOrigin;
static Vector3 m_vFindWaterEdgesMin;
static Vector3 m_vFindWaterEdgesMax;
static Vector3 m_WaterEdgesBuffer[SIZE_OF_WATEREDGES_BUFFER];
static u32 m_WaterEdgeAudioProperties[SIZE_OF_WATEREDGES_BUFFER];
// Add a point to the buffer, testing tolerance
static bool AddWaterEdgeToBuffer(const Vector3 & vMidEdge, u32 iAudioProperties);
// Clear out any points which are now outside of the max range
static void ClearWaterEdges();
#if !__FINAL
static sysPerformanceTimer * m_ExtractCoverPointsTimer;
static float m_fLastTimeTakenToExtractCoverPointsMs;
static sysPerformanceTimer * m_TrackObjectsTimer;
static float m_fTimeToLockDataForTracking;
static float m_fTimeToTrackAllPeds;
#endif
#endif // GTA_ENGINE
//************************************************************
// Statics to help with ped-generation recursive calls
//************************************************************
static float ms_fPedGenAlgorithmNodeFloodFillDist;
#if !__FINAL
#if SANITY_CHECK_TESSELLATION
static void SanityCheckPolyConnectionsForAllNavMeshes(void);
#endif
#endif
static void RequestAndEvictMeshes();
static int ms_iRequestAndEvictMeshesFreqMs;
static int m_iTimeOfLastRequestAndEvictMeshes;
static bool ms_bRunningRequestAndEvictMeshes;
#ifdef GTA_ENGINE
static void PrepareToUnloadNavMeshDataSetNormal(void * pNavMesh);
static void PrepareToUnloadNavMeshDataSetHeightMesh(void * pNavMesh);
static void PrepareToUnloadHierarchicalNavData(void * pNavData);
#endif
//*****************************************************************
// Loaders for different types of streamed data/platforms
//*****************************************************************
// Origin around which nav-mesh streaming takes place. Usually the player's position.
static Vector3 m_vOrigin;
// The origin during the previous frame
static Vector3 m_vLastOrigin;
//********************************************************************************
// Ped Generation
// The following variables are used for finding coordinates to create new peds,
// when done as an asynchronous 'housekeeping' task once every few seconds.
#ifdef GTA_ENGINE
static u32 m_iLastTimeProcessedPedGeneration;
static dev_u32 m_iProcessPedGenerationFreq;
static CPathServerAmbientPedGen m_AmbientPedGeneration;
static CPathServerOpponentPedGen m_OpponentPedGeneration;
#if !__FINAL
public:
static bool ms_bDrawPedGenBlockingAreas;
static bool ms_bVisualiseOpponentPedGeneration;
static void DebugDrawPedGenBlockingAreas();
static void ClearAllPathHistory();
static void ClearAllOpenClosedFlags();
static void DebugDetessellateNow();
#endif
#endif // GTA_ENGINE
// PURPOSE: Pointer to an interface object for game-specific extensions.
// NOTE: This is set by Init(), and is not considered owned by CPathServer.
static const fwPathServerGameInterface* m_GameInterface;
// This should never reach zero, since area 0 is always reserved for the player origin
//static s32 m_iNavMeshNumRequiredRegions;
// The origins & radii of the areas which needed navmeshes (the player origin is always area zero)
static TNavMeshRequiredRegion m_NavMeshRequiredRegions[NAVMESH_MAX_REQUIRED_REGIONS];
// Whether the CPathServer system is running single or multi-threaded.
static EProcessingMode m_eProcessingMode;
// The distance at which navmeshes are loaded
static float m_fNavMeshLoadProximity;
// The distance at which the hierarchical nodes are loaded
static float m_fHierarchicalNodesLoadProximity;
// Navmeshes to cover the entire game map
// static aiNavMeshStore m_StaticNavMeshStore;
#if __HIERARCHICAL_NODES_ENABLED
static aiNavNodesStore * m_pNavNodesStore;
#endif
static int m_iNumDynamicNavMeshesInExistence;
// How frequently the CPathServerThread should attempt to untessellate navmesh polygons
static u32 m_iThreadHousekeepingFrequencyInMillisecs;
static u32 m_iLastTimeThreadDidHousekeeping;
static u32 m_iLastTimeCheckedForStaleRequests;
static u32 m_iCheckForStaleRequestsFreq;
// Whether to explicitly sleep the pathfinding thread, maybe not necessary for multi-core setups
static bool m_bSleepPathServerThreadOnLongPathRequests;
// Number of iterations within FindPath() to perform before sleeping (if this feature is enabled)
static u32 m_iNumFindPathIterationsBetweenSleepChecks;
// How long to sleep for between checking for new pending path requests
static bank_u32 m_iTimeToSleepWaitingForRequestsMs;
static bank_u32 m_iTimeToSleepDuringLongRequestsMs;
#if !__FINAL
// A debug variable, so we know how many tessellations have occurred for each path request
static u32 ms_iNumTessellationsThisPath;
static u32 ms_iNumTestDynamicObjectLOS;
static u32 ms_iNumTestNavMeshLOS;
static u32 ms_iNumImmediateTestNavMeshLOS;
static u32 ms_iNumGetObjectsIntersectingRegion;
static u32 ms_iNumCacheHitsOnDynamicObjects;
static float m_fRunningTotalOfTimeOnPathRequests;
static float m_fTimeSpentProcessingThisGameTurn;
#endif
static bool ms_bLoadAllHierarchicalData;
static CPathRequest m_PathRequests[MAX_NUM_PATH_REQUESTS];
static CGridRequest m_GridRequests[MAX_NUM_GRID_REQUESTS];
static CLineOfSightRequest m_LineOfSightRequests[MAX_NUM_LOS_REQUESTS];
static CAudioRequest m_AudioRequests[MAX_NUM_AUDIO_REQUESTS];
static CFloodFillRequest m_FloodFillRequests[MAX_NUM_FLOODFILL_REQUESTS];
static CClearAreaRequest m_ClearAreaRequests[MAX_NUM_CLEARAREA_REQUESTS];
static CClosestPositionRequest m_ClosestPositionRequests[MAX_NUM_CLOSESTPOSITION_REQUESTS];
static u32 m_iNextHandle;
static u32 m_iNextPathIndexToStartFrom;
static u32 m_iNextGridIndexToStartFrom;
static u32 m_iNextLosIndexToStartFrom;
static u32 m_iNextAudioIndexToStartFrom;
static u32 m_iNextFloodFillIndexToStartFrom;
static u32 m_iNextClearAreaIndexToStartFrom;
static u32 m_iNextClosestPositionIndexToStartFrom;
static u32 m_iNumDynamicObjects;
static void SwitchNavMeshInArea(const Vector3 & vMin, const Vector3 & vMax, ESWITCH_NAVMESH_POLYS eSwitch, scrThreadId iScriptUID);
static void ApplyPedAreaSwitchesToNewlyLoadedNavNodes(CHierarchicalNavData * pNavNodes);
public:
static s32 GetNumPathRegionSwitches() { return m_iNumPathRegionSwitches; }
static const TPathRegionSwitch & GetPathRegionSwitch(s32 i) { return m_PathRegionSwitches[i]; }
protected:
static s32 m_iNumPathRegionSwitches;
static TPathRegionSwitch m_PathRegionSwitches[MAX_NUM_PATH_REGION_SWITCHES];
public:
#if !__FINAL
static bool ms_bDrawPedSwitchAreas;
static void DebugDrawPedSwitchAreas();
#endif
static void ProcessAddDeferredDynamicObjects();
static s32 EvictDynamicObjectForScript();
// Dynamic objects added from script are added to a list, and added to the pathfinder at a safe point in the frame
// This is to workaround issues of locking objects/navmeshes in order to evict less important objects.
static s32 m_iNumDeferredAddDynamicObjects;
static s32 m_iNextScriptObjectHandle;
static s32 m_iNumScriptBlockingObjects;
static TScriptDeferredAddDynamicObject m_ScriptDeferredAddDynamicObjects[TScriptDeferredAddDynamicObject::ms_iMaxNum];
static TScriptObjHandlePair m_ScriptedDynamicObjects[MAX_NUM_SCRIPTED_DYNAMIC_OBJECTS];
// This member mainatins the worker thread which does the path processing
static CPathServerThread m_PathServerThread;
static bool ms_bUseEventsForRequests;
static bool ms_bProcessAllPendingPathsAtOnce;
static u32 m_iNumTimesGaveTime;
static bool ms_bCurrentlyRemovingAndAddingObjects;
// The total amount of memory used by the precalc'd paths (aka edge groups), use for hierarchical pathfinding
static s32 m_iTotalMemoryUsedByPrecalcPaths;
// How many times the game (or the main worker thread) had to stall waiting for access to shared resources
// (ie. the navmeshes or the dynamic objects).
// NB : Don't know if we can get this info now we're using semaphores instead of spinlocks..
static bool m_bDisplayTimeTakenToAddDynamicObjects;
// Audio parameters
static f32 m_fAudioVelocityDotProduct;
static f32 m_fAudioVelocityCubeSize;
static f32 m_fAudioMinPolySizeForRadiusSearch;
#ifdef GTA_ENGINE
#if __BANK
static bool m_bCheckForThreadStalls;
static u32 m_iNumThreadStallsForNavMeshes;
static u32 m_iNumThreadStallsForDynamicObjects;
static u32 m_iNumTimesCouldntUpdateObjectsDueToGameThreadAccess;
static float m_fMainGameTimeSpendOnThreadStalls;
static float m_fPedGenTimeToObtainCriticalSection;
static float m_fPedGenTimeToDoAlgorithm;
static float m_fPedGenTimeToReleaseCriticalSection;
static s32 m_iNumImmediateModeLosCallsThisFrame;
static s32 m_iNumImmediateModeWanderPathsThisFrame;
static s32 m_iNumImmediateModeFleePathsThisFrame;
static s32 m_iNumImmediateModeSeekPathsThisFrame;
static float m_fTimeSpentOnImmediateModeCallsThisFrame;
static inline void CheckForThreadStall(sysCriticalSectionToken & cst)
{
if(cst.TryLock())
{
cst.Unlock();
}
else
{
// Must remember to update this section for all the critical section we may be using
if(&cst==&m_NavMeshDataCriticalSectionToken) m_iNumThreadStallsForNavMeshes++;
else if(&cst==&m_NavMeshImmediateAccessCriticalSectionToken) m_iNumThreadStallsForNavMeshes++;
else if(&cst==&m_DynamicObjectsCriticalSectionToken) m_iNumThreadStallsForDynamicObjects++;
}
}
#endif
#endif
};
#ifdef GTA_ENGINE
#define GTA_ENGINE_ONLY(x) x
#else
#define GTA_ENGINE_ONLY(x)
#endif
//extern CPathServer g_PathServer;
#if __BANK
#ifndef __TOOL
extern void PathServer_AddWidgets(bkBank & bank);
#endif //__TOOL
#endif //__BANK
struct TFloodFillForClosest
{
CNavMesh * pNavMesh; // the current navmesh
TNavMeshPoly * pPoly; // the current poly
};
class CFire;
struct TPotentialExplosion
{
CFire * pFire;
float fDistSqr;
};
struct TGasCloud
{
Vec3V worldPos;
float fDistSqr;
};
// How many potential positions to choose for catmull-rom control points
#define PATHSPLINE_NUM_TEST_DISTANCES 4
// The distances from adjacent waypoints towards the corner-point, for vCtrlPt2 and vCtrlPt3
extern const float g_fPathSplineDists[PATHSPLINE_NUM_TEST_DISTANCES];
// The magnitude that the outer control pts are pulled back (scales the length of the line-seg)
extern const float g_fOuterCtrlPtDists[PATHSPLINE_NUM_TEST_DISTANCES];
// The number of subdivisions used when testing the spline against the navmesh (crude approximation of final realtime curve)
#define PATHSPLINE_NUM_TEST_SUBDIVISIONS 4
inline void CalcPathSplineCtrlPts(
const int iSplineEnum, const float fCtrlPt2TValOverride,
const Vector3 & vLast, const Vector3 & vNext,
const Vector3 & vLastToCurrent, const Vector3 & vCurrentToNext,
Vector3 & vCtrlPt1, Vector3 & vCtrlPt2, Vector3 & vCtrlPt3, Vector3 & vCtrlPt4)
{
Assert(iSplineEnum >= 0 && iSplineEnum<PATHSPLINE_NUM_TEST_DISTANCES);
if(fCtrlPt2TValOverride != 0.0f)
vCtrlPt2 = vLast + (vLastToCurrent * fCtrlPt2TValOverride);
else
vCtrlPt2 = vLast + (vLastToCurrent * g_fPathSplineDists[iSplineEnum]);
vCtrlPt1 = vCtrlPt2 - (vLastToCurrent * g_fOuterCtrlPtDists[iSplineEnum]);
vCtrlPt3 = vNext - (vCurrentToNext * g_fPathSplineDists[iSplineEnum]);
vCtrlPt4 = vCtrlPt3 + (vCurrentToNext * g_fOuterCtrlPtDists[iSplineEnum]);
}
inline void CalcPathSplineCtrlPtsV(
const int iSplineEnum, ScalarV_In vCtrlPt2TValOverride,
Vec3V_In vLast, Vec3V_In vNext,
Vec3V_In vLastToCurrent, Vec3V_In vCurrentToNext,
Vec3V_InOut vCtrlPt1, Vec3V_InOut vCtrlPt2, Vec3V_InOut vCtrlPt3, Vec3V_InOut vCtrlPt4)
{
Assert(iSplineEnum >= 0 && iSplineEnum<PATHSPLINE_NUM_TEST_DISTANCES);
const ScalarV pathSplineDistV = LoadScalar32IntoScalarV(g_fPathSplineDists[iSplineEnum]);
const ScalarV outerCtrlPtDistsV = LoadScalar32IntoScalarV(g_fOuterCtrlPtDists[iSplineEnum]);
const ScalarV tV = SelectFT(IsEqual(vCtrlPt2TValOverride, ScalarV(V_ZERO)), vCtrlPt2TValOverride, pathSplineDistV);
const Vec3V pt2V = AddScaled(vLast, vLastToCurrent, tV);
const Vec3V pt1V = SubtractScaled(pt2V, vLastToCurrent, outerCtrlPtDistsV);
const Vec3V pt3V = SubtractScaled(vNext, vCurrentToNext, pathSplineDistV);;
const Vec3V pt4V = AddScaled(pt3V, vCurrentToNext, outerCtrlPtDistsV);;
vCtrlPt1 = pt1V;
vCtrlPt2 = pt2V;
vCtrlPt3 = pt3V;
vCtrlPt4 = pt4V;
}
inline Vector3 PathSpline(const Vector3 & vCtrlPt1, const Vector3 & vCtrlPt2, const Vector3 & vCtrlPt3, const Vector3 & vCtrlPt4, const float u)
{
const Vector3 vTargetAfterSlide =
vCtrlPt1 * (-0.5f*u*u*u + u*u - 0.5f*u) +
vCtrlPt2 * (1.5f*u*u*u + -2.5f*u*u + 1.0f) +
vCtrlPt3 * (-1.5f*u*u*u + 2.0f*u*u + 0.5f*u) +
vCtrlPt4 * (0.5f*u*u*u - 0.5f*u*u);
return vTargetAfterSlide;
}
//-----------------------------------------------------------------------------
class CBaseModelInfo;
class CFire;
class CCarDoor;
/*
PURPOSE
CPathServerGta now holds some functions that depend on code that we may not
want to move to the RAGE framework, such as CEntity and CFire.
TODO
To continue moving code to RAGE, the CPathServer class (already mostly free
from GTA dependencies) should probably be merged with fwPathServerBase, and
renamed fwPathServer. Then, CPathServerGta here can be renamed back to
CPathServer.
*/
class CPathServerGta : public CPathServer
{
friend class CNavGenApp;
public:
//*****************************************************************************************
// CPopulation will call these functions when objects are converted to/from dummies.
// Not all objects & entities are added, only those which pose significant obstructions.
static bool MaybeAddDynamicObject(CEntity * pEntity);
static void MaybeRemoveDynamicObject(CEntity * pEntity);
static bool AddFireObject(CFire * pFire);
static bool RemoveFireObject(const CFire * pFire);
static bool RemoveVehicleDoorObject(const CCarDoor * pDoor);
static s32 AddScriptedBlockingObject(const scrThreadId iThreadId, const Vector3 & vPosition, const Vector3 & vSize, const float fHeading, const s32 iBlockingFlags=TDynamicObject::BLOCKINGOBJECT_ALL_PATH_TYPES);
static bool UpdateScriptedBlockingObject(const scrThreadId iThreadId, const s32 iObjHandle, const Vector3 & vPosition, const Vector3 & vSize, const float fHeading, const s32 iBlockingFlags=TDynamicObject::BLOCKINGOBJECT_ALL_PATH_TYPES);
static bool RemoveScriptedBlockingObject(const scrThreadId iThreadId, s32 iObjIndex);
static void RemoveAllBlockingObjectsForScript(const scrThreadId iThreadId);
static bool DoesScriptedBlockingObjectExist(const scrThreadId iThreadId, const s32 iObjHandle);
// Constructor/destructor for some entities will call these two functions (eg. boats)
static bool MaybeRequestDynamicObjectNavMesh(CEntity * pEntity);
static bool MaybeRemoveDynamicObjectNavMesh(CEntity * pEntity);
static bool SetUpDynamicNavMeshInstance(CDynamicNavMeshEntry & newEntry, TNavMeshIndex iIndexOfNewNavmesh, CNavMesh * pBackedUpCopy, CVehicle * pVehicle);
// Called every frame for moving objects. We have to check whether the object has moved enough to need recalculating its bounds, etc
static void UpdateDynamicObject(CEntity * pEntity, bool bForceUpdate=false, bool bForceActivate=false);
static void UpdateFireObject(CFire * pFire);
static void UpdateVehicleDoorsDynamicObjects(CVehicle * pVehicle, const bool bForceUpdate=false);
static void UpdateVehicleDoorDynamicObject(CVehicle * pVehicle, CCarDoor * pDoor, const bool bForceUpdate=false);
static void AddVehicleDoorDynamicObject(CVehicle * pVehicle, CCarDoor * pDoor);
// Finds a safe position for a ped on a dynamic navmesh associated with the given entity.
// Input & output positions are in worldspace, although internal calculations are done locally to the entity.
static EGetClosestPosRet GetClosestPositionForPedOnDynamicNavmesh(CEntity * pEntity, const Vector3 & vNearThisPosition, const float fMaxSearchRadius, Vector3 & vOut);
static bool ShouldAvoidObject(const CEntity* pEntity);
static bool ShouldPedAvoidObject(const class CPed* pPed, const CEntity* pEntity);
static bool IsObjectSignificant(const CEntity* pEntity);
static bool SpecialCaseShouldAvoidFragmentObject(CObject * pObj); // HACK_GTAV
static bool SpecialCaseDontRemoveSmashedGlass(CObject * pObj); // HACK_GTAV
protected:
static bool AddDynamicObject(CEntity * pEntity, CBaseModelInfo * pModelInfo);
static void AddVehicleDoorsDynamicObjects(CVehicle * pVehicle);
};
#ifdef GTA_ENGINE
// TODO: Move this elsewhere. /FF
/*
PURPOSE
Interface to extend CPathServer with some features of the GTA engine.
*/
class CPathServerGameInterfaceGta : public fwPathServerGameInterface
{
public:
virtual void OverridePathRequestParameters(const TRequestPathStruct& reqStruct, CPathRequest& pathRequest) const;
protected:
// Helper function, used to be CPathFindMovementCosts::SetFromPed().
static void SetPathFindMovementCostsFromPed(CPathFindMovementCosts& costsOut, const CPed * pPed);
};
#endif // GTA_ENGINE
//-----------------------------------------------------------------------------
/*
PURPOSE
Loose functions that used to be member functions of TDynObjBounds. They got moved out
to facilitate TDynObjBounds moving down to the RAGE level, without having to bring
CEntity/CFire/CVehicle dependencies with it.
*/
namespace TDynObjBoundsFuncs
{
void CalcBoundsForEntity(TDynObjBounds &bnds, CEntity * pEntity, TDynamicObject * pDynObj);
void CalcBoundsForFire(TDynObjBounds &bnds, CFire * pFire, TDynamicObject * pDynObj);
bool CalcBoundsForVehicleDoor(TDynObjBounds& bnds, CCarDoor * pDoor, CVehicle * pParent, const Matrix34 & doorMat, TDynamicObject * pDynObj);
void CalcBoundsForBlockingObject(TDynObjBounds& bnds, const Vector3 & vPos, const Vector3 & vSize, const float fRotation, TDynamicObject * pDynObj);
#ifdef GTA_ENGINE
int GetDoorComponents(const CVehicle * pVehicle, int * iComponents, const s32 iMaxNum);
int GetHeliIgnoreComponents(const CVehicle * pVehicle, int * iComponents, const s32 iMaxNum);
s32 GetIgnoreComponentsForEntity(const CEntity * pEntity, s32 * pOut_ComponentsArray, const s32 iMaxNum);
#endif
}
#endif // PATHSERVER_H