Update to 1.10.0-beta1

This commit is contained in:
dP
2019-10-31 22:24:28 +03:00
parent b84a475e14
commit 599ccf0c2b
1470 changed files with 354219 additions and 16795 deletions
+149 -35
View File
@@ -11,12 +11,96 @@
#include "../../stdafx.h"
#include "../../ship.h"
#include "../../industry.h"
#include "../../vehicle_func.h"
#include "yapf.hpp"
#include "yapf_node_ship.hpp"
#include "../../safeguards.h"
template <class Types>
class CYapfDestinationTileWaterT
{
public:
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
typedef typename Types::TrackFollower TrackFollower;
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
typedef typename Node::Key Key; ///< key to hash tables
protected:
TileIndex m_destTile;
TrackdirBits m_destTrackdirs;
StationID m_destStation;
public:
void SetDestination(const Ship *v)
{
if (v->current_order.IsType(OT_GOTO_STATION)) {
m_destStation = v->current_order.GetDestination();
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
m_destTrackdirs = INVALID_TRACKDIR_BIT;
} else {
m_destStation = INVALID_STATION;
m_destTile = v->dest_tile;
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
}
}
protected:
/** to access inherited path finder */
inline Tpf& Yapf()
{
return *static_cast<Tpf*>(this);
}
public:
/** Called by YAPF to detect if node ends in the desired destination */
inline bool PfDetectDestination(Node& n)
{
return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
}
inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
{
if (m_destStation != INVALID_STATION) {
return IsDockingTile(tile) && IsShipDestinationTile(tile, m_destStation);
}
return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
}
/**
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
*/
inline bool PfCalcEstimate(Node& n)
{
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
if (PfDetectDestination(n)) {
n.m_estimate = n.m_cost;
return true;
}
TileIndex tile = n.m_segment_last_tile;
DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
int x2 = 2 * TileX(m_destTile);
int y2 = 2 * TileY(m_destTile);
int dx = abs(x1 - x2);
int dy = abs(y1 - y2);
int dmin = min(dx, dy);
int dxy = abs(dx - dy);
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
n.m_estimate = n.m_cost + d;
assert(n.m_estimate >= n.m_parent->m_estimate);
return true;
}
};
/** Node Follower module of YAPF for ships */
template <class Types>
class CYapfFollowShipT
@@ -75,31 +159,32 @@ public:
/* convert origin trackdir to TrackdirBits */
TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
/* get available trackdirs on the destination tile */
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
/* create pathfinder instance */
Tpf pf;
/* set origin and destination nodes */
pf.SetOrigin(src_tile, trackdirs);
pf.SetDestination(v->dest_tile, dest_trackdirs);
pf.SetDestination(v);
/* find best path */
path_found = pf.FindPath(v);
Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
Node *pNode = pf.GetBestNode();
if (pNode != NULL) {
if (pNode != nullptr) {
uint steps = 0;
for (Node *n = pNode; n->m_parent != NULL; n = n->m_parent) steps++;
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
uint skip = 0;
if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2;
/* walk through the path back to the origin */
Node *pPrevNode = NULL;
while (pNode->m_parent != NULL) {
if (steps > 1 && --steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
TrackdirByte td;
td = pNode->GetTrackdir();
path_cache.push_front(td);
Node *pPrevNode = nullptr;
while (pNode->m_parent != nullptr) {
steps--;
/* Skip tiles at end of path near destination. */
if (skip > 0) skip--;
if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
path_cache.push_front(pNode->GetTrackdir());
}
pPrevNode = pNode;
pNode = pNode->m_parent;
@@ -125,23 +210,20 @@ public:
*/
static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
{
/* get available trackdirs on the destination tile */
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
/* create pathfinder instance */
Tpf pf;
/* set origin and destination nodes */
pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
pf.SetDestination(v->dest_tile, dest_trackdirs);
pf.SetDestination(v);
/* find best path */
if (!pf.FindPath(v)) return false;
Node *pNode = pf.GetBestNode();
if (pNode == NULL) return false;
if (pNode == nullptr) return false;
/* path was found
* walk through the path back to the origin */
while (pNode->m_parent != NULL) {
while (pNode->m_parent != nullptr) {
pNode = pNode->m_parent;
}
@@ -169,6 +251,30 @@ protected:
}
public:
inline int CurveCost(Trackdir td1, Trackdir td2)
{
assert(IsValidTrackdir(td1));
assert(IsValidTrackdir(td2));
if (HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) {
/* 90-deg curve penalty */
return Yapf().PfGetSettings().ship_curve90_penalty;
} else if (td2 != NextTrackdir(td1)) {
/* 45-deg curve penalty */
return Yapf().PfGetSettings().ship_curve45_penalty;
}
return 0;
}
static Vehicle *CountShipProc(Vehicle *v, void *data)
{
uint *count = (uint *)data;
/* Ignore other vehicles (aircraft) and ships inside depot. */
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
return nullptr;
}
/**
* Called by YAPF to calculate the cost from the origin to the given node.
* Calculates only the cost of given node, adds it to the parent node cost
@@ -179,9 +285,13 @@ public:
/* base tile cost depending on distance */
int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
/* additional penalty for curves */
if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
/* new trackdir does not match the next one when going straight */
c += YAPF_TILE_LENGTH;
c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir());
if (IsDockingTile(n.GetTile())) {
/* Check docking tile for occupancy */
uint count = 1;
HasVehicleOnPos(n.GetTile(), &count, &CountShipProc);
c += count * 3 * YAPF_TILE_LENGTH;
}
/* Skipped tile cost for aqueducts. */
@@ -219,30 +329,36 @@ struct CYapfShip_TypesT
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
typedef CYapfFollowShipT<Types> PfFollow; // node follower
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
typedef CYapfDestinationTileT<Types> PfDestination; // destination/distance provider
typedef CYapfDestinationTileWaterT<Types> PfDestination; // destination/distance provider
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
typedef CYapfCostShipT<Types> PfCost; // cost provider
};
/* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */
/* YAPF type 1 - uses TileIndex/Trackdir as Node key */
struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater , CShipNodeListTrackDir> > {};
/* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */
/* YAPF type 2 - uses TileIndex/DiagDirection as Node key */
struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater , CShipNodeListExitDir > > {};
/* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */
struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
static inline bool RequireTrackdirKey()
{
/* If the two curve penalties are not equal, then it is not possible to use the
* ExitDir keyed node list, as it there will be key overlap. Using Trackdir keyed
* nodes means potentially more paths are tested, which would be wasteful if it's
* not necessary.
*/
return _settings_game.pf.yapf.ship_curve45_penalty != _settings_game.pf.yapf.ship_curve90_penalty;
}
/** Ship controller helper - path finder invoker */
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, ShipPathCache &path_cache)
{
/* default is YAPF type 2 */
typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found, ShipPathCache &path_cache);
PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir
/* check if non-default YAPF type needed */
if (_settings_game.pf.forbid_90_deg) {
pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
} else if (_settings_game.pf.yapf.disable_node_optimization) {
pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) {
pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir
}
Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found, path_cache);
@@ -256,13 +372,11 @@ bool YapfShipCheckReverse(const Ship *v)
TileIndex tile = v->tile;
typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir);
PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg
PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir
/* check if non-default YAPF type needed */
if (_settings_game.pf.forbid_90_deg) {
pfnCheckReverseShip = &CYapfShip3::CheckShipReverse; // Trackdir, forbid 90-deg
} else if (_settings_game.pf.yapf.disable_node_optimization) {
pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir, allow 90-deg
if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) {
pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir
}
bool reverse = pfnCheckReverseShip(v, tile, td, td_rev);