LCOV - code coverage report
Current view: top level - source/simulation2/components - CCmpPathfinder_Common.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 15 58 25.9 %
Date: 2023-01-19 00:18:29 Functions: 10 22 45.5 %

          Line data    Source code
       1             : /* Copyright (C) 2022 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 "ps/TaskManager.h"
      39             : #include "renderer/TerrainOverlay.h"
      40             : #include "simulation2/components/ICmpObstructionManager.h"
      41             : #include "simulation2/helpers/Grid.h"
      42             : 
      43             : #include <vector>
      44             : 
      45             : class HierarchicalPathfinder;
      46             : class LongPathfinder;
      47             : class VertexPathfinder;
      48             : 
      49             : class SceneCollector;
      50             : class AtlasOverlay;
      51             : 
      52             : #ifdef NDEBUG
      53             : #define PATHFIND_DEBUG 0
      54             : #else
      55             : #define PATHFIND_DEBUG 1
      56             : #endif
      57             : 
      58             : /**
      59             :  * Implementation of ICmpPathfinder
      60             :  */
      61           3 : class CCmpPathfinder final : public ICmpPathfinder
      62             : {
      63             : public:
      64         116 :     static void ClassInit(CComponentManager& componentManager)
      65             :     {
      66         116 :         componentManager.SubscribeToMessageType(MT_Deserialized);
      67         116 :         componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
      68         116 :         componentManager.SubscribeToMessageType(MT_TerrainChanged);
      69         116 :         componentManager.SubscribeToMessageType(MT_WaterChanged);
      70         116 :         componentManager.SubscribeToMessageType(MT_ObstructionMapShapeChanged);
      71         116 :     }
      72             : 
      73             :     ~CCmpPathfinder();
      74             : 
      75           6 :     DEFAULT_COMPONENT_ALLOCATOR(Pathfinder)
      76             : 
      77             :     // Template state:
      78             : 
      79             :     std::map<std::string, pass_class_t> m_PassClassMasks;
      80             :     std::vector<PathfinderPassability> m_PassClasses;
      81             :     u16 m_MaxSameTurnMoves; // Compute only this many paths when useMax is true in StartProcessingMoves.
      82             : 
      83             :     // Dynamic state:
      84             : 
      85             :     // Lazily-constructed dynamic state (not serialized):
      86             : 
      87             :     u16 m_GridSize; // Navcells per side of the map.
      88             :     Grid<NavcellData>* m_Grid; // terrain/passability information
      89             :     Grid<NavcellData>* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations
      90             : 
      91             :     // Keep clever updates in memory to avoid memory fragmentation from the grid.
      92             :     // This should be used only in UpdateGrid(), there is no guarantee the data is properly initialized anywhere else.
      93             :     GridUpdateInformation m_DirtinessInformation;
      94             :     // The data from clever updates is stored for the AI manager
      95             :     GridUpdateInformation m_AIPathfinderDirtinessInformation;
      96             :     bool m_TerrainDirty;
      97             : 
      98             :     std::vector<VertexPathfinder> m_VertexPathfinders;
      99             :     std::unique_ptr<HierarchicalPathfinder> m_PathfinderHier;
     100             :     std::unique_ptr<LongPathfinder> m_LongPathfinder;
     101             : 
     102             :     // One per live asynchronous path computing task.
     103             :     std::vector<Future<void>> m_Futures;
     104             : 
     105             :     template<typename T>
     106          12 :     class PathRequests {
     107             :     public:
     108             :         std::vector<T> m_Requests;
     109             :         std::vector<PathResult> m_Results;
     110             :         // This is the array index of the next path to compute.
     111             :         std::atomic<size_t> m_NextPathToCompute = 0;
     112             :         // This is false until all scheduled paths have been computed.
     113             :         std::atomic<bool> m_ComputeDone = true;
     114             : 
     115           0 :         void ClearComputed()
     116             :         {
     117           0 :             if (m_Results.size() == m_Requests.size())
     118           0 :                 m_Requests.clear();
     119             :             else
     120           0 :                 m_Requests.erase(m_Requests.end() - m_Results.size(), m_Requests.end());
     121           0 :             m_Results.clear();
     122           0 :         }
     123             : 
     124             :         /**
     125             :          * @param max - if non-zero, how many paths to process.
     126             :          */
     127           0 :         void PrepareForComputation(u16 max)
     128             :         {
     129           0 :             size_t n = m_Requests.size();
     130           0 :             if (max && n > max)
     131           0 :                 n = max;
     132           0 :             m_NextPathToCompute = 0;
     133           0 :             m_Results.resize(n);
     134           0 :             m_ComputeDone = n == 0;
     135           0 :         }
     136             : 
     137             :         template<typename U>
     138             :         void Compute(const CCmpPathfinder& cmpPathfinder, const U& pathfinder);
     139             :     };
     140             :     PathRequests<LongPathRequest> m_LongPathRequests;
     141             :     PathRequests<ShortPathRequest> m_ShortPathRequests;
     142             : 
     143             :     u32 m_NextAsyncTicket; // Unique IDs for asynchronous path requests.
     144             : 
     145             :     AtlasOverlay* m_AtlasOverlay;
     146             : 
     147         116 :     static std::string GetSchema()
     148             :     {
     149         116 :         return "<a:component type='system'/><empty/>";
     150             :     }
     151             : 
     152             :     void Init(const CParamNode& paramNode) override;
     153             : 
     154             :     void Deinit() override;
     155             : 
     156             :     template<typename S>
     157             :     void SerializeCommon(S& serialize);
     158             : 
     159             :     void Serialize(ISerializer& serialize) override;
     160             : 
     161             :     void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override;
     162             : 
     163             :     void HandleMessage(const CMessage& msg, bool global) override;
     164             : 
     165             :     pass_class_t GetPassabilityClass(const std::string& name) const override;
     166             : 
     167             :     void GetPassabilityClasses(std::map<std::string, pass_class_t>& passClasses) const override;
     168             :     void GetPassabilityClasses(
     169             :         std::map<std::string, pass_class_t>& nonPathfindingPassClasses,
     170             :         std::map<std::string, pass_class_t>& pathfindingPassClasses) const override;
     171             : 
     172             :     const PathfinderPassability* GetPassabilityFromMask(pass_class_t passClass) const;
     173             : 
     174           0 :     entity_pos_t GetClearance(pass_class_t passClass) const override
     175             :     {
     176           0 :         const PathfinderPassability* passability = GetPassabilityFromMask(passClass);
     177           0 :         if (!passability)
     178           0 :             return fixed::Zero();
     179             : 
     180           0 :         return passability->m_Clearance;
     181             :     }
     182             : 
     183           0 :     entity_pos_t GetMaximumClearance() const override
     184             :     {
     185           0 :         entity_pos_t max = fixed::Zero();
     186             : 
     187           0 :         for (const PathfinderPassability& passability : m_PassClasses)
     188           0 :             if (passability.m_Clearance > max)
     189           0 :                 max = passability.m_Clearance;
     190             : 
     191           0 :         return max + Pathfinding::CLEARANCE_EXTENSION_RADIUS;
     192             :     }
     193             : 
     194             :     const Grid<NavcellData>& GetPassabilityGrid() override;
     195             : 
     196           0 :     const GridUpdateInformation& GetAIPathfinderDirtinessInformation() const override
     197             :     {
     198           0 :         return m_AIPathfinderDirtinessInformation;
     199             :     }
     200             : 
     201           3 :     void FlushAIPathfinderDirtinessInformation() override
     202             :     {
     203           3 :         m_AIPathfinderDirtinessInformation.Clean();
     204           3 :     }
     205             : 
     206             :     Grid<u16> ComputeShoreGrid(bool expandOnWater = false) override;
     207             : 
     208             :     void ComputePathImmediate(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) const override;
     209             : 
     210             :     u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify) override;
     211             : 
     212             :     WaypointPath ComputeShortPathImmediate(const ShortPathRequest& request) const override;
     213             : 
     214             :     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) override;
     215             : 
     216             :     bool IsGoalReachable(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) override;
     217             : 
     218             :     void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass) override;
     219             : 
     220             :     void SetDebugOverlay(bool enabled) override;
     221             : 
     222             :     void SetHierDebugOverlay(bool enabled) override;
     223             : 
     224             :     void GetDebugData(u32& steps, double& time, Grid<u8>& grid) const override;
     225             : 
     226             :     void SetAtlasOverlay(bool enable, pass_class_t passClass = 0) override;
     227             : 
     228             :     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 override;
     229             : 
     230             :     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 override;
     231             : 
     232             :     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 override;
     233             : 
     234             :     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 override;
     235             : 
     236             :     void SendRequestedPaths() override;
     237             : 
     238             :     void StartProcessingMoves(bool useMax) override;
     239             : 
     240             :     template <typename T>
     241             :     std::vector<T> GetMovesToProcess(std::vector<T>& requests, bool useMax = false, size_t maxMoves = 0);
     242             : 
     243             :     template <typename T>
     244             :     void PushRequestsToWorkers(std::vector<T>& from);
     245             : 
     246             :     /**
     247             :      * Regenerates the grid based on the current obstruction list, if necessary
     248             :      */
     249             :     void UpdateGrid() override;
     250             : 
     251             :     /**
     252             :      * Updates the terrain-only grid without updating the dirtiness informations.
     253             :      * Useful for fast passability updates in Atlas.
     254             :      */
     255             :     void MinimalTerrainUpdate(int itile0, int jtile0, int itile1, int jtile1);
     256             : 
     257             :     /**
     258             :      * Regenerates the terrain-only grid.
     259             :      * Atlas doesn't need to have passability cells expanded.
     260             :      */
     261             :     void TerrainUpdateHelper(bool expandPassability = true, int itile0 = -1, int jtile0 = -1, int itile1 = -1, int jtile1 = -1);
     262             : 
     263             :     void RenderSubmit(SceneCollector& collector);
     264             : };
     265             : 
     266           0 : class AtlasOverlay : public TerrainTextureOverlay
     267             : {
     268             : public:
     269             :     const CCmpPathfinder* m_Pathfinder;
     270             :     pass_class_t m_PassClass;
     271             : 
     272           0 :     AtlasOverlay(const CCmpPathfinder* pathfinder, pass_class_t passClass) :
     273           0 :         TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TERRAIN_TILE), m_Pathfinder(pathfinder), m_PassClass(passClass)
     274             :     {
     275           0 :     }
     276             : 
     277           0 :     void BuildTextureRGBA(u8* data, size_t w, size_t h) override
     278             :     {
     279             :         // Render navcell passability, based on the terrain-only grid
     280           0 :         u8* p = data;
     281           0 :         for (size_t j = 0; j < h; ++j)
     282             :         {
     283           0 :             for (size_t i = 0; i < w; ++i)
     284             :             {
     285           0 :                 SColor4ub color(0, 0, 0, 0);
     286           0 :                 if (!IS_PASSABLE(m_Pathfinder->m_TerrainOnlyGrid->get((int)i, (int)j), m_PassClass))
     287           0 :                     color = SColor4ub(255, 0, 0, 127);
     288             : 
     289           0 :                 *p++ = color.R;
     290           0 :                 *p++ = color.G;
     291           0 :                 *p++ = color.B;
     292           0 :                 *p++ = color.A;
     293             :             }
     294             :         }
     295           0 :     }
     296             : };
     297             : 
     298             : #endif // INCLUDED_CCMPPATHFINDER_COMMON

Generated by: LCOV version 1.13