Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1069 lines
42 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // nav_mesh.h
  9. // The Navigation Mesh interface
  10. // Author: Michael S. Booth ([email protected]), January 2003
  11. //
  12. // Author: Michael S. Booth ([email protected]), 2003
  13. //
  14. // NOTE: The Navigation code uses Doxygen-style comments. If you run Doxygen over this code, it will
  15. // auto-generate documentation. Visit www.doxygen.org to download the system for free.
  16. //
  17. #ifndef _NAV_MESH_H_
  18. #define _NAV_MESH_H_
  19. #include "utlbuffer.h"
  20. #include "filesystem.h"
  21. #include "GameEventListener.h"
  22. #include "nav.h"
  23. #include "nav_area.h"
  24. #include "nav_colors.h"
  25. class CNavArea;
  26. class CBaseEntity;
  27. class CBreakable;
  28. extern ConVar nav_edit;
  29. extern ConVar nav_quicksave;
  30. extern ConVar nav_show_approach_points;
  31. extern ConVar nav_show_danger;
  32. //--------------------------------------------------------------------------------------------------------
  33. class NavAreaCollector
  34. {
  35. bool m_checkForDuplicates;
  36. public:
  37. NavAreaCollector( bool checkForDuplicates = false )
  38. {
  39. m_checkForDuplicates = checkForDuplicates;
  40. }
  41. bool operator() ( CNavArea *area )
  42. {
  43. if ( m_checkForDuplicates && m_area.HasElement( area ) )
  44. return true;
  45. m_area.AddToTail( area );
  46. return true;
  47. }
  48. CUtlVector< CNavArea * > m_area;
  49. };
  50. //--------------------------------------------------------------------------------------------------------
  51. class EditDestroyNotification
  52. {
  53. CNavArea *m_deadArea;
  54. public:
  55. EditDestroyNotification( CNavArea *deadArea )
  56. {
  57. m_deadArea = deadArea;
  58. }
  59. bool operator()( CBaseCombatCharacter *actor )
  60. {
  61. actor->OnNavAreaRemoved( m_deadArea );
  62. return true;
  63. }
  64. };
  65. //--------------------------------------------------------------------------------------------------------
  66. class NavAttributeClearer
  67. {
  68. public:
  69. NavAttributeClearer( NavAttributeType attribute )
  70. {
  71. m_attribute = attribute;
  72. }
  73. bool operator() ( CNavArea *area )
  74. {
  75. area->SetAttributes( area->GetAttributes() & (~m_attribute) );
  76. return true;
  77. }
  78. NavAttributeType m_attribute;
  79. };
  80. //--------------------------------------------------------------------------------------------------------
  81. class NavAttributeSetter
  82. {
  83. public:
  84. NavAttributeSetter( NavAttributeType attribute )
  85. {
  86. m_attribute = attribute;
  87. }
  88. bool operator() ( CNavArea *area )
  89. {
  90. area->SetAttributes( area->GetAttributes() | m_attribute );
  91. return true;
  92. }
  93. NavAttributeType m_attribute;
  94. };
  95. //--------------------------------------------------------------------------------------------------------
  96. class NavAttributeToggler
  97. {
  98. public:
  99. NavAttributeToggler( NavAttributeType attribute )
  100. {
  101. m_attribute = attribute;
  102. }
  103. bool operator() ( CNavArea *area );
  104. NavAttributeType m_attribute;
  105. };
  106. //--------------------------------------------------------------------------------------------------------
  107. struct NavAttributeLookup
  108. {
  109. const char *name;
  110. NavAttributeType attribute;
  111. };
  112. extern NavAttributeLookup TheNavAttributeTable[];
  113. //--------------------------------------------------------------------------------------------------------
  114. class SelectOverlappingAreas
  115. {
  116. public:
  117. bool operator()( CNavArea *area );
  118. };
  119. //--------------------------------------------------------------------------------------------------------
  120. abstract_class INavAvoidanceObstacle
  121. {
  122. public:
  123. virtual bool IsPotentiallyAbleToObstructNavAreas( void ) const = 0; // could we at some future time obstruct nav?
  124. virtual float GetNavObstructionHeight( void ) const = 0; // height at which to obstruct nav areas
  125. virtual bool CanObstructNavAreas( void ) const = 0; // can we obstruct nav right this instant?
  126. virtual CBaseEntity *GetObstructingEntity( void ) = 0;
  127. virtual void OnNavMeshLoaded( void ) = 0;
  128. };
  129. //--------------------------------------------------------------------------------------------------------
  130. enum GetNavAreaFlags_t
  131. {
  132. GETNAVAREA_CHECK_LOS = 0x1,
  133. GETNAVAREA_ALLOW_BLOCKED_AREAS = 0x2,
  134. GETNAVAREA_CHECK_GROUND = 0x4,
  135. };
  136. //--------------------------------------------------------------------------------------------------------
  137. // for nav mesh visibilty computation
  138. struct NavVisPair_t
  139. {
  140. void SetPair( CNavArea *pArea1, CNavArea *pArea2 )
  141. {
  142. int iArea1 = (int)( pArea1 > pArea2 );
  143. int iArea2 = ( iArea1 + 1 ) % 2;
  144. pAreas[iArea1] = pArea1;
  145. pAreas[iArea2] = pArea2;
  146. }
  147. CNavArea *pAreas[2];
  148. };
  149. // for nav mesh visibilty computation
  150. class CVisPairHashFuncs
  151. {
  152. public:
  153. CVisPairHashFuncs( int ) {}
  154. bool operator()( const NavVisPair_t &lhs, const NavVisPair_t &rhs ) const
  155. {
  156. return ( lhs.pAreas[0] == rhs.pAreas[0] && lhs.pAreas[1] == rhs.pAreas[1] );
  157. }
  158. unsigned int operator()( const NavVisPair_t &item ) const
  159. {
  160. COMPILE_TIME_ASSERT( sizeof(CNavArea *) == sizeof( intp ) );
  161. intp key[2] = { (intp)item.pAreas[0] + item.pAreas[1]->GetID(), (intp)item.pAreas[1] + item.pAreas[0]->GetID() };
  162. if ( sizeof( key ) >= 16 )
  163. {
  164. return Hash16( key );
  165. }
  166. else
  167. {
  168. return Hash8( key );
  169. }
  170. }
  171. };
  172. //--------------------------------------------------------------------------------------------------------------
  173. //
  174. // The 'place directory' is used to save and load places from
  175. // nav files in a size-efficient manner that also allows for the
  176. // order of the place ID's to change without invalidating the
  177. // nav files.
  178. //
  179. // The place directory is stored in the nav file as a list of
  180. // place name strings. Each nav area then contains an index
  181. // into that directory, or zero if no place has been assigned to
  182. // that area.
  183. //
  184. class PlaceDirectory
  185. {
  186. public:
  187. typedef unsigned short IndexType; // Loaded/Saved as UnsignedShort. Change this and you'll have to version.
  188. PlaceDirectory( void );
  189. void Reset( void );
  190. bool IsKnown( Place place ) const; /// return true if this place is already in the directory
  191. IndexType GetIndex( Place place ) const; /// return the directory index corresponding to this Place (0 = no entry)
  192. void AddPlace( Place place ); /// add the place to the directory if not already known
  193. Place IndexToPlace( IndexType entry ) const; /// given an index, return the Place
  194. void Save( CUtlBuffer &fileBuffer ); /// store the directory
  195. void Load( CUtlBuffer &fileBuffer, int version ); /// load the directory
  196. const CUtlVector< Place > *GetPlaces( void ) const
  197. {
  198. return &m_directory;
  199. }
  200. bool HasUnnamedPlaces( void ) const
  201. {
  202. return m_hasUnnamedAreas;
  203. }
  204. private:
  205. CUtlVector< Place > m_directory;
  206. bool m_hasUnnamedAreas;
  207. };
  208. extern PlaceDirectory placeDirectory;
  209. //--------------------------------------------------------------------------------------------------------
  210. /**
  211. * The CNavMesh is the global interface to the Navigation Mesh.
  212. * @todo Make this an abstract base class interface, and derive mod-specific implementations.
  213. */
  214. class CNavMesh : public CGameEventListener
  215. {
  216. public:
  217. CNavMesh( void );
  218. virtual ~CNavMesh();
  219. virtual void PreLoadAreas( int nAreas ) {}
  220. virtual CNavArea *CreateArea( void ) const; // CNavArea factory
  221. virtual void DestroyArea( CNavArea * ) const;
  222. virtual HidingSpot *CreateHidingSpot( void ) const; // Hiding Spot factory
  223. virtual void Reset( void ); // destroy Navigation Mesh data and revert to initial state
  224. virtual void Update( void ); // invoked on each game frame
  225. virtual void FireGameEvent( IGameEvent *event ); // incoming event processing
  226. virtual NavErrorType Load( void ); // load navigation data from a file
  227. virtual NavErrorType PostLoad( unsigned int version ); // (EXTEND) invoked after all areas have been loaded - for pointer binding, etc
  228. bool IsLoaded( void ) const { return m_isLoaded; } // return true if a Navigation Mesh has been loaded
  229. bool IsAnalyzed( void ) const { return m_isAnalyzed; } // return true if a Navigation Mesh has been analyzed
  230. /**
  231. * Return true if nav mesh can be trusted for all climbing/jumping decisions because game environment is fairly simple.
  232. * Authoritative meshes mean path followers can skip CPU intensive realtime scanning of unpredictable geometry.
  233. */
  234. virtual bool IsAuthoritative( void ) const { return false; }
  235. const CUtlVector< Place > *GetPlacesFromNavFile( bool *hasUnnamedPlaces ); // Reads the used place names from the nav file (can be used to selectively precache before the nav is loaded)
  236. virtual bool Save( void ) const; // store Navigation Mesh to a file
  237. bool IsOutOfDate( void ) const { return m_isOutOfDate; } // return true if the Navigation Mesh is older than the current map version
  238. virtual unsigned int GetSubVersionNumber( void ) const; // returns sub-version number of data format used by derived classes
  239. virtual void SaveCustomData( CUtlBuffer &fileBuffer ) const { } // store custom mesh data for derived classes
  240. virtual void LoadCustomData( CUtlBuffer &fileBuffer, unsigned int subVersion ) { } // load custom mesh data for derived classes
  241. virtual void SaveCustomDataPreArea( CUtlBuffer &fileBuffer ) const { } // store custom mesh data for derived classes that needs to be loaded before areas are read in
  242. virtual void LoadCustomDataPreArea( CUtlBuffer &fileBuffer, unsigned int subVersion ) { } // load custom mesh data for derived classes that needs to be loaded before areas are read in
  243. // events
  244. virtual void OnServerActivate( void ); // (EXTEND) invoked when server loads a new map
  245. virtual void OnRoundRestart( void ); // invoked when a game round restarts
  246. virtual void OnRoundRestartPreEntity( void ); // invoked when a game round restarts, but before entities are deleted and recreated
  247. virtual void OnBreakableCreated( CBaseEntity *breakable ) { } // invoked when a breakable is created
  248. virtual void OnBreakableBroken( CBaseEntity *broken ) { } // invoked when a breakable is broken
  249. virtual void OnAreaBlocked( CNavArea *area ); // invoked when the area becomes blocked
  250. virtual void OnAreaUnblocked( CNavArea *area ); // invoked when the area becomes un-blocked
  251. virtual void OnAvoidanceObstacleEnteredArea( CNavArea *area ); // invoked when the area becomes obstructed
  252. virtual void OnAvoidanceObstacleLeftArea( CNavArea *area ); // invoked when the area becomes un-obstructed
  253. virtual void OnEditCreateNotify( CNavArea *newArea ); // invoked when given area has just been added to the mesh in edit mode
  254. virtual void OnEditDestroyNotify( CNavArea *deadArea ); // invoked when given area has just been deleted from the mesh in edit mode
  255. virtual void OnEditDestroyNotify( CNavLadder *deadLadder ); // invoked when given ladder has just been deleted from the mesh in edit mode
  256. virtual void OnNodeAdded( CNavNode *node ) {};
  257. // Obstructions
  258. void RegisterAvoidanceObstacle( INavAvoidanceObstacle *obstruction );
  259. void UnregisterAvoidanceObstacle( INavAvoidanceObstacle *obstruction );
  260. const CUtlVector< INavAvoidanceObstacle * > &GetObstructions( void ) const { return m_avoidanceObstacles; }
  261. unsigned int GetNavAreaCount( void ) const { return m_areaCount; } // return total number of nav areas
  262. // See GetNavAreaFlags_t for flags
  263. CNavArea *GetNavArea( const Vector &pos, float beneathLimt = 120.0f, bool checkLOS = false ) const; // given a position, return the nav area that IsOverlapping and is *immediately* beneath it
  264. CNavArea *GetNavArea( CBaseEntity *pEntity, int nGetNavAreaFlags, float flBeneathLimit = 120.0f ) const;
  265. CNavArea *GetNavAreaByID( unsigned int id ) const;
  266. CNavArea *GetNearestNavArea( const Vector &pos, bool anyZ = false, float maxDist = 10000.0f, bool checkLOS = false, bool checkGround = true ) const;
  267. CNavArea *GetNearestNavArea( CBaseEntity *pEntity, int nGetNavAreaFlags = GETNAVAREA_CHECK_GROUND, float maxDist = 10000.0f ) const;
  268. Place GetPlace( const Vector &pos ) const; // return Place at given coordinate
  269. const char *PlaceToName( Place place ) const; // given a place, return its name
  270. Place NameToPlace( const char *name ) const; // given a place name, return a place ID or zero if no place is defined
  271. Place PartialNameToPlace( const char *name ) const; // given the first part of a place name, return a place ID or zero if no place is defined, or the partial match is ambiguous
  272. void PrintAllPlaces( void ) const; // output a list of names to the console
  273. int PlaceNameAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); // Given a partial place name, fill in possible place names for ConCommand autocomplete
  274. bool GetGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const; // get the Z coordinate of the topmost ground level below the given point
  275. bool GetSimpleGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const;// get the Z coordinate of the ground level directly below the given point
  276. /// increase "danger" weights in the given nav area and nearby ones
  277. void IncreaseDangerNearby( int teamID, float amount, CNavArea *area, const Vector &pos, float maxRadius, float dangerLimit = -1.0f );
  278. void DrawDanger( void ) const; // draw the current danger levels
  279. void DrawPlayerCounts( void ) const; // draw the current player counts for each area
  280. //-------------------------------------------------------------------------------------
  281. // Auto-generation
  282. //
  283. #define INCREMENTAL_GENERATION true
  284. void BeginGeneration( bool incremental = false ); // initiate the generation process
  285. void BeginAnalysis( bool quitWhenFinished = false ); // re-analyze an existing Mesh. Determine Hiding Spots, Encounter Spots, etc.
  286. bool IsGenerating( void ) const { return m_generationMode != GENERATE_NONE; } // return true while a Navigation Mesh is being generated
  287. const char *GetPlayerSpawnName( void ) const; // return name of player spawn entity
  288. void SetPlayerSpawnName( const char *name ); // define the name of player spawn entities
  289. void AddWalkableSeed( const Vector &pos, const Vector &normal ); // add given walkable position to list of seed positions for map sampling
  290. virtual void AddWalkableSeeds( void ); // adds walkable positions for any/all positions a mod specifies
  291. void ClearWalkableSeeds( void ) { m_walkableSeeds.RemoveAll(); } // erase all walkable seed positions
  292. void MarkStairAreas( void );
  293. virtual unsigned int GetGenerationTraceMask( void ) const; // return the mask used by traces when generating the mesh
  294. //-------------------------------------------------------------------------------------
  295. // Edit mode
  296. //
  297. unsigned int GetNavPlace( void ) const { return m_navPlace; }
  298. void SetNavPlace( unsigned int place ) { m_navPlace = place; }
  299. // Edit callbacks from ConCommands
  300. void CommandNavDelete( void ); // delete current area
  301. void CommandNavDeleteMarked( void ); // delete current marked area
  302. virtual void CommandNavFloodSelect( const CCommand &args ); // select current area and all connected areas, recursively
  303. void CommandNavToggleSelectedSet( void ); // toggles all areas into/out of the selected set
  304. void CommandNavStoreSelectedSet( void ); // stores the current selected set for later
  305. void CommandNavRecallSelectedSet( void ); // restores an older selected set
  306. void CommandNavAddToSelectedSet( void ); // add current area to selected set
  307. void CommandNavAddToSelectedSetByID( const CCommand &args ); // add specified area id to selected set
  308. void CommandNavRemoveFromSelectedSet( void ); // remove current area from selected set
  309. void CommandNavToggleInSelectedSet( void ); // add/remove current area from selected set
  310. void CommandNavClearSelectedSet( void ); // clear the selected set to empty
  311. void CommandNavBeginSelecting( void ); // start continuously selecting areas into the selected set
  312. void CommandNavEndSelecting( void ); // stop continuously selecting areas into the selected set
  313. void CommandNavBeginDragSelecting( void ); // start dragging a selection area
  314. void CommandNavEndDragSelecting( void ); // stop dragging a selection area
  315. void CommandNavBeginDragDeselecting( void ); // start dragging a deselection area
  316. void CommandNavEndDragDeselecting( void ); // stop dragging a deselection area
  317. void CommandNavRaiseDragVolumeMax( void ); // raise the top of the drag volume
  318. void CommandNavLowerDragVolumeMax( void ); // lower the top of the drag volume
  319. void CommandNavRaiseDragVolumeMin( void ); // raise the bottom of the drag volume
  320. void CommandNavLowerDragVolumeMin( void ); // lower the bottom of the drag volume
  321. void CommandNavToggleSelecting( bool playSound = true ); // start/stop continuously selecting areas into the selected set
  322. void CommandNavBeginDeselecting( void ); // start continuously de-selecting areas from the selected set
  323. void CommandNavEndDeselecting( void ); // stop continuously de-selecting areas from the selected set
  324. void CommandNavToggleDeselecting( bool playSound = true ); // start/stop continuously de-selecting areas from the selected set
  325. void CommandNavSelectInvalidAreas( void ); // adds invalid areas to the selected set
  326. void CommandNavSelectBlockedAreas( void ); // adds blocked areas to the selected set
  327. void CommandNavSelectObstructedAreas( void ); // adds obstructed areas to the selected set
  328. void CommandNavSelectDamagingAreas( void ); // adds damaging areas to the selected set
  329. void CommandNavSelectHalfSpace( const CCommand &args ); // selects all areas that intersect the half-space
  330. void CommandNavSelectStairs( void ); // adds stairs areas to the selected set
  331. void CommandNavSplit( void ); // split current area
  332. void CommandNavMerge( void ); // merge adjacent areas
  333. void CommandNavMark( const CCommand &args ); // mark an area for further operations
  334. void CommandNavUnmark( void ); // removes the mark
  335. void CommandNavBeginArea( void ); // begin creating a new nav area
  336. void CommandNavEndArea( void ); // end creation of the new nav area
  337. void CommandNavBeginShiftXY( void ); // begin shifting selected set in the XY plane
  338. void CommandNavEndShiftXY( void ); // end shifting selected set in the XY plane
  339. void CommandNavConnect( void ); // connect marked area to selected area
  340. void CommandNavDisconnect( void ); // disconnect marked area from selected area
  341. void CommandNavSplice( void ); // create new area in between marked and selected areas
  342. void CommandNavCrouch( void ); // toggle crouch attribute on current area
  343. void CommandNavTogglePlaceMode( void ); // switch between normal and place editing
  344. void CommandNavSetPlaceMode( void ); // switch between normal and place editing
  345. void CommandNavPlaceFloodFill( void ); // floodfill areas out from current area
  346. void CommandNavPlaceSet( void ); // sets the Place for the selected set
  347. void CommandNavPlacePick( void ); // "pick up" the place at the current area
  348. void CommandNavTogglePlacePainting( void ); // switch between "painting" places onto areas
  349. void CommandNavMarkUnnamed( void ); // mark an unnamed area for further operations
  350. void CommandNavCornerSelect( void ); // select a corner on the current area
  351. void CommandNavCornerRaise( const CCommand &args ); // raise a corner on the current area
  352. void CommandNavCornerLower( const CCommand &args ); // lower a corner on the current area
  353. void CommandNavCornerPlaceOnGround( const CCommand &args ); // position a corner on the current area at ground height
  354. void CommandNavWarpToMark( void ); // warp a spectating local player to the selected mark
  355. void CommandNavLadderFlip( void ); // Flips the direction a ladder faces
  356. void CommandNavToggleAttribute( NavAttributeType attribute ); // toggle an attribute on current area
  357. void CommandNavMakeSniperSpots( void ); // cuts up the marked area into individual areas suitable for sniper spots
  358. void CommandNavBuildLadder( void ); // builds a nav ladder on the climbable surface under the cursor
  359. void CommandNavRemoveJumpAreas( void ); // removes jump areas, replacing them with connections
  360. void CommandNavSubdivide( const CCommand &args ); // subdivide each nav area in X and Y to create 4 new areas - limit min size
  361. void CommandNavSaveSelected( const CCommand &args ); // Save selected set to disk
  362. void CommandNavMergeMesh( const CCommand &args ); // Merge a saved selected set into the current mesh
  363. void CommandNavMarkWalkable( void );
  364. void AddToDragSelectionSet( CNavArea *pArea );
  365. void RemoveFromDragSelectionSet( CNavArea *pArea );
  366. void ClearDragSelectionSet( void );
  367. CNavArea *GetMarkedArea( void ) const; // return area marked by user in edit mode
  368. CNavLadder *GetMarkedLadder( void ) const { return m_markedLadder; } // return ladder marked by user in edit mode
  369. CNavArea *GetSelectedArea( void ) const { return m_selectedArea; } // return area user is pointing at in edit mode
  370. CNavLadder *GetSelectedLadder( void ) const { return m_selectedLadder; } // return ladder user is pointing at in edit mode
  371. void SetMarkedLadder( CNavLadder *ladder ); // mark ladder for further edit operations
  372. void SetMarkedArea( CNavArea *area ); // mark area for further edit operations
  373. bool IsContinuouslySelecting( void ) const
  374. {
  375. return m_isContinuouslySelecting;
  376. }
  377. bool IsContinuouslyDeselecting( void ) const
  378. {
  379. return m_isContinuouslyDeselecting;
  380. }
  381. void CreateLadder( const Vector &mins, const Vector &maxs, float maxHeightAboveTopArea );
  382. void CreateLadder( const Vector &top, const Vector &bottom, float width, const Vector2D &ladderDir, float maxHeightAboveTopArea );
  383. float SnapToGrid( float x, bool forceGrid = false ) const; // snap given coordinate to generation grid boundary
  384. Vector SnapToGrid( const Vector& in, bool snapX = true, bool snapY = true, bool forceGrid = false ) const; // snap given vector's X & Y coordinates to generation grid boundary
  385. const Vector &GetEditCursorPosition( void ) const { return m_editCursorPos; } // return position of edit cursor
  386. void StripNavigationAreas( void );
  387. const char *GetFilename( void ) const; // return the filename for this map's "nav" file
  388. /// @todo Remove old select code and make all commands use this selected set
  389. void AddToSelectedSet( CNavArea *area ); // add area to the currently selected set
  390. void RemoveFromSelectedSet( CNavArea *area ); // remove area from the currently selected set
  391. void ClearSelectedSet( void ); // clear the currently selected set to empty
  392. bool IsSelectedSetEmpty( void ) const; // return true if the selected set is empty
  393. bool IsInSelectedSet( const CNavArea *area ) const; // return true if the given area is in the selected set
  394. int GetSelecteSetSize( void ) const;
  395. const NavAreaVector &GetSelectedSet( void ) const; // return the selected set
  396. /**
  397. * Apply the functor to all navigation areas in the Selected Set,
  398. * or the current selected area.
  399. * If functor returns false, stop processing and return false.
  400. */
  401. template < typename Functor >
  402. bool ForAllSelectedAreas( Functor &func )
  403. {
  404. if (IsSelectedSetEmpty())
  405. {
  406. CNavArea *area = GetSelectedArea();
  407. if (area)
  408. {
  409. if (func( area ) == false)
  410. return false;
  411. }
  412. }
  413. else
  414. {
  415. FOR_EACH_VEC( m_selectedSet, it )
  416. {
  417. CNavArea *area = m_selectedSet[ it ];
  418. if (func( area ) == false)
  419. return false;
  420. }
  421. }
  422. return true;
  423. }
  424. //-------------------------------------------------------------------------------------
  425. /**
  426. * Apply the functor to all navigation areas.
  427. * If functor returns false, stop processing and return false.
  428. */
  429. template < typename Functor >
  430. bool ForAllAreas( Functor &func )
  431. {
  432. FOR_EACH_VEC( TheNavAreas, it )
  433. {
  434. CNavArea *area = TheNavAreas[ it ];
  435. if (func( area ) == false)
  436. return false;
  437. }
  438. return true;
  439. }
  440. // const version of the above
  441. template < typename Functor >
  442. bool ForAllAreas( Functor &func ) const
  443. {
  444. FOR_EACH_VEC( TheNavAreas, it )
  445. {
  446. const CNavArea *area = TheNavAreas[ it ];
  447. if (func( area ) == false)
  448. return false;
  449. }
  450. return true;
  451. }
  452. //-------------------------------------------------------------------------------------
  453. /**
  454. * Apply the functor to all navigation areas that overlap the given extent.
  455. * If functor returns false, stop processing and return false.
  456. */
  457. template < typename Functor >
  458. bool ForAllAreasOverlappingExtent( Functor &func, const Extent &extent )
  459. {
  460. VPROF_BUDGET( "CNavMesh::ForAllAreasOverlappingExtent", "NextBot" );
  461. if ( !m_grid.Count() )
  462. {
  463. #if _DEBUG
  464. Warning("Query before nav mesh is loaded! %d\n", TheNavAreas.Count() );
  465. #endif
  466. return true;
  467. }
  468. static unsigned int searchMarker = RandomInt(0, 1024*1024 );
  469. if ( ++searchMarker == 0 )
  470. {
  471. ++searchMarker;
  472. }
  473. Extent areaExtent;
  474. // get list in cell that contains position
  475. int startX = WorldToGridX( extent.lo.x );
  476. int endX = WorldToGridX( extent.hi.x );
  477. int startY = WorldToGridY( extent.lo.y );
  478. int endY = WorldToGridY( extent.hi.y );
  479. for( int x = startX; x <= endX; ++x )
  480. {
  481. for( int y = startY; y <= endY; ++y )
  482. {
  483. int iGrid = x + y*m_gridSizeX;
  484. if ( iGrid >= m_grid.Count() )
  485. {
  486. ExecuteNTimes( 10, Warning( "** Walked off of the CNavMesh::m_grid in ForAllAreasOverlappingExtent()\n" ) );
  487. return true;
  488. }
  489. NavAreaVector *areaVector = &m_grid[ iGrid ];
  490. // find closest area in this cell
  491. FOR_EACH_VEC( (*areaVector), it )
  492. {
  493. CNavArea *area = (*areaVector)[ it ];
  494. // skip if we've already visited this area
  495. if ( area->m_nearNavSearchMarker == searchMarker )
  496. continue;
  497. // mark as visited
  498. area->m_nearNavSearchMarker = searchMarker;
  499. area->GetExtent( &areaExtent );
  500. if ( extent.IsOverlapping( areaExtent ) )
  501. {
  502. if ( func( area ) == false )
  503. return false;
  504. }
  505. }
  506. }
  507. }
  508. return true;
  509. }
  510. template < typename Functor >
  511. bool ForAllAreasInRadius( Functor &func, const Vector &pos, float radius )
  512. {
  513. // use a unique marker for this method, so it can be used within a SearchSurroundingArea() call
  514. static unsigned int searchMarker = RandomInt(0, 1024*1024 );
  515. ++searchMarker;
  516. if ( searchMarker == 0 )
  517. {
  518. ++searchMarker;
  519. }
  520. // get list in cell that contains position
  521. int originX = WorldToGridX( pos.x );
  522. int originY = WorldToGridY( pos.y );
  523. int shiftLimit = ceil( radius / m_gridCellSize );
  524. float radiusSq = radius * radius;
  525. if ( radius == 0.0f )
  526. {
  527. shiftLimit = MAX( m_gridSizeX, m_gridSizeY ); // range 0 means all areas
  528. }
  529. for( int x = originX - shiftLimit; x <= originX + shiftLimit; ++x )
  530. {
  531. if ( x < 0 || x >= m_gridSizeX )
  532. continue;
  533. for( int y = originY - shiftLimit; y <= originY + shiftLimit; ++y )
  534. {
  535. if ( y < 0 || y >= m_gridSizeY )
  536. continue;
  537. NavAreaVector *areaVector = &m_grid[ x + y*m_gridSizeX ];
  538. // find closest area in this cell
  539. FOR_EACH_VEC( (*areaVector), it )
  540. {
  541. CNavArea *area = (*areaVector)[ it ];
  542. // skip if we've already visited this area
  543. if ( area->m_nearNavSearchMarker == searchMarker )
  544. continue;
  545. // mark as visited
  546. area->m_nearNavSearchMarker = searchMarker;
  547. float distSq = ( area->GetCenter() - pos ).LengthSqr();
  548. if ( ( distSq <= radiusSq ) || ( radiusSq == 0 ) )
  549. {
  550. if ( func( area ) == false )
  551. return false;
  552. }
  553. }
  554. }
  555. }
  556. return true;
  557. }
  558. //-------------------------------------------------------------------------------------
  559. /**
  560. * Apply the functor to all navigation ladders.
  561. * If functor returns false, stop processing and return false.
  562. */
  563. template < typename Functor >
  564. bool ForAllLadders( Functor &func )
  565. {
  566. for ( int i=0; i<m_ladders.Count(); ++i )
  567. {
  568. CNavLadder *ladder = m_ladders[i];
  569. if (func( ladder ) == false)
  570. return false;
  571. }
  572. return true;
  573. }
  574. //-------------------------------------------------------------------------------------
  575. /**
  576. * Apply the functor to all navigation ladders.
  577. * If functor returns false, stop processing and return false.
  578. */
  579. template < typename Functor >
  580. bool ForAllLadders( Functor &func ) const
  581. {
  582. for ( int i=0; i<m_ladders.Count(); ++i )
  583. {
  584. const CNavLadder *ladder = m_ladders[i];
  585. if (func( ladder ) == false)
  586. return false;
  587. }
  588. return true;
  589. }
  590. //-------------------------------------------------------------------------------------
  591. /**
  592. * tests a new area for connections to adjacent pre-existing areas
  593. */
  594. template < typename Functor > void StitchAreaIntoMesh( CNavArea *area, NavDirType dir, Functor &func );
  595. //-------------------------------------------------------------------------------------
  596. /**
  597. * Use the functor to test if an area is needing stitching into the existing nav mesh.
  598. * The functor is different from how we normally use functors - it does no processing,
  599. * and it's return value is true if the area is in the new set to be stiched, and false
  600. * if it's a pre-existing area.
  601. */
  602. template < typename Functor >
  603. bool StitchMesh( Functor &func )
  604. {
  605. FOR_EACH_VEC( TheNavAreas, it )
  606. {
  607. CNavArea *area = TheNavAreas[ it ];
  608. if ( func( area ) )
  609. {
  610. StitchAreaIntoMesh( area, NORTH, func );
  611. StitchAreaIntoMesh( area, SOUTH, func );
  612. StitchAreaIntoMesh( area, EAST, func );
  613. StitchAreaIntoMesh( area, WEST, func );
  614. }
  615. }
  616. return true;
  617. }
  618. NavLadderVector& GetLadders( void ) { return m_ladders; } // Returns the list of ladders
  619. CNavLadder *GetLadderByID( unsigned int id ) const;
  620. CUtlVector< CNavArea * >& GetTransientAreas( void ) { return m_transientAreas; }
  621. enum EditModeType
  622. {
  623. NORMAL, // normal mesh editing
  624. PLACE_PAINTING, // in place painting mode
  625. CREATING_AREA, // creating a new nav area
  626. CREATING_LADDER, // creating a nav ladder
  627. DRAG_SELECTING, // drag selecting a set of areas
  628. SHIFTING_XY, // shifting selected set in XY plane
  629. SHIFTING_Z, // shifting selected set in Z plane
  630. };
  631. EditModeType GetEditMode( void ) const; // return the current edit mode
  632. void SetEditMode( EditModeType mode ); // change the edit mode
  633. bool IsEditMode( EditModeType mode ) const; // return true if current mode matches given mode
  634. bool FindNavAreaOrLadderAlongRay( const Vector &start, const Vector &end, CNavArea **area, CNavLadder **ladder, CNavArea *ignore = NULL );
  635. void PostProcessCliffAreas();
  636. void SimplifySelectedAreas( void ); // Simplifies the selected set by reducing to 1x1 areas and re-merging them up with loosened tolerances
  637. protected:
  638. virtual void PostCustomAnalysis( void ) { } // invoked when custom analysis step is complete
  639. bool FindActiveNavArea( void ); // Finds the area or ladder the local player is currently pointing at. Returns true if a surface was hit by the traceline.
  640. virtual void RemoveNavArea( CNavArea *area ); // remove an area from the grid
  641. bool FindGroundForNode( Vector *pos, Vector *normal );
  642. void GenerateNodes( const Extent &bounds );
  643. void RemoveNodes( void );
  644. virtual bool IsMeshVisibilityGenerated( void ) const { return true; } // allow derived meshes to skip costly mesh visibility computation and storage
  645. private:
  646. friend class CNavArea;
  647. friend class CNavNode;
  648. friend class CNavUIBasePanel;
  649. mutable CUtlVector<NavAreaVector> m_grid;
  650. float m_gridCellSize; // the width/height of a grid cell for spatially partitioning nav areas for fast access
  651. int m_gridSizeX;
  652. int m_gridSizeY;
  653. float m_minX;
  654. float m_minY;
  655. unsigned int m_areaCount; // total number of nav areas
  656. bool m_isLoaded; // true if a Navigation Mesh has been loaded
  657. bool m_isOutOfDate; // true if the Navigation Mesh is older than the actual BSP
  658. bool m_isAnalyzed; // true if the Navigation Mesh needs analysis
  659. enum { HASH_TABLE_SIZE = 256 };
  660. CNavArea *m_hashTable[ HASH_TABLE_SIZE ]; // hash table to optimize lookup by ID
  661. int ComputeHashKey( unsigned int id ) const; // returns a hash key for the given nav area ID
  662. int WorldToGridX( float wx ) const; // given X component, return grid index
  663. int WorldToGridY( float wy ) const; // given Y component, return grid index
  664. void AllocateGrid( float minX, float maxX, float minY, float maxY ); // clear and reset the grid to the given extents
  665. void GridToWorld( int gridX, int gridY, Vector *pos ) const;
  666. void AddNavArea( CNavArea *area ); // add an area to the grid
  667. void DestroyNavigationMesh( bool incremental = false ); // free all resources of the mesh and reset it to empty state
  668. void DestroyHidingSpots( void );
  669. void ComputeBattlefrontAreas( void ); // determine areas where rushing teams will first meet
  670. //----------------------------------------------------------------------------------
  671. // Place directory
  672. //
  673. char **m_placeName; // master directory of place names (ie: "places")
  674. unsigned int m_placeCount; // number of "places" defined in placeName[]
  675. void LoadPlaceDatabase( void ); // load the place names from a file
  676. //----------------------------------------------------------------------------------
  677. // Edit mode
  678. //
  679. EditModeType m_editMode; // the current edit mode
  680. bool m_isEditing; // true if in edit mode
  681. unsigned int m_navPlace; // current navigation place for editing
  682. void OnEditModeStart( void ); // called when edit mode has just been enabled
  683. void DrawEditMode( void ); // draw navigation areas
  684. void OnEditModeEnd( void ); // called when edit mode has just been disabled
  685. void UpdateDragSelectionSet( void ); // update which areas are overlapping the drag selected bounds
  686. Vector m_editCursorPos; // current position of the cursor
  687. CNavArea *m_markedArea; // currently marked area for edit operations
  688. CNavArea *m_selectedArea; // area that is selected this frame
  689. CNavArea *m_lastSelectedArea; // area that was selected last frame
  690. NavCornerType m_markedCorner; // currently marked corner for edit operations
  691. Vector m_anchor; // first corner of an area being created
  692. bool m_isPlacePainting; // if true, we set an area's place by pointing at it
  693. bool m_splitAlongX; // direction the selected nav area would be split
  694. float m_splitEdge; // location of the possible split
  695. bool m_climbableSurface; // if true, the cursor is pointing at a climable surface
  696. Vector m_surfaceNormal; // Normal of the surface the cursor is pointing at
  697. Vector m_ladderAnchor; // first corner of a ladder being created
  698. Vector m_ladderNormal; // Normal of the surface of the ladder being created
  699. CNavLadder *m_selectedLadder; // ladder that is selected this frame
  700. CNavLadder *m_lastSelectedLadder; // ladder that was selected last frame
  701. CNavLadder *m_markedLadder; // currently marked ladder for edit operations
  702. bool FindLadderCorners( Vector *c1, Vector *c2, Vector *c3 ); // computes the other corners of a ladder given m_ladderAnchor, m_editCursorPos, and m_ladderNormal
  703. void GetEditVectors( Vector *pos, Vector *forward ); // Gets the eye position and view direction of the editing player
  704. CountdownTimer m_showAreaInfoTimer; // Timer that controls how long area info is displayed
  705. NavAreaVector m_selectedSet; // all currently selected areas
  706. NavAreaVector m_dragSelectionSet; // all areas in the current drag selection
  707. bool m_isContinuouslySelecting; // if true, we are continuously adding to the selected set
  708. bool m_isContinuouslyDeselecting; // if true, we are continuously removing from the selected set
  709. bool m_bIsDragDeselecting;
  710. int m_nDragSelectionVolumeZMax;
  711. int m_nDragSelectionVolumeZMin;
  712. void DoToggleAttribute( CNavArea *area, NavAttributeType attribute ); // toggle an attribute on given area
  713. //----------------------------------------------------------------------------------
  714. // Auto-generation
  715. //
  716. bool UpdateGeneration( float maxTime = 0.25f ); // process the auto-generation for 'maxTime' seconds. return false if generation is complete.
  717. virtual void BeginCustomAnalysis( bool bIncremental ) {}
  718. virtual void EndCustomAnalysis() {}
  719. CNavNode *m_currentNode; // the current node we are sampling from
  720. NavDirType m_generationDir;
  721. CNavNode *AddNode( const Vector &destPos, const Vector &destNormal, NavDirType dir, CNavNode *source, bool isOnDisplacement, float obstacleHeight, float flObstacleStartDist, float flObstacleEndDist ); // add a nav node and connect it, update current node
  722. NavLadderVector m_ladders; // list of ladder navigation representations
  723. void BuildLadders( void );
  724. void DestroyLadders( void );
  725. bool SampleStep( void ); // sample the walkable areas of the map
  726. void CreateNavAreasFromNodes( void ); // cover all of the sampled nodes with nav areas
  727. bool TestArea( CNavNode *node, int width, int height ); // check if an area of size (width, height) can fit, starting from node as upper left corner
  728. int BuildArea( CNavNode *node, int width, int height ); // create a CNavArea of size (width, height) starting fom node at upper left corner
  729. bool CheckObstacles( CNavNode *node, int width, int height, int x, int y );
  730. void MarkPlayerClipAreas( void );
  731. void MarkJumpAreas( void );
  732. void StichAndRemoveJumpAreas( void );
  733. void RemoveJumpAreas( void );
  734. void SquareUpAreas( void );
  735. void MergeGeneratedAreas( void );
  736. void ConnectGeneratedAreas( void );
  737. void FixUpGeneratedAreas( void );
  738. void FixCornerOnCornerAreas( void );
  739. void FixConnections( void );
  740. void SplitAreasUnderOverhangs( void );
  741. void ValidateNavAreaConnections( void );
  742. void StitchGeneratedAreas( void ); // Stitches incrementally-generated areas into the existing mesh
  743. void StitchAreaSet( CUtlVector< CNavArea * > *areas ); // Stitches an arbitrary set of areas into the existing mesh
  744. void HandleObstacleTopAreas( void ); // Handles fixing/generating areas on top of slim obstacles such as fences and railings
  745. void RaiseAreasWithInternalObstacles();
  746. void CreateObstacleTopAreas();
  747. bool CreateObstacleTopAreaIfNecessary( CNavArea *area, CNavArea *areaOther, NavDirType dir, bool bMultiNode );
  748. void RemoveOverlappingObstacleTopAreas();
  749. enum GenerationStateType
  750. {
  751. SAMPLE_WALKABLE_SPACE,
  752. CREATE_AREAS_FROM_SAMPLES,
  753. FIND_HIDING_SPOTS,
  754. FIND_ENCOUNTER_SPOTS,
  755. FIND_SNIPER_SPOTS,
  756. FIND_EARLIEST_OCCUPY_TIMES,
  757. FIND_LIGHT_INTENSITY,
  758. COMPUTE_MESH_VISIBILITY,
  759. CUSTOM, // mod-specific generation step
  760. SAVE_NAV_MESH,
  761. NUM_GENERATION_STATES
  762. }
  763. m_generationState; // the state of the generation process
  764. enum GenerationModeType
  765. {
  766. GENERATE_NONE,
  767. GENERATE_FULL,
  768. GENERATE_INCREMENTAL,
  769. GENERATE_SIMPLIFY,
  770. GENERATE_ANALYSIS_ONLY,
  771. }
  772. m_generationMode; // true while a Navigation Mesh is being generated
  773. int m_generationIndex; // used for iterating nav areas during generation process
  774. int m_sampleTick; // counter for displaying pseudo-progress while sampling walkable space
  775. bool m_bQuitWhenFinished;
  776. float m_generationStartTime;
  777. Extent m_simplifyGenerationExtent;
  778. char *m_spawnName; // name of player spawn entity, used to initiate sampling
  779. struct WalkableSeedSpot
  780. {
  781. Vector pos;
  782. Vector normal;
  783. };
  784. CUtlVector< WalkableSeedSpot > m_walkableSeeds; // list of walkable seed spots for sampling
  785. CNavNode *GetNextWalkableSeedNode( void ); // return the next walkable seed as a node
  786. int m_seedIdx;
  787. int m_hostThreadModeRestoreValue; // stores the value of host_threadmode before we changed it
  788. void BuildTransientAreaList( void );
  789. CUtlVector< CNavArea * > m_transientAreas;
  790. void UpdateAvoidanceObstacleAreas( void );
  791. CUtlVector< CNavArea * > m_avoidanceObstacleAreas;
  792. CUtlVector< INavAvoidanceObstacle * > m_avoidanceObstacles;
  793. void UpdateBlockedAreas( void );
  794. CUtlVector< CNavArea * > m_blockedAreas;
  795. CUtlVector< int > m_storedSelectedSet; // "Stored" selected set, so we can do some editing and then restore the old selected set. Done by ID, so we don't have to worry about split/delete/etc.
  796. void BeginVisibilityComputations( void );
  797. void EndVisibilityComputations( void );
  798. void TestAllAreasForBlockedStatus( void ); // Used to update blocked areas after a round restart. Need to delay so the map logic has all fired.
  799. CountdownTimer m_updateBlockedAreasTimer;
  800. };
  801. // the global singleton interface
  802. extern CNavMesh *TheNavMesh;
  803. // factory for creating the Navigation Mesh
  804. extern CNavMesh *NavMeshFactory( void );
  805. // for debugging the A* algorithm, if nonzero, show debug display and decrement for each pathfind
  806. extern int g_DebugPathfindCounter;
  807. //--------------------------------------------------------------------------------------------------------------
  808. inline bool CNavMesh::IsEditMode( EditModeType mode ) const
  809. {
  810. return m_editMode == mode;
  811. }
  812. //--------------------------------------------------------------------------------------------------------------
  813. inline CNavMesh::EditModeType CNavMesh::GetEditMode( void ) const
  814. {
  815. return m_editMode;
  816. }
  817. //--------------------------------------------------------------------------------------------------------------
  818. inline unsigned int CNavMesh::GetSubVersionNumber( void ) const
  819. {
  820. return 0;
  821. }
  822. //--------------------------------------------------------------------------------------------------------------
  823. inline CNavArea *CNavMesh::CreateArea( void ) const
  824. {
  825. return new CNavArea;
  826. }
  827. //--------------------------------------------------------------------------------------------------------------
  828. inline void CNavMesh::DestroyArea( CNavArea *pArea ) const
  829. {
  830. delete pArea;
  831. }
  832. //--------------------------------------------------------------------------------------------------------------
  833. inline int CNavMesh::ComputeHashKey( unsigned int id ) const
  834. {
  835. return id & 0xFF;
  836. }
  837. //--------------------------------------------------------------------------------------------------------------
  838. inline int CNavMesh::WorldToGridX( float wx ) const
  839. {
  840. int x = (int)( (wx - m_minX) / m_gridCellSize );
  841. if (x < 0)
  842. x = 0;
  843. else if (x >= m_gridSizeX)
  844. x = m_gridSizeX-1;
  845. return x;
  846. }
  847. //--------------------------------------------------------------------------------------------------------------
  848. inline int CNavMesh::WorldToGridY( float wy ) const
  849. {
  850. int y = (int)( (wy - m_minY) / m_gridCellSize );
  851. if (y < 0)
  852. y = 0;
  853. else if (y >= m_gridSizeY)
  854. y = m_gridSizeY-1;
  855. return y;
  856. }
  857. //--------------------------------------------------------------------------------------------------------------
  858. inline unsigned int CNavMesh::GetGenerationTraceMask( void ) const
  859. {
  860. return MASK_NPCSOLID_BRUSHONLY;
  861. }
  862. //--------------------------------------------------------------------------------------------------------------
  863. //
  864. // Function prototypes
  865. //
  866. extern void ApproachAreaAnalysisPrep( void );
  867. extern void CleanupApproachAreaAnalysisPrep( void );
  868. extern bool IsHeightDifferenceValid( float test, float other1, float other2, float other3 );
  869. #endif // _NAV_MESH_H_