10#include "../../stdafx.h"
17#include "../../viewport_func.h"
18#include "../../newgrf_station.h"
20#include "../../safeguards.h"
22template <
typename Tpf>
void DumpState(Tpf &pf1, Tpf &pf2)
29 assert(f1.has_value());
30 assert(f2.has_value());
31 fwrite(dmp1.
m_out.c_str(), 1, dmp1.
m_out.size(), *f1);
32 fwrite(dmp2.
m_out.c_str(), 1, dmp2.
m_out.size(), *f2);
39 typedef typename Types::Tpf
Tpf;
40 typedef typename Types::TrackFollower TrackFollower;
41 typedef typename Types::NodeList::Item
Node;
47 return *
static_cast<Tpf *
>(
this);
63 this->res_dest_tile = tile;
64 this->res_dest_td = td;
95 this->res_fail_tile = tile;
96 this->res_fail_td = td;
101 this->res_fail_tile = tile;
102 this->res_fail_td = td;
108 this->signals_set_to_red.emplace_back(tile, rev_td);
114 return tile != this->res_dest_tile || td != this->
res_dest_td;
127 }
else if (tile != this->res_fail_tile || td != this->res_fail_td) {
130 return (tile != this->res_dest_tile || td != this->res_dest_td) && (tile != this->res_fail_tile || td != this->
res_fail_td);
137 this->res_dest_node = node;
138 this->res_dest_tile = tile;
139 this->res_dest_td = td;
145 assert(node->parent !=
nullptr);
148 if (node->parent->num_signals_passed >= 2)
return;
151 this->res_dest_node = node;
159 this->origin_tile = origin;
161 if (target !=
nullptr) {
164 target->
okay =
false;
170 this->signals_set_to_red.clear();
171 for (
Node *node = this->res_dest_node; node->parent !=
nullptr; node = node->parent) {
179 this->res_fail_tile = fail_node == node ? stop_tile :
INVALID_TILE;
181 }
while (fail_node != node && (fail_node = fail_node->parent) !=
nullptr);
192 if (target !=
nullptr) target->
okay =
true;
194 if (
Yapf().CanUseGlobalCache(*this->res_dest_node)) {
202template <
class Types>
206 typedef typename Types::Tpf
Tpf;
207 typedef typename Types::TrackFollower TrackFollower;
208 typedef typename Types::NodeList::Item
Node;
209 typedef typename Node::Key
Key;
215 return *
static_cast<Tpf *
>(
this);
226 TrackFollower F(
Yapf().GetVehicle());
227 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
228 Yapf().AddMultipleNodes(&old_node, F);
250 if (max_penalty != 0) pf1.DisableCache(
true);
251 FindDepotData result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
253 if (_debug_desync_level >= 2) {
255 pf2.DisableCache(
true);
256 FindDepotData result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
258 Debug(desync, 2,
"warning: FindNearestDepotTwoWay cache mismatch: {} vs {}",
271 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
272 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(
true);
273 Yapf().SetDestination(v);
274 Yapf().SetMaxCost(max_penalty);
284 while (pNode->parent !=
nullptr) {
285 pNode = pNode->parent;
290 return FindDepotData(n->GetLastTile(), n->cost, pNode->cost != 0);
294template <
class Types>
298 typedef typename Types::Tpf
Tpf;
299 typedef typename Types::TrackFollower TrackFollower;
300 typedef typename Types::NodeList::Item
Node;
301 typedef typename Node::Key
Key;
307 return *
static_cast<Tpf *
>(
this);
318 TrackFollower F(
Yapf().GetVehicle(),
Yapf().GetCompatibleRailTypes());
319 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()) && F.MaskReservedTracks()) {
320 Yapf().AddMultipleNodes(&old_node, F);
335 if (_debug_desync_level < 2) {
336 result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype,
false);
338 bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype,
true);
340 pf2.DisableCache(
true);
341 result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype,
false);
342 if (result1 != result2) {
343 Debug(desync, 2,
"warning: FindSafeTile cache mismatch: {} vs {}", result2 ?
"T" :
"F", result1 ?
"T" :
"F");
351 bool FindNearestSafeTile(
const Train *v,
TileIndex t1,
Trackdir td,
bool override_railtype,
bool dont_reserve)
354 Yapf().SetOrigin(t1, td);
355 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(
false);
356 Yapf().SetDestination(v, override_railtype);
358 if (!
Yapf().FindPath(v))
return false;
365 Node *pPrev =
nullptr;
366 while (pNode->parent !=
nullptr) {
368 pNode = pNode->parent;
373 return dont_reserve || this->
TryReservePath(
nullptr, pNode->GetLastTile());
377template <
class Types>
381 typedef typename Types::Tpf
Tpf;
382 typedef typename Types::TrackFollower TrackFollower;
383 typedef typename Types::NodeList::Item
Node;
384 typedef typename Node::Key
Key;
390 return *
static_cast<Tpf *
>(
this);
401 TrackFollower F(
Yapf().GetVehicle());
402 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
403 Yapf().AddMultipleNodes(&old_node, F);
419 if (_debug_desync_level < 2) {
420 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
422 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found,
false,
nullptr,
nullptr);
424 pf2.DisableCache(
true);
425 Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
426 if (result1 != result2) {
427 Debug(desync, 2,
"warning: ChooseRailTrack cache mismatch: {} vs {}", result1, result2);
443 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(
true);
444 Yapf().SetDestination(v);
447 path_found =
Yapf().FindPath(v);
452 if (pNode !=
nullptr) {
458 Node *pPrev =
nullptr;
459 while (pNode->parent !=
nullptr) {
461 pNode = pNode->parent;
471 Node &best_next_node = *pPrev;
472 next_trackdir = best_next_node.GetTrackdir();
474 if (reserve_track && path_found) {
475 if (dest !=
nullptr) *dest =
Yapf().GetBestNode()->GetLastTile();
481 path_found |=
Yapf().stopped_on_first_two_way_signal;
482 return next_trackdir;
488 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
490 if (_debug_desync_level >= 2) {
492 pf2.DisableCache(
true);
493 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
494 if (result1 != result2) {
495 Debug(desync, 2,
"warning: CheckReverseTrain cache mismatch: {} vs {}", result1 ?
"T" :
"F", result2 ?
"T" :
"F");
507 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
508 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(
false);
509 Yapf().SetDestination(v);
512 if (!
Yapf().FindPath(v))
return false;
517 while (pNode->parent !=
nullptr) {
518 pNode = pNode->parent;
522 bool reversed = (pNode->cost != 0);
527template <
class Tpf_,
class Ttrack_follower,
class Tnode_list,
template <
class Types>
class TdestinationT,
template <
class Types>
class TfollowT>
533 typedef Ttrack_follower TrackFollower;
537 typedef TfollowT<Types> PfFollow;
539 typedef TdestinationT<Types> PfDestination;
544struct CYapfRail1 :
CYapfT<CYapfRail_TypesT<CYapfRail1 , CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
545struct CYapfRail2 :
CYapfT<CYapfRail_TypesT<CYapfRail2 , CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
547struct CYapfAnyDepotRail1 :
CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail1, CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
548struct CYapfAnyDepotRail2 :
CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail2, CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
550struct CYapfAnySafeTileRail1 :
CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail1, CFollowTrackFreeRail , CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT> > {};
551struct CYapfAnySafeTileRail2 :
CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail2, CFollowTrackFreeRailNo90, CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT> > {};
557 ? CYapfRail2::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest)
558 : CYapfRail1::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
575 int reverse_penalty = 0;
607 if (reverse_penalty == 0) reverse_penalty = 1;
610 ? CYapfRail2::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty)
611 : CYapfRail1::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
632 ? CYapfAnySafeTileRail2::stFindNearestSafeTile(v, tile, td, override_railtype)
633 : CYapfAnySafeTileRail1::stFindNearestSafeTile(v, tile, td, override_railtype);
641 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);
CYapfBaseT - A-star type path finder base class.
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Tpf & Yapf()
to access inherited path finder
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
char TransportTypeChar() const
return debug report character to identify the transportation type
Types::NodeList::Item Node
this will be our node type
Node::Key Key
key to hash tables
char TransportTypeChar() const
Return debug report character to identify the transportation type.
Node::Key Key
key to hash tables
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Types::NodeList::Item Node
this will be our node type
Tpf & Yapf()
to access inherited path finder
Node::Key Key
key to hash tables
Tpf & Yapf()
to access inherited path finder
char TransportTypeChar() const
return debug report character to identify the transportation type
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Types::NodeList::Item Node
this will be our node type
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
YAPF origin provider base class - used when there are two tile/trackdir origins.
void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
Set the target to where the reservation should be extended.
Types::NodeList::Item Node
this will be our node type
TileIndex res_fail_tile
The tile where the reservation failed.
bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
Unreserve a single track/platform.
bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
Reserve a railway platform.
bool ReserveSingleTrack(TileIndex tile, Trackdir td)
Try to reserve a single track/platform.
std::vector< std::pair< TileIndex, Trackdir > > signals_set_to_red
List of signals turned red during a path reservation.
Trackdir res_fail_td
The trackdir where the reservation failed.
Node * res_dest_node
The reservation target node.
TileIndex origin_tile
Tile our reservation will originate from.
TileIndex res_dest_tile
The reservation target tile.
bool TryReservePath(PBSTileInfo *target, TileIndex origin)
Try to reserve the path till the reservation target.
Tpf & Yapf()
to access inherited pathfinder
void FindSafePositionOnNode(Node *node)
Check the node for a possible reservation target.
Trackdir res_dest_td
The reservation target trackdir.
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost caching functi...
YAPF template that uses Ttypes template argument to determine all YAPF components (base classes) from...
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
Hash table based node list multi-container class.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
DiagDirection
Enumeration for diagonal directions.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
int32_t TileIndexDiff
An offset value between two tiles.
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
@ SRT_PATH_RESERVATION
Trigger platform when train reserves path.
static const int YAPF_INFINITE_PENALTY
This penalty is the equivalent of "infinite", which means that paths that get this penalty will be ch...
static const int YAPF_TILE_LENGTH
Length (penalty) of one tile with YAPF.
PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
Follow a train reservation to the last tile.
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
Determine whether a certain track on a tile is a safe position to end a path.
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
@ SIGNAL_STATE_RED
The signal is red.
@ SIGNAL_STATE_GREEN
The signal is green.
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
void SetRailStationReservation(Tile t, bool b)
Set the reservation state of the rail station.
bool HasStationReservation(Tile t)
Get the reservation state of the rail station.
static int s_rail_change_counter
if any track changes, this counter is incremented - that will invalidate segment cost cache
Class that represents the dump-into-string target.
std::string m_out
the output string
Helper container to find a depot.
bool reverse
True if reversing is necessary for the train to get to this depot.
TileIndex tile
The tile of the depot.
PathfinderSettings pf
settings for all pathfinders
This struct contains information about the end of a reserved path.
Trackdir trackdir
The reserved trackdir on the tile.
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
bool okay
True if tile is a safe waiting position, false otherwise.
bool forbid_90_deg
forbid trains to make 90 deg turns
T * Last()
Get the last vehicle in the chain.
'Train' is either a loco or a wagon.
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
TileIndex tile
Current tile index.
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
TrackBits
Allow incrementing of Track variables.
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels)
Trackdir
Enumeration for tracks and directions.
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Track
These are used to specify a single track.
@ INVALID_TRACK
Flag for an invalid track.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
Base includes/functions for YAPF.
Entry point for OpenTTD to YAPF's cache.
Cost determination for rails.
Determining the destination for rail vehicles.
Node tailored for rail pathfinding.
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.
bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
Try to extend the reserved path of a train to the nearest safe tile using YAPF.
Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
Finds the best path for given train using YAPF.
FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_penalty)
Used when user sends train to the nearest depot or if train needs servicing using YAPF.
bool YapfTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using YAPF.