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:
Jonathan G Rennison
2015-08-06 22:55:09 +01:00
1106 changed files with 149811 additions and 81548 deletions

View File

@@ -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.

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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..

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -14,6 +14,8 @@
#include "yapf_node_road.hpp"
#include "../../roadstop_base.h"
#include "../../safeguards.h"
template <class Types>
class CYapfCostRoadT

View File

@@ -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;
}

View 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 */