OpenTTD Source: src/pathfinder/yapf/yapf_rail.cpp Source File

OpenTTD Source 15.0-beta1

yapf_rail.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10#include "../../stdafx.h"
11
12#include "yapf.hpp"
13#include "yapf_cache.h"
14#include "yapf_node_rail.hpp"
15#include "yapf_costrail.hpp"
16#include "yapf_destrail.hpp"
17#include "../../viewport_func.h"
18#include "../../newgrf_station.h"
19
20#include "../../safeguards.h"
21
22template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
23{
24 DumpTarget dmp1, dmp2;
25 pf1.DumpBase(dmp1);
26 pf2.DumpBase(dmp2);
27 auto f1 = FileHandle::Open("yapf1.txt", "wt");
28 auto f2 = FileHandle::Open("yapf2.txt", "wt");
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);
33}
34
35template <class Types>
36 class CYapfReserveTrack
37{
38public:
39 typedef typename Types::Tpf Tpf;
40 typedef typename Types::TrackFollower TrackFollower;
41 typedef typename Types::NodeList::Item Node;
42
43protected:
45 inline Tpf &Yapf()
46 {
47 return *static_cast<Tpf *>(this);
48 }
49
50private:
51 TileIndex res_dest_tile;
52 Trackdir res_dest_td;
53 Node *res_dest_node;
54 TileIndex res_fail_tile;
55 Trackdir res_fail_td;
56 TileIndex origin_tile;
57
58 std::vector<std::pair<TileIndex, Trackdir>> signals_set_to_red;
59
60 bool FindSafePositionProc(TileIndex tile, Trackdir td)
61 {
62 if (IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns())) {
63 this->res_dest_tile = tile;
64 this->res_dest_td = td;
65 return false; // Stop iterating segment
66 }
67 return true;
68 }
69
71 bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
72 {
73 TileIndex start = tile;
74 TileIndexDiff diff = TileOffsByDiagDir(dir);
75
76 do {
77 if (HasStationReservation(tile)) return false;
78 SetRailStationReservation(tile, true);
79 MarkTileDirtyByTile(tile);
80 tile = TileAdd(tile, diff);
81 } while (IsCompatibleTrainStationTile(tile, start) && tile != this->origin_tile);
82
83 TriggerStationRandomisation(nullptr, start, SRT_PATH_RESERVATION);
84
85 return true;
86 }
87
89 bool ReserveSingleTrack(TileIndex tile, Trackdir td)
90 {
91 Trackdir rev_td = ReverseTrackdir(td);
92 if (IsRailStationTile(tile)) {
93 if (!ReserveRailStationPlatform(tile, TrackdirToExitdir(rev_td))) {
94 /* Platform could not be reserved, undo. */
95 this->res_fail_tile = tile;
96 this->res_fail_td = td;
97 }
98 } else {
99 if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) {
100 /* Tile couldn't be reserved, undo. */
101 this->res_fail_tile = tile;
102 this->res_fail_td = td;
103 return false;
104 }
105
106 /* Green path signal opposing the path? Turn to red. */
107 if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
108 this->signals_set_to_red.emplace_back(tile, rev_td);
109 SetSignalStateByTrackdir(tile, rev_td, SIGNAL_STATE_RED);
110 MarkTileDirtyByTile(tile);
111 }
112 }
113
114 return tile != this->res_dest_tile || td != this->res_dest_td;
115 }
116
118 bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
119 {
120 if (IsRailStationTile(tile)) {
121 TileIndex start = tile;
122 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(td)));
123 while ((tile != this->res_fail_tile || td != this->res_fail_td) && IsCompatibleTrainStationTile(tile, start)) {
124 SetRailStationReservation(tile, false);
125 tile = TileAdd(tile, diff);
126 }
127 } else if (tile != this->res_fail_tile || td != this->res_fail_td) {
128 UnreserveRailTrack(tile, TrackdirToTrack(td));
129 }
130 return (tile != this->res_dest_tile || td != this->res_dest_td) && (tile != this->res_fail_tile || td != this->res_fail_td);
131 }
132
133public:
135 inline void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
136 {
137 this->res_dest_node = node;
138 this->res_dest_tile = tile;
139 this->res_dest_td = td;
140 }
141
143 inline void FindSafePositionOnNode(Node *node)
144 {
145 assert(node->parent != nullptr);
146
147 /* We will never pass more than two signals, no need to check for a safe tile. */
148 if (node->parent->num_signals_passed >= 2) return;
149
150 if (!node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::FindSafePositionProc)) {
151 this->res_dest_node = node;
152 }
153 }
154
156 bool TryReservePath(PBSTileInfo *target, TileIndex origin)
157 {
158 this->res_fail_tile = INVALID_TILE;
159 this->origin_tile = origin;
160
161 if (target != nullptr) {
162 target->tile = this->res_dest_tile;
163 target->trackdir = this->res_dest_td;
164 target->okay = false;
165 }
166
167 /* Don't bother if the target is reserved. */
168 if (!IsWaitingPositionFree(Yapf().GetVehicle(), this->res_dest_tile, this->res_dest_td)) return false;
169
170 this->signals_set_to_red.clear();
171 for (Node *node = this->res_dest_node; node->parent != nullptr; node = node->parent) {
172 node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
173 if (this->res_fail_tile != INVALID_TILE) {
174 /* Reservation failed, undo. */
175 Node *fail_node = this->res_dest_node;
176 TileIndex stop_tile = this->res_fail_tile;
177 do {
178 /* If this is the node that failed, stop at the failed tile. */
179 this->res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE;
180 fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
181 } while (fail_node != node && (fail_node = fail_node->parent) != nullptr);
182
183 /* Re-instate green path signals we turned to red. */
184 for (auto [sig_tile, td] : this->signals_set_to_red) {
185 SetSignalStateByTrackdir(sig_tile, td, SIGNAL_STATE_GREEN);
186 }
187
188 return false;
189 }
190 }
191
192 if (target != nullptr) target->okay = true;
193
194 if (Yapf().CanUseGlobalCache(*this->res_dest_node)) {
195 YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
196 }
197
198 return true;
199 }
200};
201
202template <class Types>
203 class CYapfFollowAnyDepotRailT
204{
205public:
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;
210
211protected:
213 inline Tpf &Yapf()
214 {
215 return *static_cast<Tpf *>(this);
216 }
217
218public:
224 inline void PfFollowNode(Node &old_node)
225 {
226 TrackFollower F(Yapf().GetVehicle());
227 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
228 Yapf().AddMultipleNodes(&old_node, F);
229 }
230 }
231
233 inline char TransportTypeChar() const
234 {
235 return 't';
236 }
237
238 static FindDepotData stFindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
239 {
240 Tpf pf1;
241 /*
242 * With caching enabled it simply cannot get a reliable result when you
243 * have limited the distance a train may travel. This means that the
244 * cached result does not match uncached result in all cases and that
245 * causes desyncs. So disable caching when finding for a depot that is
246 * nearby. This only happens with automatic servicing of vehicles,
247 * so it will only impact performance when you do not manually set
248 * depot orders and you do not disable automatic servicing.
249 */
250 if (max_penalty != 0) pf1.DisableCache(true);
251 FindDepotData result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
252
253 if (_debug_desync_level >= 2) {
254 Tpf pf2;
255 pf2.DisableCache(true);
256 FindDepotData result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
257 if (result1.tile != result2.tile || (result1.reverse != result2.reverse)) {
258 Debug(desync, 2, "warning: FindNearestDepotTwoWay cache mismatch: {} vs {}",
259 result1.tile != INVALID_TILE ? "T" : "F",
260 result2.tile != INVALID_TILE ? "T" : "F");
261 DumpState(pf1, pf2);
262 }
263 }
264
265 return result1;
266 }
267
268 inline FindDepotData FindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
269 {
270 /* set origin and destination nodes */
271 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
272 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
273 Yapf().SetDestination(v);
274 Yapf().SetMaxCost(max_penalty);
275
276 /* find the best path */
277 if (!Yapf().FindPath(v)) return FindDepotData();
278
279 /* Some path found. */
280 Node *n = Yapf().GetBestNode();
281
282 /* walk through the path back to the origin */
283 Node *pNode = n;
284 while (pNode->parent != nullptr) {
285 pNode = pNode->parent;
286 }
287
288 /* if the origin node is our front vehicle tile/Trackdir then we didn't reverse
289 * but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed) */
290 return FindDepotData(n->GetLastTile(), n->cost, pNode->cost != 0);
291 }
292};
293
294template <class Types>
295 class CYapfFollowAnySafeTileRailT : public CYapfReserveTrack<Types>
296{
297public:
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;
302
303protected:
305 inline Tpf &Yapf()
306 {
307 return *static_cast<Tpf *>(this);
308 }
309
310public:
316 inline void PfFollowNode(Node &old_node)
317 {
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);
321 }
322 }
323
325 inline char TransportTypeChar() const
326 {
327 return 't';
328 }
329
330 static bool stFindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype)
331 {
332 /* Create pathfinder instance */
333 Tpf pf1;
334 bool result1;
335 if (_debug_desync_level < 2) {
336 result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false);
337 } else {
338 bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true);
339 Tpf pf2;
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");
344 DumpState(pf1, pf2);
345 }
346 }
347
348 return result1;
349 }
350
351 bool FindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype, bool dont_reserve)
352 {
353 /* Set origin and destination. */
354 Yapf().SetOrigin(t1, td);
355 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(false);
356 Yapf().SetDestination(v, override_railtype);
357
358 if (!Yapf().FindPath(v)) return false;
359
360 /* Found a destination, set as reservation target. */
361 Node *pNode = Yapf().GetBestNode();
362 this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir());
363
364 /* Walk through the path back to the origin. */
365 Node *pPrev = nullptr;
366 while (pNode->parent != nullptr) {
367 pPrev = pNode;
368 pNode = pNode->parent;
369
370 this->FindSafePositionOnNode(pPrev);
371 }
372
373 return dont_reserve || this->TryReservePath(nullptr, pNode->GetLastTile());
374 }
375};
376
377template <class Types>
378 class CYapfFollowRailT : public CYapfReserveTrack<Types>
379{
380public:
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;
385
386protected:
388 inline Tpf &Yapf()
389 {
390 return *static_cast<Tpf *>(this);
391 }
392
393public:
399 inline void PfFollowNode(Node &old_node)
400 {
401 TrackFollower F(Yapf().GetVehicle());
402 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
403 Yapf().AddMultipleNodes(&old_node, F);
404 }
405 }
406
408 inline char TransportTypeChar() const
409 {
410 return 't';
411 }
412
413 static Trackdir stChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
414 {
415 /* create pathfinder instance */
416 Tpf pf1;
417 Trackdir result1;
418
419 if (_debug_desync_level < 2) {
420 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
421 } else {
422 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, nullptr, nullptr);
423 Tpf pf2;
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);
428 DumpState(pf1, pf2);
429 }
430 }
431
432 return result1;
433 }
434
435 inline Trackdir ChooseRailTrack(const Train *v, TileIndex, DiagDirection, TrackBits, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
436 {
437 if (target != nullptr) target->tile = INVALID_TILE;
438 if (dest != nullptr) *dest = INVALID_TILE;
439
440 /* set origin and destination nodes */
441 PBSTileInfo origin = FollowTrainReservation(v);
442 Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1);
443 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
444 Yapf().SetDestination(v);
445
446 /* find the best path */
447 path_found = Yapf().FindPath(v);
448
449 /* if path not found - return INVALID_TRACKDIR */
450 Trackdir next_trackdir = INVALID_TRACKDIR;
451 Node *pNode = Yapf().GetBestNode();
452 if (pNode != nullptr) {
453 /* reserve till end of path */
454 this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir());
455
456 /* path was found or at least suggested
457 * walk through the path back to the origin */
458 Node *pPrev = nullptr;
459 while (pNode->parent != nullptr) {
460 pPrev = pNode;
461 pNode = pNode->parent;
462
463 this->FindSafePositionOnNode(pPrev);
464 }
465
466 /* If the best PF node has no parent, then there is no (valid) best next trackdir to return.
467 * This occurs when the PF is called while the train is already at its destination. */
468 if (pPrev == nullptr) return INVALID_TRACKDIR;
469
470 /* return trackdir from the best origin node (one of start nodes) */
471 Node &best_next_node = *pPrev;
472 next_trackdir = best_next_node.GetTrackdir();
473
474 if (reserve_track && path_found) {
475 if (dest != nullptr) *dest = Yapf().GetBestNode()->GetLastTile();
476 this->TryReservePath(target, pNode->GetLastTile());
477 }
478 }
479
480 /* Treat the path as found if stopped on the first two way signal(s). */
481 path_found |= Yapf().stopped_on_first_two_way_signal;
482 return next_trackdir;
483 }
484
485 static bool stCheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
486 {
487 Tpf pf1;
488 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
489
490 if (_debug_desync_level >= 2) {
491 Tpf pf2;
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");
496 DumpState(pf1, pf2);
497 }
498 }
499
500 return result1;
501 }
502
503 inline bool CheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
504 {
505 /* create pathfinder instance
506 * set origin and destination nodes */
507 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
508 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(false);
509 Yapf().SetDestination(v);
510
511 /* find the best path */
512 if (!Yapf().FindPath(v)) return false;
513
514 /* path was found
515 * walk through the path back to the origin */
516 Node *pNode = Yapf().GetBestNode();
517 while (pNode->parent != nullptr) {
518 pNode = pNode->parent;
519 }
520
521 /* check if it was reversed origin */
522 bool reversed = (pNode->cost != 0);
523 return reversed;
524 }
525};
526
527template <class Tpf_, class Ttrack_follower, class Tnode_list, template <class Types> class TdestinationT, template <class Types> class TfollowT>
528 struct CYapfRail_TypesT
529{
530 typedef CYapfRail_TypesT<Tpf_, Ttrack_follower, Tnode_list, TdestinationT, TfollowT> Types;
531
532 typedef Tpf_ Tpf;
533 typedef Ttrack_follower TrackFollower;
534 typedef Tnode_list NodeList;
535 typedef Train VehicleType;
536 typedef CYapfBaseT<Types> PfBase;
537 typedef TfollowT<Types> PfFollow;
538 typedef CYapfOriginTileTwoWayT<Types> PfOrigin;
539 typedef TdestinationT<Types> PfDestination;
540 typedef CYapfSegmentCostCacheGlobalT<Types> PfCache;
541 typedef CYapfCostRailT<Types> PfCost;
542};
543
544 struct CYapfRail1 : CYapfT<CYapfRail_TypesT<CYapfRail1 , CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
545 struct CYapfRail2 : CYapfT<CYapfRail_TypesT<CYapfRail2 , CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
546
547 struct CYapfAnyDepotRail1 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail1, CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
548 struct CYapfAnyDepotRail2 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail2, CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT> > {};
549
550 struct CYapfAnySafeTileRail1 : CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail1, CFollowTrackFreeRail , CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT> > {};
551 struct CYapfAnySafeTileRail2 : CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail2, CFollowTrackFreeRailNo90, CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT> > {};
552
553
554 Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
555{
556 Trackdir td_ret = _settings_game.pf.forbid_90_deg
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);
559
560 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks);
561}
562
563 bool YapfTrainCheckReverse(const Train *v)
564{
565 const Train *last_veh = v->Last();
566
567 /* get trackdirs of both ends */
568 Trackdir td = v->GetVehicleTrackdir();
569 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
570
571 /* tiles where front and back are */
572 TileIndex tile = v->tile;
573 TileIndex tile_rev = last_veh->tile;
574
575 int reverse_penalty = 0;
576
577 if (v->track == TRACK_BIT_WORMHOLE) {
578 /* front in tunnel / on bridge */
579 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
580
581 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
582 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
583
584 /* Current position of the train in the wormhole */
585 TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos);
586
587 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
588 * Note: Negative penalties are ok for the start tile. */
589 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
590 }
591
592 if (last_veh->track == TRACK_BIT_WORMHOLE) {
593 /* back in tunnel / on bridge */
594 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
595
596 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
597 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
598
599 /* Current position of the last wagon in the wormhole */
600 TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos);
601
602 /* Add distance to drive in the wormhole as penalty for the revere path. */
603 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
604 }
605
606 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
607 if (reverse_penalty == 0) reverse_penalty = 1;
608
609 bool reverse = _settings_game.pf.forbid_90_deg
610 ? CYapfRail2::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty)
611 : CYapfRail1::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
612
613 return reverse;
614}
615
616 FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_penalty)
617{
618 const Train *last_veh = v->Last();
619
620 PBSTileInfo origin = FollowTrainReservation(v);
621 TileIndex last_tile = last_veh->tile;
622 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
623
624 return _settings_game.pf.forbid_90_deg
625 ? CYapfAnyDepotRail2::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY)
626 : CYapfAnyDepotRail1::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY);
627}
628
629 bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
630{
631 return _settings_game.pf.forbid_90_deg
632 ? CYapfAnySafeTileRail2::stFindNearestSafeTile(v, tile, td, override_railtype)
633 : CYapfAnySafeTileRail1::stFindNearestSafeTile(v, tile, td, override_railtype);
634}
635
637int CSegmentCostCacheBase::s_rail_change_counter = 0;
638
639 void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
640{
641 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);
642}
CYapfBaseT
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:49
CYapfCostRailT
Definition yapf_costrail.hpp:21
CYapfFollowAnyDepotRailT
Definition yapf_rail.cpp:204
CYapfFollowAnyDepotRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:206
CYapfFollowAnyDepotRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:213
CYapfFollowAnyDepotRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:224
CYapfFollowAnyDepotRailT::TransportTypeChar
char TransportTypeChar() const
return debug report character to identify the transportation type
Definition yapf_rail.cpp:233
CYapfFollowAnyDepotRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:208
CYapfFollowAnyDepotRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:209
CYapfFollowAnySafeTileRailT
Definition yapf_rail.cpp:296
CYapfFollowAnySafeTileRailT::TransportTypeChar
char TransportTypeChar() const
Return debug report character to identify the transportation type.
Definition yapf_rail.cpp:325
CYapfFollowAnySafeTileRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:301
CYapfFollowAnySafeTileRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:298
CYapfFollowAnySafeTileRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:316
CYapfFollowAnySafeTileRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:300
CYapfFollowAnySafeTileRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:305
CYapfFollowRailT
Definition yapf_rail.cpp:379
CYapfFollowRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:384
CYapfFollowRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:388
CYapfFollowRailT::TransportTypeChar
char TransportTypeChar() const
return debug report character to identify the transportation type
Definition yapf_rail.cpp:408
CYapfFollowRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:381
CYapfFollowRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:383
CYapfFollowRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:399
CYapfOriginTileTwoWayT
YAPF origin provider base class - used when there are two tile/trackdir origins.
Definition yapf_common.hpp:60
CYapfReserveTrack
Definition yapf_rail.cpp:37
CYapfReserveTrack::SetReservationTarget
void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
Set the target to where the reservation should be extended.
Definition yapf_rail.cpp:135
CYapfReserveTrack::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:41
CYapfReserveTrack::res_fail_tile
TileIndex res_fail_tile
The tile where the reservation failed.
Definition yapf_rail.cpp:54
CYapfReserveTrack::UnreserveSingleTrack
bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
Unreserve a single track/platform.
Definition yapf_rail.cpp:118
CYapfReserveTrack::ReserveRailStationPlatform
bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
Reserve a railway platform.
Definition yapf_rail.cpp:71
CYapfReserveTrack::ReserveSingleTrack
bool ReserveSingleTrack(TileIndex tile, Trackdir td)
Try to reserve a single track/platform.
Definition yapf_rail.cpp:89
CYapfReserveTrack::signals_set_to_red
std::vector< std::pair< TileIndex, Trackdir > > signals_set_to_red
List of signals turned red during a path reservation.
Definition yapf_rail.cpp:58
CYapfReserveTrack::res_fail_td
Trackdir res_fail_td
The trackdir where the reservation failed.
Definition yapf_rail.cpp:55
CYapfReserveTrack::res_dest_node
Node * res_dest_node
The reservation target node.
Definition yapf_rail.cpp:53
CYapfReserveTrack::origin_tile
TileIndex origin_tile
Tile our reservation will originate from.
Definition yapf_rail.cpp:56
CYapfReserveTrack::res_dest_tile
TileIndex res_dest_tile
The reservation target tile.
Definition yapf_rail.cpp:51
CYapfReserveTrack::TryReservePath
bool TryReservePath(PBSTileInfo *target, TileIndex origin)
Try to reserve the path till the reservation target.
Definition yapf_rail.cpp:156
CYapfReserveTrack::Yapf
Tpf & Yapf()
to access inherited pathfinder
Definition yapf_rail.cpp:45
CYapfReserveTrack::FindSafePositionOnNode
void FindSafePositionOnNode(Node *node)
Check the node for a possible reservation target.
Definition yapf_rail.cpp:143
CYapfReserveTrack::res_dest_td
Trackdir res_dest_td
The reservation target trackdir.
Definition yapf_rail.cpp:52
CYapfReserveTrack::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:39
CYapfSegmentCostCacheGlobalT
CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost caching functi...
Definition yapf_costcache.hpp:105
CYapfT
YAPF template that uses Ttypes template argument to determine all YAPF components (base classes) from...
Definition yapf_common.hpp:121
FileHandle::Open
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1170
NodeList
Hash table based node list multi-container class.
Definition nodelist.hpp:21
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
DiagDirection
DiagDirection
Enumeration for diagonal directions.
Definition direction_type.h:73
MarkTileDirtyByTile
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition viewport.cpp:2057
DistanceManhattan
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:146
TileAdd
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:454
TileOffsByDiagDir
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:567
TileVirtXY
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:404
TileIndexDiff
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
TriggerStationRandomisation
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
Definition newgrf_station.cpp:919
SRT_PATH_RESERVATION
@ SRT_PATH_RESERVATION
Trigger platform when train reserves path.
Definition newgrf_station.h:111
YAPF_INFINITE_PENALTY
static const int YAPF_INFINITE_PENALTY
This penalty is the equivalent of "infinite", which means that paths that get this penalty will be ch...
Definition pathfinder_type.h:27
YAPF_TILE_LENGTH
static const int YAPF_TILE_LENGTH
Length (penalty) of one tile with YAPF.
Definition pathfinder_type.h:16
FollowTrainReservation
PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
Follow a train reservation to the last tile.
Definition pbs.cpp:288
TryReserveRailTrack
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
Definition pbs.cpp:80
IsWaitingPositionFree
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
Definition pbs.cpp:426
UnreserveRailTrack
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition pbs.cpp:140
IsSafeWaitingPosition
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.
Definition pbs.cpp:380
SetSignalStateByTrackdir
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition rail_map.h:449
HasPbsSignalOnTrackdir
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition rail_map.h:463
GetSignalStateByTrackdir
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition rail_map.h:438
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
SIGNAL_STATE_RED
@ SIGNAL_STATE_RED
The signal is red.
Definition signal_type.h:43
SIGNAL_STATE_GREEN
@ SIGNAL_STATE_GREEN
The signal is green.
Definition signal_type.h:44
IsCompatibleTrainStationTile
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition station_map.h:544
IsRailStationTile
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
Definition station_map.h:102
SetRailStationReservation
void SetRailStationReservation(Tile t, bool b)
Set the reservation state of the rail station.
Definition station_map.h:571
HasStationReservation
bool HasStationReservation(Tile t)
Get the reservation state of the rail station.
Definition station_map.h:559
CSegmentCostCacheBase::s_rail_change_counter
static int s_rail_change_counter
if any track changes, this counter is incremented - that will invalidate segment cost cache
Definition yapf_costcache.hpp:48
CYapfAnyDepotRail1
Definition yapf_rail.cpp:547
CYapfAnyDepotRail2
Definition yapf_rail.cpp:548
CYapfAnySafeTileRail1
Definition yapf_rail.cpp:550
CYapfAnySafeTileRail2
Definition yapf_rail.cpp:551
CYapfRail1
Definition yapf_rail.cpp:544
CYapfRail2
Definition yapf_rail.cpp:545
CYapfRail_TypesT
Definition yapf_rail.cpp:529
DumpTarget
Class that represents the dump-into-string target.
Definition dbg_helpers.h:95
DumpTarget::m_out
std::string m_out
the output string
Definition dbg_helpers.h:118
FindDepotData
Helper container to find a depot.
Definition pathfinder_type.h:38
FindDepotData::reverse
bool reverse
True if reversing is necessary for the train to get to this depot.
Definition pathfinder_type.h:41
FindDepotData::tile
TileIndex tile
The tile of the depot.
Definition pathfinder_type.h:39
GameSettings::pf
PathfinderSettings pf
settings for all pathfinders
Definition settings_type.h:599
LinkGraph::BaseNode
Node of the link graph.
Definition linkgraph.h:90
PBSTileInfo
This struct contains information about the end of a reserved path.
Definition pbs.h:26
PBSTileInfo::trackdir
Trackdir trackdir
The reserved trackdir on the tile.
Definition pbs.h:28
PBSTileInfo::tile
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
Definition pbs.h:27
PBSTileInfo::okay
bool okay
True if tile is a safe waiting position, false otherwise.
Definition pbs.h:29
PathfinderSettings::forbid_90_deg
bool forbid_90_deg
forbid trains to make 90 deg turns
Definition settings_type.h:466
SpecializedVehicle::Last
T * Last()
Get the last vehicle in the chain.
Definition vehicle_base.h:1118
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
Train
'Train' is either a loco or a wagon.
Definition train.h:89
Train::GetVehicleTrackdir
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition train_cmd.cpp:4220
Vehicle::y_pos
int32_t y_pos
y coordinate.
Definition vehicle_base.h:305
Vehicle::x_pos
int32_t x_pos
x coordinate.
Definition vehicle_base.h:304
Vehicle::tile
TileIndex tile
Current tile index.
Definition vehicle_base.h:264
INVALID_TILE
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
TrackdirToTrack
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition track_func.h:262
ReverseTrackdir
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition track_func.h:247
FindFirstTrack
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition track_func.h:177
TrackdirToExitdir
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition track_func.h:439
TrackBits
TrackBits
Allow incrementing of Track variables.
Definition track_type.h:35
TRACK_BIT_WORMHOLE
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels)
Definition track_type.h:52
Trackdir
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:67
INVALID_TRACKDIR
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:86
Track
Track
These are used to specify a single track.
Definition track_type.h:19
INVALID_TRACK
@ INVALID_TRACK
Flag for an invalid track.
Definition track_type.h:28
GetTunnelBridgeDirection
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
Definition tunnelbridge_map.h:26
GetOtherTunnelBridgeEnd
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
Definition tunnelbridge_map.h:78
yapf.hpp
Base includes/functions for YAPF.
yapf_cache.h
Entry point for OpenTTD to YAPF's cache.
yapf_costrail.hpp
Cost determination for rails.
yapf_destrail.hpp
Determining the destination for rail vehicles.
yapf_node_rail.hpp
Node tailored for rail pathfinding.
YapfNotifyTrackLayoutChange
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.
Definition yapf_rail.cpp:639
YapfTrainFindNearestSafeTile
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.
Definition yapf_rail.cpp:629
YapfTrainChooseTrack
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.
Definition yapf_rail.cpp:554
YapfTrainFindNearestDepot
FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_penalty)
Used when user sends train to the nearest depot or if train needs servicing using YAPF.
Definition yapf_rail.cpp:616
YapfTrainCheckReverse
bool YapfTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using YAPF.
Definition yapf_rail.cpp:563