44
55#include " GamePlayer.h"
66#include " helpers/EnumRange.h"
7+ #include " helpers/IdRange.h"
78#include " pathfinding/FreePathFinder.h"
89#include " pathfinding/FreePathFinderImpl.h"
910#include " pathfinding/PathConditionHuman.h"
1011#include " pathfinding/PathConditionShip.h"
1112#include " pathfinding/PathConditionTrade.h"
1213#include " pathfinding/RoadPathFinder.h"
14+ #include " pathfinding/ShipPathData.h"
1315#include " world/GameWorld.h"
1416#include " gameTypes/ShipDirection.h"
1517#include " gameData/GameConsts.h"
@@ -51,11 +53,10 @@ RoadPathDirection GameWorld::FindPathForWareOnRoads(const noRoadNode& start, con
5153}
5254
5355bool GameWorldBase::FindShipPathToHarbor (const MapPoint start, HarborId harborId, SeaId seaId,
54- std::vector<Direction>* route, unsigned * length)
56+ std::vector<Direction>* route, unsigned * length) const
5557{
56- // Find the distance to the furthest harbor from the target harbor and take that as maximum
57- unsigned maxDistance = 0 ;
5858 const MapPoint coastalPoint = GetCoastalPoint (harborId, seaId);
59+ RTTR_Assert (coastalPoint.isValid ());
5960
6061 // already arrived?
6162 if (start == coastalPoint)
@@ -66,23 +67,52 @@ bool GameWorldBase::FindShipPathToHarbor(const MapPoint start, HarborId harborId
6667 route->clear ();
6768 return true ;
6869 }
70+ auto & shipPathData = GetShipPathData ();
71+ // If we start from a harbor we can get the route directly w/o the costly pathfinding
72+ for (const auto startHbId : helpers::idRange<HarborId>(GetNumHarborPoints ()))
73+ {
74+ if (GetCoastalPoint (startHbId, seaId) == start)
75+ {
76+ auto hbRoute = shipPathData.getHarborConnection (startHbId, harborId, seaId);
77+ if (length)
78+ *length = hbRoute.size ();
79+ if (route)
80+ *route = std::move (hbRoute);
81+ }
82+ }
6983
70- for (const auto dir : helpers::EnumRange<ShipDirection>{})
84+ // Try cache first
85+ bool reversed = false ;
86+ if (const auto * cachedPath = shipPathData.findCachedPath (start, coastalPoint, reversed))
7187 {
72- const std::vector<HarborPos::Neighbor>& neighbors = GetHarborNeighbors (harborId, dir);
73- for (const HarborPos::Neighbor& neighbor : neighbors)
88+ if (route)
7489 {
75- if (IsHarborAtSea (neighbor.id , seaId) && neighbor.distance > maxDistance)
76- maxDistance = neighbor.distance ;
90+ *route = *cachedPath;
91+ if (reversed)
92+ {
93+ std::reverse (route->begin (), route->end ());
94+ for (auto & d : *route)
95+ d = d + 3u ; // reverse direction
96+ }
7797 }
98+ if (length)
99+ *length = cachedPath->size ();
100+ return true ;
78101 }
79- // Add a few fields reserve
80- maxDistance += 6 ;
81- return FindShipPath (start, coastalPoint, maxDistance, route, length);
102+
103+ // Not in cache -> compute full path and add
104+ std::vector<Direction> newRoute;
105+ if (!FindShipPath (start, coastalPoint, std::numeric_limits<unsigned >::max (), &newRoute, length))
106+ return false ;
107+ shipPathData.addToCache (start, coastalPoint, newRoute);
108+ if (route)
109+ *route = std::move (newRoute);
110+
111+ return true ;
82112}
83113
84114bool GameWorldBase::FindShipPath (const MapPoint start, const MapPoint dest, unsigned maxDistance,
85- std::vector<Direction>* route, unsigned * length)
115+ std::vector<Direction>* route, unsigned * length) const
86116{
87117 return GetFreePathFinder ().FindPath (start, dest, true , maxDistance, route, length, nullptr ,
88118 PathConditionShip (*this ));
0 commit comments