Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CCmpPathfinder_Common.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_CCMPPATHFINDER_COMMON
19 #define INCLUDED_CCMPPATHFINDER_COMMON
20 
21 /**
22  * @file
23  * Declares CCmpPathfinder, whose implementation is split into multiple source files,
24  * and provides common code needed for more than one of those files.
25  * CCmpPathfinder includes two pathfinding algorithms (one tile-based, one vertex-based)
26  * with some shared state and functionality, so the code is split into
27  * CCmpPathfinder_Vertex.cpp, CCmpPathfinder_Tile.cpp and CCmpPathfinder.cpp
28  */
29 
31 
32 #include "ICmpPathfinder.h"
33 
34 #include "graphics/Overlay.h"
35 #include "graphics/Terrain.h"
36 #include "maths/MathUtil.h"
39 
40 class PathfinderOverlay;
41 class SceneCollector;
42 struct PathfindTile;
43 
44 #ifdef NDEBUG
45 #define PATHFIND_DEBUG 0
46 #else
47 #define PATHFIND_DEBUG 1
48 #endif
49 
50 /*
51  * For efficient pathfinding we want to try hard to minimise the per-tile search cost,
52  * so we precompute the tile passability flags and movement costs for the various different
53  * types of unit.
54  * We also want to minimise memory usage (there can easily be 100K tiles so we don't want
55  * to store many bytes for each).
56  *
57  * To handle passability efficiently, we have a small number of passability classes
58  * (e.g. "infantry", "ship"). Each unit belongs to a single passability class, and
59  * uses that for all its pathfinding.
60  * Passability is determined by water depth, terrain slope, forestness, buildingness.
61  * We need at least one bit per class per tile to represent passability.
62  *
63  * We use a separate bit to indicate building obstructions (instead of folding it into
64  * the class passabilities) so that it can be ignored when doing the accurate short paths.
65  * We use another bit to indicate tiles near obstructions that block construction,
66  * for the AI to plan safe building spots.
67  *
68  * To handle movement costs, we have an arbitrary number of unit cost classes (e.g. "infantry", "camel"),
69  * and a small number of terrain cost classes (e.g. "grass", "steep grass", "road", "sand"),
70  * and a cost mapping table between the classes (e.g. camels are fast on sand).
71  * We need log2(|terrain cost classes|) bits per tile to represent costs.
72  *
73  * We could have one passability bitmap per class, and another array for cost classes,
74  * but instead (for no particular reason) we'll pack them all into a single u16 array.
75  *
76  * We handle dynamic updates currently by recomputing the entire array, which is stupid;
77  * it should only bother updating the region that has changed.
78  */
80 {
81 public:
83  m_Mask(mask)
84  {
85  if (node.GetChild("MinWaterDepth").IsOk())
86  m_MinDepth = node.GetChild("MinWaterDepth").ToFixed();
87  else
88  m_MinDepth = std::numeric_limits<fixed>::min();
89 
90  if (node.GetChild("MaxWaterDepth").IsOk())
91  m_MaxDepth = node.GetChild("MaxWaterDepth").ToFixed();
92  else
93  m_MaxDepth = std::numeric_limits<fixed>::max();
94 
95  if (node.GetChild("MaxTerrainSlope").IsOk())
96  m_MaxSlope = node.GetChild("MaxTerrainSlope").ToFixed();
97  else
98  m_MaxSlope = std::numeric_limits<fixed>::max();
99 
100  if (node.GetChild("MinShoreDistance").IsOk())
101  m_MinShore = node.GetChild("MinShoreDistance").ToFixed();
102  else
103  m_MinShore = std::numeric_limits<fixed>::min();
104 
105  if (node.GetChild("MaxShoreDistance").IsOk())
106  m_MaxShore = node.GetChild("MaxShoreDistance").ToFixed();
107  else
108  m_MaxShore = std::numeric_limits<fixed>::max();
109 
110  }
111 
112  bool IsPassable(fixed waterdepth, fixed steepness, fixed shoredist)
113  {
114  return ((m_MinDepth <= waterdepth && waterdepth <= m_MaxDepth) && (steepness < m_MaxSlope) && (m_MinShore <= shoredist && shoredist <= m_MaxShore));
115  }
116 
118 private:
124 };
125 
126 typedef u16 TerrainTile;
127 // 1 bit for pathfinding obstructions,
128 // 1 bit for construction obstructions (used by AI),
129 // PASS_CLASS_BITS for terrain passability (allowing PASS_CLASS_BITS classes),
130 // COST_CLASS_BITS for movement costs (allowing 2^COST_CLASS_BITS classes)
131 
132 const int PASS_CLASS_BITS = 10;
133 const int COST_CLASS_BITS = 16 - (PASS_CLASS_BITS + 2);
134 #define IS_TERRAIN_PASSABLE(item, classmask) (((item) & (classmask)) == 0)
135 #define IS_PASSABLE(item, classmask) (((item) & ((classmask) | 1)) == 0)
136 #define GET_COST_CLASS(item) ((item) >> (PASS_CLASS_BITS + 2))
137 #define COST_CLASS_MASK(id) ( (TerrainTile) ((id) << (PASS_CLASS_BITS + 2)) )
138 
140 
142 {
150 };
151 
153 {
164 };
165 
166 /**
167  * Implementation of ICmpPathfinder
168  */
170 {
171 public:
172  static void ClassInit(CComponentManager& componentManager)
173  {
174  componentManager.SubscribeToMessageType(MT_Update);
175  componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
176  componentManager.SubscribeToMessageType(MT_TerrainChanged);
177  componentManager.SubscribeToMessageType(MT_TurnStart);
178  }
179 
181 
182  // Template state:
183 
184  std::map<std::string, pass_class_t> m_PassClassMasks;
186 
187  std::map<std::string, cost_class_t> m_TerrainCostClassTags;
188  std::map<std::string, cost_class_t> m_UnitCostClassTags;
189  std::vector<std::vector<u32> > m_MoveCosts; // costs[unitClass][terrainClass]
190  std::vector<std::vector<fixed> > m_MoveSpeeds; // speeds[unitClass][terrainClass]
191 
192  // Dynamic state:
193 
196  u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests
197  u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn
198 
199  // Lazily-constructed dynamic state (not serialized):
200 
201  u16 m_MapSize; // tiles per side
202  Grid<TerrainTile>* m_Grid; // terrain/passability information
203  Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid)
204  bool m_TerrainDirty; // indicates if m_Grid has been updated since terrain changed
205 
206  // For responsiveness we will process some moves in the same turn they were generated in
207 
208  u16 m_MaxSameTurnMoves; // max number of moves that can be created and processed in the same turn
209 
210  // Debugging - output from last pathfind operation:
211 
217 
219 
220  static std::string GetSchema()
221  {
222  return "<a:component type='system'/><empty/>";
223  }
224 
225  virtual void Init(const CParamNode& paramNode);
226 
227  virtual void Deinit();
228 
229  virtual void Serialize(ISerializer& serialize);
230 
231  virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize);
232 
233  virtual void HandleMessage(const CMessage& msg, bool global);
234 
235  virtual pass_class_t GetPassabilityClass(const std::string& name);
236 
237  virtual std::map<std::string, pass_class_t> GetPassabilityClasses();
238 
239  virtual cost_class_t GetCostClass(const std::string& name);
240 
241  virtual const Grid<u16>& GetPassabilityGrid();
242 
243  virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, Path& ret);
244 
245  virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify);
246 
247  virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, Path& ret);
248 
249  virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify);
250 
251  virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal& goal, pass_class_t passClass, cost_class_t costClass);
252 
253  virtual void ResetDebugPath();
254 
255  virtual void SetDebugOverlay(bool enabled);
256 
257  virtual fixed GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, cost_class_t costClass);
258 
259  virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal& goal);
260 
261  virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass);
262 
264 
266 
268 
270 
271  virtual void FinishAsyncRequests();
272 
273  void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests);
274 
275  void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests);
276 
277  virtual void ProcessSameTurnMoves();
278 
279  /**
280  * Returns the tile containing the given position
281  */
283  {
284  i = (u16)clamp((x / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, m_MapSize-1);
285  j = (u16)clamp((z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), 0, m_MapSize-1);
286  }
287 
288  /**
289  * Returns the position of the center of the given tile
290  */
291  static void TileCenter(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z)
292  {
295  }
296 
297  static fixed DistanceToGoal(CFixedVector2D pos, const CCmpPathfinder::Goal& goal);
298 
299  /**
300  * Regenerates the grid based on the current obstruction list, if necessary
301  */
302  void UpdateGrid();
303 
304  void RenderSubmit(SceneCollector& collector);
305 };
306 
307 #endif // INCLUDED_CCMPPATHFINDER_COMMON
ICmpPathfinder::pass_class_t m_Mask
An entity initialisation parameter node.
Definition: ParamNode.h:112
void SubscribeToMessageType(MessageTypeId mtid)
Subscribe the current component type to the given message type.
std::vector< SOverlayLine > m_DebugOverlayShortPathLines
#define u8
Definition: types.h:39
A simple fixed-point number class.
Definition: Fixed.h:115
PathfinderPassability(ICmpPathfinder::pass_class_t mask, const CParamNode &node)
ICmpPathfinder::pass_class_t passClass
Interface for ICmpObstructionManager Test functions to filter out unwanted shapes.
static void ClassInit(CComponentManager &componentManager)
virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const Goal &goal, pass_class_t passClass, cost_class_t costClass)
If the debug overlay is enabled, render the path that will computed by ComputePath.
Implementation of ICmpPathfinder.
void UpdateGrid()
Regenerates the grid based on the current obstruction list, if necessary.
Similar to Grid, except optimised for sparse usage (the grid is subdivided into buckets whose content...
Definition: Grid.h:112
virtual void HandleMessage(const CMessage &msg, bool global)
Line-based overlay, with world-space coordinates, rendered in the world potentially behind other obje...
Definition: Overlay.h:36
static fixed DistanceToGoal(CFixedVector2D pos, const CCmpPathfinder::Goal &goal)
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
virtual void ResetDebugPath()
static std::string GetSchema()
std::vector< PathfinderPassability > m_PassClasses
std::map< std::string, cost_class_t > m_TerrainCostClassTags
bool IsOk() const
Returns true if this is a valid CParamNode, false if it represents a non-existent node...
Definition: ParamNode.cpp:193
virtual fixed GetMovementSpeed(entity_pos_t x0, entity_pos_t z0, cost_class_t costClass)
Find the speed factor (typically around 1.0) for a unit of the given cost class at the given position...
Serialization interface; see serialization overview.
Definition: ISerializer.h:120
virtual void ProcessSameTurnMoves()
Process moves during the same turn they were created in to improve responsiveness.
virtual std::map< std::string, pass_class_t > GetPassabilityClasses()
Get the list of all known passability classes.
virtual ICmpObstruction::EFoundationCheck CheckBuildingPlacement(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass)
Check whether a building placed here is valid and doesn&#39;t hit any obstructions or impassable terrain...
void NearestTile(entity_pos_t x, entity_pos_t z, u16 &i, u16 &j)
Returns the tile containing the given position.
Grid< u8 > * m_ObstructionGrid
std::vector< std::vector< u32 > > m_MoveCosts
Basic 2D array, intended for storing tile data, plus support for lazy updates by ICmpObstructionManag...
Grid< TerrainTile > * m_Grid
Pathfinder algorithms.
void RenderSubmit(SceneCollector &collector)
ICmpPathfinder::pass_class_t passClass
std::vector< AsyncShortPathRequest > m_AsyncShortPathRequests
This interface accepts renderable objects.
Definition: Scene.h:82
fixed ToFixed() const
Parses the content of this node as a fixed-point number.
Definition: ParamNode.cpp:222
Terrain overlay for pathfinder debugging.
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none...
Definition: ParamNode.cpp:185
virtual void Serialize(ISerializer &serialize)
virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Goal &goal, pass_class_t passClass, cost_class_t costClass, entity_id_t notify)
Asynchronous version of ComputePath.
std::vector< std::vector< fixed > > m_MoveSpeeds
void ProcessLongRequests(const std::vector< AsyncLongPathRequest > &longRequests)
Definition: path.h:75
PathfindTileGrid * m_DebugGrid
std::map< std::string, cost_class_t > m_UnitCostClassTags
Tile data for A* computation.
std::vector< AsyncLongPathRequest > m_AsyncLongPathRequests
virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const Goal &goal, pass_class_t passClass, cost_class_t costClass, Path &ret)
ICmpPathfinder::Goal goal
#define DEFAULT_COMPONENT_ALLOCATOR(cname)
Definition: Component.h:44
virtual void SetDebugOverlay(bool enabled)
Toggle the storage and rendering of debug info.
const int COST_CLASS_BITS
virtual pass_class_t GetPassabilityClass(const std::string &name)
Get the tag for a given passability class name.
std::map< std::string, pass_class_t > m_PassClassMasks
SparseGrid< PathfindTile > PathfindTileGrid
virtual void Init(const CParamNode &paramNode)
static CFixed FromInt(int n)
Definition: Fixed.h:136
virtual CFixedVector2D GetNearestPointOnGoal(CFixedVector2D pos, const Goal &goal)
Returns the coordinates of the point on the goal that is closest to pos in a straight line...
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal &goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify)
Asynchronous version of ComputeShortPath (using ControlGroupObstructionFilter).
PathfinderOverlay * m_DebugOverlay
#define u16
Definition: types.h:40
ICmpPathfinder::Goal goal
ICmpPathfinder::cost_class_t costClass
virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter &filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass)
Check whether a unit placed here is valid and doesn&#39;t hit any obstructions or impassable terrain...
#define u32
Definition: types.h:41
static void TileCenter(u16 i, u16 j, entity_pos_t &x, entity_pos_t &z)
Returns the position of the center of the given tile.
virtual void Deinit()
void ProcessShortRequests(const std::vector< AsyncShortPathRequest > &shortRequests)
bool IsPassable(fixed waterdepth, fixed steepness, fixed shoredist)
u16 TerrainTile
virtual cost_class_t GetCostClass(const std::string &name)
Get the tag for a given movement cost class name.
u32 entity_id_t
Entity ID type.
Definition: Entity.h:24
virtual const Grid< u16 > & GetPassabilityGrid()
const int PASS_CLASS_BITS
virtual void ComputeShortPath(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const Goal &goal, pass_class_t passClass, Path &ret)
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
Helper functions related to geometry algorithms.
virtual void FinishAsyncRequests()
Finish computing asynchronous path requests and send the CMessagePathResult messages.
Deserialization interface; see serialization overview.
Definition: IDeserializer.h:34
pass_class_t m_DebugPassClass
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)
virtual bool CheckMovement(const IObstructionTestFilter &filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass)
Check whether the given movement line is valid and doesn&#39;t hit any obstructions or impassable terrain...