1 /* Copyright (C) 2017 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. Its implementation is mainly done in CCmpPathfinder.cpp, 24 * but the short-range (vertex) pathfinding is done in CCmpPathfinder_Vertex.cpp. 25 * This file provides common code needed for both files. 26 * 27 * The long-range pathfinding is done by a LongPathfinder object. 28 */ 29 30 #include "simulation2/system/Component.h" 31 32 #include "ICmpPathfinder.h" 33 34 #include "graphics/Overlay.h" 35 #include "graphics/Terrain.h" 36 #include "maths/MathUtil.h" 37 #include "ps/CLogger.h" 38 #include "simulation2/components/ICmpObstructionManager.h" 39 #include "simulation2/helpers/LongPathfinder.h" 40 41 class SceneCollector; 42 class AtlasOverlay; 43 44 #ifdef NDEBUG 45 #define PATHFIND_DEBUG 0 46 #else 47 #define PATHFIND_DEBUG 1 48 #endif 49 50 51 struct AsyncLongPathRequest 52 { 53 u32 ticket; 54 entity_pos_t x0; 55 entity_pos_t z0; 56 PathGoal goal; 57 pass_class_t passClass; 58 entity_id_t notify; 59 }; 60 61 struct AsyncShortPathRequest 62 { 63 u32 ticket; 64 entity_pos_t x0; 65 entity_pos_t z0; 66 entity_pos_t clearance; 67 entity_pos_t range; 68 PathGoal goal; 69 pass_class_t passClass; 70 bool avoidMovingUnits; 71 entity_id_t group; 72 entity_id_t notify; 73 }; 74 75 // A vertex around the corners of an obstruction 76 // (paths will be sequences of these vertexes) 77 struct Vertex 78 { 79 enum 80 { 81 UNEXPLORED, 82 OPEN, 83 CLOSED, 84 }; 85 86 CFixedVector2D p; 87 fixed g, h; 88 u16 pred; 89 u8 status; 90 u8 quadInward : 4; // the quadrant which is inside the shape (or NONE) 91 u8 quadOutward : 4; // the quadrants of the next point on the path which this vertex must be in, given 'pred' 92 }; 93 94 // Obstruction edges (paths will not cross any of these). 95 // Defines the two points of the edge. 96 struct Edge 97 { 98 CFixedVector2D p0, p1; 99 }; 100 101 // Axis-aligned obstruction squares (paths will not cross any of these). 102 // Defines the opposing corners of an axis-aligned square 103 // (from which four individual edges can be trivially computed), requiring p0 <= p1 104 struct Square 105 { 106 CFixedVector2D p0, p1; 107 }; 108 109 // Axis-aligned obstruction edges. 110 // p0 defines one end; c1 is either the X or Y coordinate of the other end, 111 // depending on the context in which this is used. 112 struct EdgeAA 113 { 114 CFixedVector2D p0; 115 fixed c1; 116 }; 117 118 /** 119 * Implementation of ICmpPathfinder 120 */ 121 class CCmpPathfinder : public ICmpPathfinder 122 { 123 public: ClassInit(CComponentManager & componentManager)124 static void ClassInit(CComponentManager& componentManager) 125 { 126 componentManager.SubscribeToMessageType(MT_Update); 127 componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays 128 componentManager.SubscribeToMessageType(MT_TerrainChanged); 129 componentManager.SubscribeToMessageType(MT_WaterChanged); 130 componentManager.SubscribeToMessageType(MT_ObstructionMapShapeChanged); 131 componentManager.SubscribeToMessageType(MT_TurnStart); 132 } 133 134 DEFAULT_COMPONENT_ALLOCATOR(Pathfinder) 135 136 // Template state: 137 138 std::map<std::string, pass_class_t> m_PassClassMasks; 139 std::vector<PathfinderPassability> m_PassClasses; 140 141 // Dynamic state: 142 143 std::vector<AsyncLongPathRequest> m_AsyncLongPathRequests; 144 std::vector<AsyncShortPathRequest> m_AsyncShortPathRequests; 145 u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests 146 u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn 147 148 // Lazily-constructed dynamic state (not serialized): 149 150 u16 m_MapSize; // tiles per side 151 Grid<NavcellData>* m_Grid; // terrain/passability information 152 Grid<NavcellData>* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations 153 154 // Keep clever updates in memory to avoid memory fragmentation from the grid. 155 // This should be used only in UpdateGrid(), there is no guarantee the data is properly initialized anywhere else. 156 GridUpdateInformation m_DirtinessInformation; 157 // The data from clever updates is stored for the AI manager 158 GridUpdateInformation m_AIPathfinderDirtinessInformation; 159 bool m_TerrainDirty; 160 161 // Interface to the long-range pathfinder. 162 LongPathfinder m_LongPathfinder; 163 164 // For responsiveness we will process some moves in the same turn they were generated in 165 166 u16 m_MaxSameTurnMoves; // max number of moves that can be created and processed in the same turn 167 168 // memory optimizations: those vectors are created once, reused for all calculations; 169 std::vector<Edge> edgesUnaligned; 170 std::vector<EdgeAA> edgesLeft; 171 std::vector<EdgeAA> edgesRight; 172 std::vector<EdgeAA> edgesBottom; 173 std::vector<EdgeAA> edgesTop; 174 175 // List of obstruction vertexes (plus start/end points); we'll try to find paths through 176 // the graph defined by these vertexes 177 std::vector<Vertex> vertexes; 178 // List of collision edges - paths must never cross these. 179 // (Edges are one-sided so intersections are fine in one direction, but not the other direction.) 180 std::vector<Edge> edges; 181 std::vector<Square> edgeSquares; // axis-aligned squares; equivalent to 4 edges 182 183 bool m_DebugOverlay; 184 std::vector<SOverlayLine> m_DebugOverlayShortPathLines; 185 AtlasOverlay* m_AtlasOverlay; 186 GetSchema()187 static std::string GetSchema() 188 { 189 return "<a:component type='system'/><empty/>"; 190 } 191 192 virtual void Init(const CParamNode& paramNode); 193 194 virtual void Deinit(); 195 196 template<typename S> 197 void SerializeCommon(S& serialize); 198 199 virtual void Serialize(ISerializer& serialize); 200 201 virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize); 202 203 virtual void HandleMessage(const CMessage& msg, bool global); 204 205 virtual pass_class_t GetPassabilityClass(const std::string& name) const; 206 207 virtual void GetPassabilityClasses(std::map<std::string, pass_class_t>& passClasses) const; 208 virtual void GetPassabilityClasses( 209 std::map<std::string, pass_class_t>& nonPathfindingPassClasses, 210 std::map<std::string, pass_class_t>& pathfindingPassClasses) const; 211 212 const PathfinderPassability* GetPassabilityFromMask(pass_class_t passClass) const; 213 GetClearance(pass_class_t passClass)214 virtual entity_pos_t GetClearance(pass_class_t passClass) const 215 { 216 const PathfinderPassability* passability = GetPassabilityFromMask(passClass); 217 if (!passability) 218 return fixed::Zero(); 219 220 return passability->m_Clearance; 221 } 222 GetMaximumClearance()223 virtual entity_pos_t GetMaximumClearance() const 224 { 225 entity_pos_t max = fixed::Zero(); 226 227 for (const PathfinderPassability& passability : m_PassClasses) 228 if (passability.m_Clearance > max) 229 max = passability.m_Clearance; 230 231 return max + Pathfinding::CLEARANCE_EXTENSION_RADIUS; 232 } 233 234 virtual const Grid<NavcellData>& GetPassabilityGrid(); 235 GetAIPathfinderDirtinessInformation()236 virtual const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const 237 { 238 return m_AIPathfinderDirtinessInformation; 239 } 240 FlushAIPathfinderDirtinessInformation()241 virtual void FlushAIPathfinderDirtinessInformation() 242 { 243 m_AIPathfinderDirtinessInformation.Clean(); 244 } 245 246 virtual Grid<u16> ComputeShoreGrid(bool expandOnWater = false); 247 ComputePath(entity_pos_t x0,entity_pos_t z0,const PathGoal & goal,pass_class_t passClass,WaypointPath & ret)248 virtual void ComputePath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) 249 { 250 m_LongPathfinder.ComputePath(x0, z0, goal, passClass, ret); 251 } 252 253 virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify); 254 255 virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret); 256 257 virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify); 258 SetDebugPath(entity_pos_t x0,entity_pos_t z0,const PathGoal & goal,pass_class_t passClass)259 virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) 260 { 261 m_LongPathfinder.SetDebugPath(x0, z0, goal, passClass); 262 } 263 SetDebugOverlay(bool enabled)264 virtual void SetDebugOverlay(bool enabled) 265 { 266 m_DebugOverlay = enabled; 267 m_LongPathfinder.SetDebugOverlay(enabled); 268 } 269 SetHierDebugOverlay(bool enabled)270 virtual void SetHierDebugOverlay(bool enabled) 271 { 272 m_LongPathfinder.SetHierDebugOverlay(enabled, &GetSimContext()); 273 } 274 GetDebugData(u32 & steps,double & time,Grid<u8> & grid)275 virtual void GetDebugData(u32& steps, double& time, Grid<u8>& grid) const 276 { 277 m_LongPathfinder.GetDebugData(steps, time, grid); 278 } 279 280 virtual void SetAtlasOverlay(bool enable, pass_class_t passClass = 0); 281 282 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) const; 283 284 virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass, bool onlyCenterPoint) const; 285 286 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) const; 287 288 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, bool onlyCenterPoint) const; 289 290 virtual void FinishAsyncRequests(); 291 292 void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests); 293 294 void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests); 295 296 virtual void ProcessSameTurnMoves(); 297 298 /** 299 * Regenerates the grid based on the current obstruction list, if necessary 300 */ 301 virtual void UpdateGrid(); 302 303 /** 304 * Updates the terrain-only grid without updating the dirtiness informations. 305 * Useful for fast passability updates in Atlas. 306 */ 307 void MinimalTerrainUpdate(); 308 309 /** 310 * Regenerates the terrain-only grid. 311 * Atlas doesn't need to have passability cells expanded. 312 */ 313 void TerrainUpdateHelper(bool expandPassability = true); 314 315 void RenderSubmit(SceneCollector& collector); 316 }; 317 318 class AtlasOverlay : public TerrainTextureOverlay 319 { 320 public: 321 const CCmpPathfinder* m_Pathfinder; 322 pass_class_t m_PassClass; 323 AtlasOverlay(const CCmpPathfinder * pathfinder,pass_class_t passClass)324 AtlasOverlay(const CCmpPathfinder* pathfinder, pass_class_t passClass) : 325 TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TILE), m_Pathfinder(pathfinder), m_PassClass(passClass) 326 { 327 } 328 BuildTextureRGBA(u8 * data,size_t w,size_t h)329 virtual void BuildTextureRGBA(u8* data, size_t w, size_t h) 330 { 331 // Render navcell passability, based on the terrain-only grid 332 u8* p = data; 333 for (size_t j = 0; j < h; ++j) 334 { 335 for (size_t i = 0; i < w; ++i) 336 { 337 SColor4ub color(0, 0, 0, 0); 338 if (!IS_PASSABLE(m_Pathfinder->m_TerrainOnlyGrid->get((int)i, (int)j), m_PassClass)) 339 color = SColor4ub(255, 0, 0, 127); 340 341 *p++ = color.R; 342 *p++ = color.G; 343 *p++ = color.B; 344 *p++ = color.A; 345 } 346 } 347 } 348 }; 349 350 #endif // INCLUDED_CCMPPATHFINDER_COMMON 351