Merge branch 'master' into infrastructure_sharing
Conflicts: src/aircraft_cmd.cpp src/economy.cpp src/lang/english.txt src/order_gui.cpp src/roadveh_cmd.cpp src/saveload/saveload.cpp src/settings.cpp src/settings_gui.cpp src/train_cmd.cpp
This commit is contained in:
@@ -78,6 +78,8 @@ struct CFollowTrackT
|
||||
m_veh_owner = o;
|
||||
m_pPerf = pPerf;
|
||||
/* don't worry, all is inlined so compiler should remove unnecessary initializations */
|
||||
m_old_tile = INVALID_TILE;
|
||||
m_old_td = INVALID_TRACKDIR;
|
||||
m_new_tile = INVALID_TILE;
|
||||
m_new_td_bits = TRACKDIR_BIT_NONE;
|
||||
m_exitdir = INVALID_DIAGDIR;
|
||||
@@ -87,13 +89,13 @@ struct CFollowTrackT
|
||||
m_railtypes = railtype_override;
|
||||
}
|
||||
|
||||
inline static TransportType TT() {return Ttr_type_;}
|
||||
inline static bool IsWaterTT() {return TT() == TRANSPORT_WATER;}
|
||||
inline static bool IsRailTT() {return TT() == TRANSPORT_RAIL;}
|
||||
inline bool IsTram() {return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM);}
|
||||
inline static bool IsRoadTT() {return TT() == TRANSPORT_ROAD;}
|
||||
inline static bool Allow90degTurns() {return T90deg_turns_allowed_;}
|
||||
inline static bool DoTrackMasking() {return IsRailTT() && Tmask_reserved_tracks;}
|
||||
inline static TransportType TT() { return Ttr_type_; }
|
||||
inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; }
|
||||
inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; }
|
||||
inline bool IsTram() { return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM); }
|
||||
inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; }
|
||||
inline static bool Allow90degTurns() { return T90deg_turns_allowed_; }
|
||||
inline static bool DoTrackMasking() { return Tmask_reserved_tracks; }
|
||||
|
||||
/** Tests if a tile is a road tile with a single tramtrack (tram can reverse) */
|
||||
inline DiagDirection GetSingleTramBit(TileIndex tile)
|
||||
@@ -122,16 +124,15 @@ struct CFollowTrackT
|
||||
m_old_tile = old_tile;
|
||||
m_old_td = old_td;
|
||||
m_err = EC_NONE;
|
||||
assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() && m_veh != NULL ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
|
||||
assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
|
||||
(IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits
|
||||
m_exitdir = TrackdirToExitdir(m_old_td);
|
||||
if (ForcedReverse()) return true;
|
||||
if (!CanExitOldTile()) return false;
|
||||
FollowTileExit();
|
||||
if (!QueryNewTileTrackStatus()) return TryReverse();
|
||||
if (!CanEnterNewTile()) return false;
|
||||
m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir);
|
||||
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
|
||||
if (m_new_td_bits == TRACKDIR_BIT_NONE || !CanEnterNewTile()) {
|
||||
/* In case we can't enter the next tile, but are
|
||||
* a normal road vehicle, then we can actually
|
||||
* try to reverse as this is the end of the road.
|
||||
@@ -234,7 +235,7 @@ protected:
|
||||
if (IsRailTT() && IsPlainRailTile(m_new_tile)) {
|
||||
m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101);
|
||||
} else {
|
||||
m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() && m_veh != NULL ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0));
|
||||
m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0));
|
||||
|
||||
if (IsTram() && m_new_td_bits == 0) {
|
||||
/* GetTileTrackStatus() returns 0 for single tram bits.
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "../../core/alloc_func.hpp"
|
||||
#include "aystar.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/**
|
||||
* This looks in the hash whether a node exists in the closed list.
|
||||
* @param node Node to search.
|
||||
@@ -124,7 +126,7 @@ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent)
|
||||
/* The f-value if g + h */
|
||||
new_f = new_g + new_h;
|
||||
|
||||
/* Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList) */
|
||||
/* Get the pointer to the parent in the ClosedList (the current one is to a copy of the one in the OpenList) */
|
||||
closedlist_parent = this->ClosedListIsInList(&parent->path.node);
|
||||
|
||||
/* Check if this item is already in the OpenList */
|
||||
|
||||
@@ -64,7 +64,7 @@ struct AyStar;
|
||||
/**
|
||||
* Check whether the end-tile is found.
|
||||
* @param aystar %AyStar search algorithm data.
|
||||
* @param current Node to examone.
|
||||
* @param current Node to exam one.
|
||||
* @note The 2nd parameter should be #OpenListNode, and \em not #AyStarNode. #AyStarNode is
|
||||
* part of #OpenListNode and so it could be accessed without any problems.
|
||||
* The good part about #OpenListNode is, and how AIs use it, that you can
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "../follow_track.hpp"
|
||||
#include "aystar.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
static const uint NPF_HASH_BITS = 12; ///< The size of the hash used in pathfinding. Just changing this value should be sufficient to change the hash size. Should be an even value.
|
||||
/* Do no change below values */
|
||||
static const uint NPF_HASH_SIZE = 1 << NPF_HASH_BITS;
|
||||
@@ -101,7 +103,7 @@ static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the minimum distance traveled to get from t0 to t1 when only
|
||||
* Calculates the minimum distance travelled to get from t0 to t1 when only
|
||||
* using tracks (ie, only making 45 degree turns). Returns the distance in the
|
||||
* NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to
|
||||
* prevent rounding.
|
||||
@@ -146,7 +148,7 @@ static int32 NPFCalcZero(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calcs the heuristic to the target station or tile. For train stations, it
|
||||
/* Calculates the heuristic to the target station or tile. For train stations, it
|
||||
* takes into account the direction of approach.
|
||||
*/
|
||||
static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
||||
@@ -246,7 +248,7 @@ static uint NPFSlopeCost(AyStarNode *current)
|
||||
}
|
||||
return 0;
|
||||
/* Should we give a bonus for slope down? Probably not, we
|
||||
* could just substract that bonus from the penalty, because
|
||||
* could just subtract that bonus from the penalty, because
|
||||
* there is only one level of steepness... */
|
||||
}
|
||||
|
||||
@@ -570,7 +572,7 @@ static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current)
|
||||
* Find the node containing the first signal on the path.
|
||||
*
|
||||
* If the first signal is on the very first two tiles of the path,
|
||||
* the second signal is returnd. If no suitable signal is present, the
|
||||
* the second signal is returned. If no suitable signal is present, the
|
||||
* last node of the path is returned.
|
||||
*/
|
||||
static const PathNode *FindSafePosition(PathNode *path, const Train *v)
|
||||
@@ -1059,7 +1061,7 @@ static NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir track
|
||||
/* Search using breadth first. Good for little track choice and inaccurate
|
||||
* heuristic, such as railway/road with two start nodes, the second being the reverse. Call
|
||||
* NPFGetFlag(result.node, NPF_FLAG_REVERSE) to see from which node the path
|
||||
* orginated. All pathfs from the second node will have the given
|
||||
* originated. All paths from the second node will have the given
|
||||
* reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full
|
||||
* tile).
|
||||
*/
|
||||
@@ -1185,6 +1187,23 @@ Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir,
|
||||
return TrackdirToTrack(ftd.best_trackdir);
|
||||
}
|
||||
|
||||
bool NPFShipCheckReverse(const Ship *v)
|
||||
{
|
||||
NPFFindStationOrTileData fstd;
|
||||
NPFFoundTargetData ftd;
|
||||
|
||||
NPFFillWithOrderData(&fstd, v);
|
||||
|
||||
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||
Trackdir trackdir_rev = ReverseTrackdir(trackdir);
|
||||
assert(trackdir != INVALID_TRACKDIR);
|
||||
assert(trackdir_rev != INVALID_TRACKDIR);
|
||||
|
||||
ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, v->tile, trackdir_rev, false, &fstd, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES);
|
||||
/* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */
|
||||
return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
|
||||
}
|
||||
|
||||
/*** Trains ***/
|
||||
|
||||
FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty)
|
||||
@@ -1247,7 +1266,7 @@ bool NPFTrainCheckReverse(const Train *v)
|
||||
|
||||
ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes);
|
||||
/* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */
|
||||
return ftd.best_bird_dist != 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
|
||||
return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
|
||||
}
|
||||
|
||||
Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target)
|
||||
|
||||
@@ -49,6 +49,13 @@ Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDir
|
||||
*/
|
||||
Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found);
|
||||
|
||||
/**
|
||||
* Returns true if it is better to reverse the ship before leaving depot using NPF.
|
||||
* @param v the ship leaving the depot
|
||||
* @return true if reversing is better
|
||||
*/
|
||||
bool NPFShipCheckReverse(const Ship *v);
|
||||
|
||||
/**
|
||||
* Used when user sends train to the nearest depot or if train needs servicing using NPF
|
||||
* @param v train that needs to go to some depot
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "../../core/alloc_func.hpp"
|
||||
#include "queue.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
|
||||
/*
|
||||
* Binary Heap
|
||||
@@ -158,7 +160,7 @@ bool BinaryHeap::Delete(void *item, int priority)
|
||||
|
||||
for (;;) {
|
||||
j = i;
|
||||
/* Check if we have 2 childs */
|
||||
/* Check if we have 2 children */
|
||||
if (2 * j + 1 <= this->size) {
|
||||
/* Is this child smaller than the parent? */
|
||||
if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
|
||||
@@ -170,13 +172,13 @@ bool BinaryHeap::Delete(void *item, int priority)
|
||||
if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
|
||||
}
|
||||
|
||||
/* One of our childs is smaller than we are, switch */
|
||||
/* One of our children is smaller than we are, switch */
|
||||
if (i != j) {
|
||||
temp = this->GetElement(j);
|
||||
this->GetElement(j) = this->GetElement(i);
|
||||
this->GetElement(i) = temp;
|
||||
} else {
|
||||
/* None of our childs is smaller, so we stay here.. stop :) */
|
||||
/* None of our children is smaller, so we stay here.. stop :) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "../../ship.h"
|
||||
#include "../../core/random_func.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
struct RememberData {
|
||||
uint16 cur_length;
|
||||
byte depth;
|
||||
@@ -193,7 +195,8 @@ Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir,
|
||||
Track track;
|
||||
|
||||
/* Let's find out how far it would be if we would reverse first */
|
||||
TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & v->state;
|
||||
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||
TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & TrackdirBitsToTrackBits(TrackdirToTrackdirBits(trackdir));
|
||||
|
||||
uint distr = UINT_MAX; // distance if we reversed
|
||||
if (b != 0) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
static const int NPF_TILE_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* This penalty is the equivalent of "infite", which means that paths that
|
||||
* This penalty is the equivalent of "infinite", which means that paths that
|
||||
* get this penalty will be chosen, but only if there is no other route
|
||||
* without it. Be careful with not applying this penalty to often, or the
|
||||
* total path cost might overflow..
|
||||
@@ -33,7 +33,7 @@ static const int YAPF_TILE_LENGTH = 100;
|
||||
static const int YAPF_TILE_CORNER_LENGTH = 71;
|
||||
|
||||
/**
|
||||
* This penalty is the equivalent of "infite", which means that paths that
|
||||
* This penalty is the equivalent of "infinite", which means that paths that
|
||||
* get this penalty will be chosen, but only if there is no other route
|
||||
* without it. Be careful with not applying this penalty to often, or the
|
||||
* total path cost might overflow..
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
*/
|
||||
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found);
|
||||
|
||||
/**
|
||||
* Returns true if it is better to reverse the ship before leaving depot using YAPF.
|
||||
* @param v the ship leaving the depot
|
||||
* @return true if reversing is better
|
||||
*/
|
||||
bool YapfShipCheckReverse(const Ship *v);
|
||||
|
||||
/**
|
||||
* Finds the best path for given road vehicle using YAPF.
|
||||
* @param v the RV that needs to find a path
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "../../misc/dbg_helpers.h"
|
||||
#include "nodelist.hpp"
|
||||
#include "../follow_track.hpp"
|
||||
#include "yapf_type.hpp"
|
||||
#include "yapf_base.hpp"
|
||||
#include "yapf_node.hpp"
|
||||
#include "yapf_common.hpp"
|
||||
|
||||
@@ -34,8 +34,8 @@ extern int _total_pf_time_us;
|
||||
* you need to declare only your node type. Look at test_yapf.h for an example.
|
||||
*
|
||||
*
|
||||
* Requrements to your pathfinder class derived from CYapfBaseT:
|
||||
* -------------------------------------------------------------
|
||||
* Requirements to your pathfinder class derived from CYapfBaseT:
|
||||
* --------------------------------------------------------------
|
||||
* Your pathfinder derived class needs to implement following methods:
|
||||
* inline void PfSetStartupNodes()
|
||||
* inline void PfFollowNode(Node& org)
|
||||
@@ -223,6 +223,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In some cases an intermediate node branch should be pruned.
|
||||
* The most prominent case is when a red EOL signal is encountered, but
|
||||
* there was a segment change (e.g. a rail type change) before that. If
|
||||
* the branch would not be pruned, the rail type change location would
|
||||
* remain the best intermediate node, and thus the vehicle would still
|
||||
* go towards the red EOL signal.
|
||||
*/
|
||||
void PruneIntermediateNodeBranch()
|
||||
{
|
||||
while (Yapf().m_pBestIntermediateNode != NULL && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) {
|
||||
Yapf().m_pBestIntermediateNode = Yapf().m_pBestIntermediateNode->m_parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AddNewNode() - called by Tderived::PfFollowNode() for each child node.
|
||||
* Nodes are evaluated here and added into open list
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
/** Base implementation for cost accounting. */
|
||||
struct CYapfCostBase {
|
||||
/**
|
||||
* Does the given track direction on the given tile yeild an uphill penalty?
|
||||
* Does the given track direction on the given tile yield an uphill penalty?
|
||||
* @param tile The tile to check.
|
||||
* @param td The track direction to check.
|
||||
* @return True if there's a slope, otherwise false.
|
||||
|
||||
@@ -212,7 +212,8 @@ public:
|
||||
/* we have a red signal in our direction
|
||||
* was it first signal which is two-way? */
|
||||
if (!IsPbsSignal(sig_type) && Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
|
||||
/* yes, the first signal is two-way red signal => DEAD END */
|
||||
/* yes, the first signal is two-way red signal => DEAD END. Prune this branch... */
|
||||
Yapf().PruneIntermediateNodeBranch();
|
||||
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
||||
Yapf().m_stopped_on_first_two_way_signal = true;
|
||||
return -1;
|
||||
|
||||
@@ -61,75 +61,6 @@ struct CYapfRailSegmentKey
|
||||
}
|
||||
};
|
||||
|
||||
/* Enum used in PfCalcCost() to see why was the segment closed. */
|
||||
enum EndSegmentReason {
|
||||
/* The following reasons can be saved into cached segment */
|
||||
ESR_DEAD_END = 0, ///< track ends here
|
||||
ESR_RAIL_TYPE, ///< the next tile has a different rail type than our tiles
|
||||
ESR_INFINITE_LOOP, ///< infinite loop detected
|
||||
ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop)
|
||||
ESR_CHOICE_FOLLOWS, ///< the next tile contains a choice (the track splits to more than one segments)
|
||||
ESR_DEPOT, ///< stop in the depot (could be a target next time)
|
||||
ESR_WAYPOINT, ///< waypoint encountered (could be a target next time)
|
||||
ESR_STATION, ///< station encountered (could be a target next time)
|
||||
ESR_SAFE_TILE, ///< safe waiting position found (could be a target)
|
||||
|
||||
/* The following reasons are used only internally by PfCalcCost().
|
||||
* They should not be found in the cached segment. */
|
||||
ESR_PATH_TOO_LONG, ///< the path is too long (searching for the nearest depot in the given radius)
|
||||
ESR_FIRST_TWO_WAY_RED, ///< first signal was 2-way and it was red
|
||||
ESR_LOOK_AHEAD_END, ///< we have just passed the last look-ahead signal
|
||||
ESR_TARGET_REACHED, ///< we have just reached the destination
|
||||
|
||||
/* Special values */
|
||||
ESR_NONE = 0xFF, ///< no reason to end the segment here
|
||||
};
|
||||
|
||||
enum EndSegmentReasonBits {
|
||||
ESRB_NONE = 0,
|
||||
|
||||
ESRB_DEAD_END = 1 << ESR_DEAD_END,
|
||||
ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE,
|
||||
ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP,
|
||||
ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG,
|
||||
ESRB_CHOICE_FOLLOWS = 1 << ESR_CHOICE_FOLLOWS,
|
||||
ESRB_DEPOT = 1 << ESR_DEPOT,
|
||||
ESRB_WAYPOINT = 1 << ESR_WAYPOINT,
|
||||
ESRB_STATION = 1 << ESR_STATION,
|
||||
ESRB_SAFE_TILE = 1 << ESR_SAFE_TILE,
|
||||
|
||||
ESRB_PATH_TOO_LONG = 1 << ESR_PATH_TOO_LONG,
|
||||
ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED,
|
||||
ESRB_LOOK_AHEAD_END = 1 << ESR_LOOK_AHEAD_END,
|
||||
ESRB_TARGET_REACHED = 1 << ESR_TARGET_REACHED,
|
||||
|
||||
/* Additional (composite) values. */
|
||||
|
||||
/* What reasons mean that the target can be found and needs to be detected. */
|
||||
ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
|
||||
|
||||
/* What reasons can be stored back into cached segment. */
|
||||
ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
|
||||
|
||||
/* Reasons to abort pathfinding in this direction. */
|
||||
ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits)
|
||||
|
||||
inline CStrA ValueStr(EndSegmentReasonBits bits)
|
||||
{
|
||||
static const char * const end_segment_reason_names[] = {
|
||||
"DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
|
||||
"DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
|
||||
"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED"
|
||||
};
|
||||
|
||||
CStrA out;
|
||||
out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data());
|
||||
return out.Transfer();
|
||||
}
|
||||
|
||||
/** cached segment cost for rail YAPF */
|
||||
struct CYapfRailSegment
|
||||
{
|
||||
@@ -265,7 +196,7 @@ struct CYapfRailNodeT
|
||||
while (cur != GetLastTile() || cur_td != GetLastTrackdir()) {
|
||||
if (!((obj.*func)(cur, cur_td))) return false;
|
||||
|
||||
ft.Follow(cur, cur_td);
|
||||
if (!ft.Follow(cur, cur_td)) break;
|
||||
cur = ft.m_new_tile;
|
||||
assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE);
|
||||
cur_td = FindFirstTrackdir(ft.m_new_td_bits);
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
#include "yapf_costrail.hpp"
|
||||
#include "yapf_destrail.hpp"
|
||||
#include "../../viewport_func.h"
|
||||
#include "../../newgrf_station.h"
|
||||
|
||||
#define DEBUG_YAPF_CACHE 0
|
||||
#include "../../safeguards.h"
|
||||
|
||||
#if DEBUG_YAPF_CACHE
|
||||
template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
|
||||
{
|
||||
DumpTarget dmp1, dmp2;
|
||||
@@ -33,7 +33,6 @@ template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
|
||||
fclose(f1);
|
||||
fclose(f2);
|
||||
}
|
||||
#endif
|
||||
|
||||
int _total_pf_time_us = 0;
|
||||
|
||||
@@ -83,6 +82,8 @@ private:
|
||||
tile = TILE_ADD(tile, diff);
|
||||
} while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile);
|
||||
|
||||
TriggerStationRandomisation(NULL, start, SRT_PATH_RESERVATION);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -237,17 +238,17 @@ public:
|
||||
if (max_penalty != 0) pf1.DisableCache(true);
|
||||
bool result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty, depot_tile, reversed);
|
||||
|
||||
#if DEBUG_YAPF_CACHE
|
||||
Tpf pf2;
|
||||
TileIndex depot_tile2 = INVALID_TILE;
|
||||
bool reversed2 = false;
|
||||
pf2.DisableCache(true);
|
||||
bool result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty, &depot_tile2, &reversed2);
|
||||
if (result1 != result2 || (result1 && (*depot_tile != depot_tile2 || *reversed != reversed2))) {
|
||||
DEBUG(yapf, 0, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
if (_debug_desync_level >= 2) {
|
||||
Tpf pf2;
|
||||
TileIndex depot_tile2 = INVALID_TILE;
|
||||
bool reversed2 = false;
|
||||
pf2.DisableCache(true);
|
||||
bool result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty, &depot_tile2, &reversed2);
|
||||
if (result1 != result2 || (result1 && (*depot_tile != depot_tile2 || *reversed != reversed2))) {
|
||||
DEBUG(desync, 2, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result1;
|
||||
}
|
||||
@@ -322,19 +323,19 @@ public:
|
||||
{
|
||||
/* Create pathfinder instance */
|
||||
Tpf pf1;
|
||||
#if !DEBUG_YAPF_CACHE
|
||||
bool result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false);
|
||||
|
||||
#else
|
||||
bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true);
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
bool result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false);
|
||||
if (result1 != result2) {
|
||||
DEBUG(yapf, 0, "CACHE ERROR: FindSafeTile() = [%s, %s]", result2 ? "T" : "F", result1 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
bool result1;
|
||||
if (_debug_desync_level < 2) {
|
||||
result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false);
|
||||
} else {
|
||||
bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true);
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false);
|
||||
if (result1 != result2) {
|
||||
DEBUG(desync, 2, "CACHE ERROR: FindSafeTile() = [%s, %s]", result2 ? "T" : "F", result1 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result1;
|
||||
}
|
||||
@@ -405,19 +406,20 @@ public:
|
||||
{
|
||||
/* create pathfinder instance */
|
||||
Tpf pf1;
|
||||
#if !DEBUG_YAPF_CACHE
|
||||
Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
Trackdir result1;
|
||||
|
||||
#else
|
||||
Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, NULL);
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
if (result1 != result2) {
|
||||
DEBUG(yapf, 0, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1, result2);
|
||||
DumpState(pf1, pf2);
|
||||
if (_debug_desync_level < 2) {
|
||||
result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
} else {
|
||||
result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, NULL);
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
if (result1 != result2) {
|
||||
DEBUG(desync, 2, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1, result2);
|
||||
DumpState(pf1, pf2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result1;
|
||||
}
|
||||
@@ -467,15 +469,15 @@ public:
|
||||
Tpf pf1;
|
||||
bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
|
||||
|
||||
#if DEBUG_YAPF_CACHE
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
|
||||
if (result1 != result2) {
|
||||
DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
if (_debug_desync_level >= 2) {
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
|
||||
if (result1 != result2) {
|
||||
DEBUG(desync, 2, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
|
||||
DumpState(pf1, pf2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result1;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "yapf_node_road.hpp"
|
||||
#include "../../roadstop_base.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
|
||||
template <class Types>
|
||||
class CYapfCostRoadT
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "yapf.hpp"
|
||||
#include "yapf_node_ship.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/** Node Follower module of YAPF for ships */
|
||||
template <class Types>
|
||||
class CYapfFollowShipT
|
||||
@@ -58,9 +60,12 @@ public:
|
||||
if (tile == v->dest_tile) {
|
||||
/* convert tracks to trackdirs */
|
||||
TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
|
||||
/* choose any trackdir reachable from enterdir */
|
||||
/* limit to trackdirs reachable from enterdir */
|
||||
trackdirs &= DiagdirReachesTrackdirs(enterdir);
|
||||
return (Trackdir)FindFirstBit2x64(trackdirs);
|
||||
|
||||
/* use vehicle's current direction if that's possible, otherwise use first usable one. */
|
||||
Trackdir veh_dir = v->GetVehicleTrackdir();
|
||||
return ((trackdirs & TrackdirToTrackdirBits(veh_dir)) != 0) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs);
|
||||
}
|
||||
|
||||
/* move back to the old tile/trackdir (where ship is coming from) */
|
||||
@@ -98,6 +103,42 @@ public:
|
||||
}
|
||||
return next_trackdir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a ship should reverse to reach its destination.
|
||||
* Called when leaving depot.
|
||||
* @param v Ship
|
||||
* @param tile Current position
|
||||
* @param td1 Forward direction
|
||||
* @param td2 Reverse direction
|
||||
* @return true if the reverse direction is better
|
||||
*/
|
||||
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);
|
||||
/* find best path */
|
||||
if (!pf.FindPath(v)) return false;
|
||||
|
||||
Node *pNode = pf.GetBestNode();
|
||||
if (pNode == NULL) return false;
|
||||
|
||||
/* path was found
|
||||
* walk through the path back to the origin */
|
||||
while (pNode->m_parent != NULL) {
|
||||
pNode = pNode->m_parent;
|
||||
}
|
||||
|
||||
Trackdir best_trackdir = pNode->GetTrackdir();
|
||||
assert(best_trackdir == td1 || best_trackdir == td2);
|
||||
return best_trackdir == td2;
|
||||
}
|
||||
};
|
||||
|
||||
/** Cost Provider module of YAPF for ships */
|
||||
@@ -128,7 +169,7 @@ 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.m_parent != NULL && n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
|
||||
if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
|
||||
/* new trackdir does not match the next one when going straight */
|
||||
c += YAPF_TILE_LENGTH;
|
||||
}
|
||||
@@ -197,3 +238,24 @@ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir,
|
||||
Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found);
|
||||
return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
|
||||
}
|
||||
|
||||
bool YapfShipCheckReverse(const Ship *v)
|
||||
{
|
||||
Trackdir td = v->GetVehicleTrackdir();
|
||||
Trackdir td_rev = ReverseTrackdir(td);
|
||||
TileIndex tile = v->tile;
|
||||
|
||||
typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir);
|
||||
PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
bool reverse = pfnCheckReverseShip(v, tile, td, td_rev);
|
||||
|
||||
return reverse;
|
||||
}
|
||||
|
||||
84
src/pathfinder/yapf/yapf_type.hpp
Normal file
84
src/pathfinder/yapf/yapf_type.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file yapf_type.hpp Types used by YAPF. */
|
||||
|
||||
#ifndef YAPF_TYPE_HPP
|
||||
#define YAPF_TYPE_HPP
|
||||
|
||||
/* Enum used in PfCalcCost() to see why was the segment closed. */
|
||||
enum EndSegmentReason {
|
||||
/* The following reasons can be saved into cached segment */
|
||||
ESR_DEAD_END = 0, ///< track ends here
|
||||
ESR_RAIL_TYPE, ///< the next tile has a different rail type than our tiles
|
||||
ESR_INFINITE_LOOP, ///< infinite loop detected
|
||||
ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop)
|
||||
ESR_CHOICE_FOLLOWS, ///< the next tile contains a choice (the track splits to more than one segments)
|
||||
ESR_DEPOT, ///< stop in the depot (could be a target next time)
|
||||
ESR_WAYPOINT, ///< waypoint encountered (could be a target next time)
|
||||
ESR_STATION, ///< station encountered (could be a target next time)
|
||||
ESR_SAFE_TILE, ///< safe waiting position found (could be a target)
|
||||
|
||||
/* The following reasons are used only internally by PfCalcCost().
|
||||
* They should not be found in the cached segment. */
|
||||
ESR_PATH_TOO_LONG, ///< the path is too long (searching for the nearest depot in the given radius)
|
||||
ESR_FIRST_TWO_WAY_RED, ///< first signal was 2-way and it was red
|
||||
ESR_LOOK_AHEAD_END, ///< we have just passed the last look-ahead signal
|
||||
ESR_TARGET_REACHED, ///< we have just reached the destination
|
||||
|
||||
/* Special values */
|
||||
ESR_NONE = 0xFF, ///< no reason to end the segment here
|
||||
};
|
||||
|
||||
enum EndSegmentReasonBits {
|
||||
ESRB_NONE = 0,
|
||||
|
||||
ESRB_DEAD_END = 1 << ESR_DEAD_END,
|
||||
ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE,
|
||||
ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP,
|
||||
ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG,
|
||||
ESRB_CHOICE_FOLLOWS = 1 << ESR_CHOICE_FOLLOWS,
|
||||
ESRB_DEPOT = 1 << ESR_DEPOT,
|
||||
ESRB_WAYPOINT = 1 << ESR_WAYPOINT,
|
||||
ESRB_STATION = 1 << ESR_STATION,
|
||||
ESRB_SAFE_TILE = 1 << ESR_SAFE_TILE,
|
||||
|
||||
ESRB_PATH_TOO_LONG = 1 << ESR_PATH_TOO_LONG,
|
||||
ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED,
|
||||
ESRB_LOOK_AHEAD_END = 1 << ESR_LOOK_AHEAD_END,
|
||||
ESRB_TARGET_REACHED = 1 << ESR_TARGET_REACHED,
|
||||
|
||||
/* Additional (composite) values. */
|
||||
|
||||
/* What reasons mean that the target can be found and needs to be detected. */
|
||||
ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
|
||||
|
||||
/* What reasons can be stored back into cached segment. */
|
||||
ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE,
|
||||
|
||||
/* Reasons to abort pathfinding in this direction. */
|
||||
ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits)
|
||||
|
||||
inline CStrA ValueStr(EndSegmentReasonBits bits)
|
||||
{
|
||||
static const char * const end_segment_reason_names[] = {
|
||||
"DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS",
|
||||
"DEPOT", "WAYPOINT", "STATION", "SAFE_TILE",
|
||||
"PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED"
|
||||
};
|
||||
|
||||
CStrA out;
|
||||
out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data());
|
||||
return out.Transfer();
|
||||
}
|
||||
|
||||
#endif /* YAPF_TYPE_HPP */
|
||||
Reference in New Issue
Block a user