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

OpenTTD Source 15.3

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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
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"sv, "wt");
28 auto f2 = FileHandle::Open("yapf2.txt"sv, "wt");
29 assert(f1.has_value());
30 assert(f2.has_value());
31 fwrite(dmp1.m_out.data(), 1, dmp1.m_out.size(), *f1);
32 fwrite(dmp2.m_out.data(), 1, dmp2.m_out.size(), *f2);
33}
34
35template <class Types>
36 class CYapfReserveTrack {
37public:
38 typedef typename Types::Tpf Tpf;
39 typedef typename Types::TrackFollower TrackFollower;
40 typedef typename Types::NodeList::Item Node;
41
42protected:
44 inline Tpf &Yapf()
45 {
46 return *static_cast<Tpf *>(this);
47 }
48
49private:
50 TileIndex res_dest_tile;
51 Trackdir res_dest_td;
52 Node *res_dest_node;
53 TileIndex res_fail_tile;
54 Trackdir res_fail_td;
55 TileIndex origin_tile;
56
57 std::vector<std::pair<TileIndex, Trackdir>> signals_set_to_red;
58
59 bool FindSafePositionProc(TileIndex tile, Trackdir td)
60 {
61 if (IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns())) {
62 this->res_dest_tile = tile;
63 this->res_dest_td = td;
64 return false; // Stop iterating segment
65 }
66 return true;
67 }
68
70 bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
71 {
72 TileIndex start = tile;
73 TileIndexDiff diff = TileOffsByDiagDir(dir);
74
75 do {
76 if (HasStationReservation(tile)) return false;
77 SetRailStationReservation(tile, true);
78 MarkTileDirtyByTile(tile);
79 tile = TileAdd(tile, diff);
80 } while (IsCompatibleTrainStationTile(tile, start) && tile != this->origin_tile);
81
82 auto *st = Station::GetByTile(start);
83 TriggerStationRandomisation(st, start, StationRandomTrigger::PathReservation);
84 TriggerStationAnimation(st, start, StationAnimationTrigger::PathReservation);
85
86 return true;
87 }
88
90 bool ReserveSingleTrack(TileIndex tile, Trackdir td)
91 {
92 Trackdir rev_td = ReverseTrackdir(td);
93 if (IsRailStationTile(tile)) {
94 if (!ReserveRailStationPlatform(tile, TrackdirToExitdir(rev_td))) {
95 /* Platform could not be reserved, undo. */
96 this->res_fail_tile = tile;
97 this->res_fail_td = td;
98 }
99 } else {
100 if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) {
101 /* Tile couldn't be reserved, undo. */
102 this->res_fail_tile = tile;
103 this->res_fail_td = td;
104 return false;
105 }
106
107 /* Green path signal opposing the path? Turn to red. */
108 if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
109 this->signals_set_to_red.emplace_back(tile, rev_td);
110 SetSignalStateByTrackdir(tile, rev_td, SIGNAL_STATE_RED);
111 MarkTileDirtyByTile(tile);
112 }
113
114 if (IsRailWaypointTile(tile)) {
115 auto *st = BaseStation::GetByTile(tile);
116 TriggerStationRandomisation(st, tile, StationRandomTrigger::PathReservation);
117 TriggerStationAnimation(st, tile, StationAnimationTrigger::PathReservation);
118 }
119 }
120
121 return tile != this->res_dest_tile || td != this->res_dest_td;
122 }
123
125 bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
126 {
127 if (IsRailStationTile(tile)) {
128 TileIndex start = tile;
129 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(td)));
130 while ((tile != this->res_fail_tile || td != this->res_fail_td) && IsCompatibleTrainStationTile(tile, start)) {
131 SetRailStationReservation(tile, false);
132 tile = TileAdd(tile, diff);
133 }
134 } else if (tile != this->res_fail_tile || td != this->res_fail_td) {
135 UnreserveRailTrack(tile, TrackdirToTrack(td));
136 }
137 return (tile != this->res_dest_tile || td != this->res_dest_td) && (tile != this->res_fail_tile || td != this->res_fail_td);
138 }
139
140public:
142 inline void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
143 {
144 this->res_dest_node = node;
145 this->res_dest_tile = tile;
146 this->res_dest_td = td;
147 }
148
150 inline void FindSafePositionOnNode(Node *node)
151 {
152 assert(node->parent != nullptr);
153
154 /* We will never pass more than two signals, no need to check for a safe tile. */
155 if (node->parent->num_signals_passed >= 2) return;
156
157 if (!node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::FindSafePositionProc)) {
158 this->res_dest_node = node;
159 }
160 }
161
163 bool TryReservePath(PBSTileInfo *target, TileIndex origin)
164 {
165 this->res_fail_tile = INVALID_TILE;
166 this->origin_tile = origin;
167
168 if (target != nullptr) {
169 target->tile = this->res_dest_tile;
170 target->trackdir = this->res_dest_td;
171 target->okay = false;
172 }
173
174 /* Don't bother if the target is reserved. */
175 if (!IsWaitingPositionFree(Yapf().GetVehicle(), this->res_dest_tile, this->res_dest_td)) return false;
176
177 this->signals_set_to_red.clear();
178 for (Node *node = this->res_dest_node; node->parent != nullptr; node = node->parent) {
179 node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
180 if (this->res_fail_tile != INVALID_TILE) {
181 /* Reservation failed, undo. */
182 Node *fail_node = this->res_dest_node;
183 TileIndex stop_tile = this->res_fail_tile;
184 do {
185 /* If this is the node that failed, stop at the failed tile. */
186 this->res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE;
187 fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
188 } while (fail_node != node && (fail_node = fail_node->parent) != nullptr);
189
190 /* Re-instate green path signals we turned to red. */
191 for (auto [sig_tile, td] : this->signals_set_to_red) {
192 SetSignalStateByTrackdir(sig_tile, td, SIGNAL_STATE_GREEN);
193 }
194
195 return false;
196 }
197 }
198
199 if (target != nullptr) target->okay = true;
200
201 if (Yapf().CanUseGlobalCache(*this->res_dest_node)) {
202 YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
203 }
204
205 return true;
206 }
207};
208
209template <class Types>
210 class CYapfFollowAnyDepotRailT {
211public:
212 typedef typename Types::Tpf Tpf;
213 typedef typename Types::TrackFollower TrackFollower;
214 typedef typename Types::NodeList::Item Node;
215 typedef typename Node::Key Key;
216
217protected:
219 inline Tpf &Yapf()
220 {
221 return *static_cast<Tpf *>(this);
222 }
223
224public:
230 inline void PfFollowNode(Node &old_node)
231 {
232 TrackFollower follower{Yapf().GetVehicle()};
233 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
234 Yapf().AddMultipleNodes(&old_node, follower);
235 }
236 }
237
239 inline char TransportTypeChar() const
240 {
241 return 't';
242 }
243
244 static FindDepotData stFindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
245 {
246 Tpf pf1;
247 /*
248 * With caching enabled it simply cannot get a reliable result when you
249 * have limited the distance a train may travel. This means that the
250 * cached result does not match uncached result in all cases and that
251 * causes desyncs. So disable caching when finding for a depot that is
252 * nearby. This only happens with automatic servicing of vehicles,
253 * so it will only impact performance when you do not manually set
254 * depot orders and you do not disable automatic servicing.
255 */
256 if (max_penalty != 0) pf1.DisableCache(true);
257 FindDepotData result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
258
259 if (_debug_desync_level >= 2) {
260 Tpf pf2;
261 pf2.DisableCache(true);
262 FindDepotData result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
263 if (result1.tile != result2.tile || (result1.reverse != result2.reverse)) {
264 Debug(desync, 2, "warning: FindNearestDepotTwoWay cache mismatch: {} vs {}",
265 result1.tile != INVALID_TILE ? "T" : "F",
266 result2.tile != INVALID_TILE ? "T" : "F");
267 DumpState(pf1, pf2);
268 }
269 }
270
271 return result1;
272 }
273
274 inline FindDepotData FindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
275 {
276 /* set origin and destination nodes */
277 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
278 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
279 Yapf().SetDestination(v);
280 Yapf().SetMaxCost(max_penalty);
281
282 /* find the best path */
283 if (!Yapf().FindPath(v)) return FindDepotData();
284
285 /* Some path found. */
286 Node *n = Yapf().GetBestNode();
287
288 /* walk through the path back to the origin */
289 Node *node = n;
290 while (node->parent != nullptr) {
291 node = node->parent;
292 }
293
294 /* if the origin node is our front vehicle tile/Trackdir then we didn't reverse
295 * but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed) */
296 return FindDepotData(n->GetLastTile(), n->cost, node->cost != 0);
297 }
298};
299
300template <class Types>
301 class CYapfFollowAnySafeTileRailT : public CYapfReserveTrack<Types> {
302public:
303 typedef typename Types::Tpf Tpf;
304 typedef typename Types::TrackFollower TrackFollower;
305 typedef typename Types::NodeList::Item Node;
306 typedef typename Node::Key Key;
307
308protected:
310 inline Tpf &Yapf()
311 {
312 return *static_cast<Tpf *>(this);
313 }
314
315public:
321 inline void PfFollowNode(Node &old_node)
322 {
323 TrackFollower follower{Yapf().GetVehicle(), Yapf().GetCompatibleRailTypes()};
324 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()) && follower.MaskReservedTracks()) {
325 Yapf().AddMultipleNodes(&old_node, follower);
326 }
327 }
328
330 inline char TransportTypeChar() const
331 {
332 return 't';
333 }
334
335 static bool stFindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype)
336 {
337 /* Create pathfinder instance */
338 Tpf pf1;
339 bool result1;
340 if (_debug_desync_level < 2) {
341 result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false);
342 } else {
343 bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true);
344 Tpf pf2;
345 pf2.DisableCache(true);
346 result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false);
347 if (result1 != result2) {
348 Debug(desync, 2, "warning: FindSafeTile cache mismatch: {} vs {}", result2 ? "T" : "F", result1 ? "T" : "F");
349 DumpState(pf1, pf2);
350 }
351 }
352
353 return result1;
354 }
355
356 bool FindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype, bool dont_reserve)
357 {
358 /* Set origin and destination. */
359 Yapf().SetOrigin(t1, td);
360 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
361 Yapf().SetDestination(v, override_railtype);
362
363 if (!Yapf().FindPath(v)) return false;
364
365 /* Found a destination, set as reservation target. */
366 Node *node = Yapf().GetBestNode();
367 this->SetReservationTarget(node, node->GetLastTile(), node->GetLastTrackdir());
368
369 /* Walk through the path back to the origin. */
370 Node *prev = nullptr;
371 while (node->parent != nullptr) {
372 prev = node;
373 node = node->parent;
374
375 this->FindSafePositionOnNode(prev);
376 }
377
378 return dont_reserve || this->TryReservePath(nullptr, node->GetLastTile());
379 }
380};
381
382template <class Types>
383 class CYapfFollowRailT : public CYapfReserveTrack<Types> {
384public:
385 typedef typename Types::Tpf Tpf;
386 typedef typename Types::TrackFollower TrackFollower;
387 typedef typename Types::NodeList::Item Node;
388 typedef typename Node::Key Key;
389
390protected:
392 inline Tpf &Yapf()
393 {
394 return *static_cast<Tpf *>(this);
395 }
396
397public:
403 inline void PfFollowNode(Node &old_node)
404 {
405 TrackFollower follower{Yapf().GetVehicle()};
406 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
407 Yapf().AddMultipleNodes(&old_node, follower);
408 }
409 }
410
412 inline char TransportTypeChar() const
413 {
414 return 't';
415 }
416
417 static Trackdir stChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
418 {
419 /* create pathfinder instance */
420 Tpf pf1;
421 Trackdir result1;
422
423 if (_debug_desync_level < 2) {
424 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
425 } else {
426 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, nullptr, nullptr);
427 Tpf pf2;
428 pf2.DisableCache(true);
429 Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
430 if (result1 != result2) {
431 Debug(desync, 2, "warning: ChooseRailTrack cache mismatch: {} vs {}", result1, result2);
432 DumpState(pf1, pf2);
433 }
434 }
435
436 return result1;
437 }
438
439 inline Trackdir ChooseRailTrack(const Train *v, TileIndex, DiagDirection, TrackBits, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
440 {
441 if (target != nullptr) target->tile = INVALID_TILE;
442 if (dest != nullptr) *dest = INVALID_TILE;
443
444 /* set origin and destination nodes */
445 PBSTileInfo origin = FollowTrainReservation(v);
446 Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1);
447 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
448 Yapf().SetDestination(v);
449
450 /* find the best path */
451 path_found = Yapf().FindPath(v);
452
453 /* if path not found - return INVALID_TRACKDIR */
454 Trackdir next_trackdir = INVALID_TRACKDIR;
455 Node *node = Yapf().GetBestNode();
456 if (node != nullptr) {
457 /* reserve till end of path */
458 this->SetReservationTarget(node, node->GetLastTile(), node->GetLastTrackdir());
459
460 /* path was found or at least suggested
461 * walk through the path back to the origin */
462 Node *prev = nullptr;
463 while (node->parent != nullptr) {
464 prev = node;
465 node = node->parent;
466
467 this->FindSafePositionOnNode(prev);
468 }
469
470 /* If the best PF node has no parent, then there is no (valid) best next trackdir to return.
471 * This occurs when the PF is called while the train is already at its destination. */
472 if (prev == nullptr) return INVALID_TRACKDIR;
473
474 /* return trackdir from the best origin node (one of start nodes) */
475 Node &best_next_node = *prev;
476 next_trackdir = best_next_node.GetTrackdir();
477
478 if (reserve_track && path_found) {
479 if (dest != nullptr) *dest = Yapf().GetBestNode()->GetLastTile();
480 this->TryReservePath(target, node->GetLastTile());
481 }
482 }
483
484 /* Treat the path as found if stopped on the first two way signal(s). */
485 path_found |= Yapf().stopped_on_first_two_way_signal;
486 return next_trackdir;
487 }
488
489 static bool stCheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
490 {
491 Tpf pf1;
492 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
493
494 if (_debug_desync_level >= 2) {
495 Tpf pf2;
496 pf2.DisableCache(true);
497 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
498 if (result1 != result2) {
499 Debug(desync, 2, "warning: CheckReverseTrain cache mismatch: {} vs {}", result1 ? "T" : "F", result2 ? "T" : "F");
500 DumpState(pf1, pf2);
501 }
502 }
503
504 return result1;
505 }
506
507 inline bool CheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
508 {
509 /* create pathfinder instance
510 * set origin and destination nodes */
511 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
512 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(false);
513 Yapf().SetDestination(v);
514
515 /* find the best path */
516 if (!Yapf().FindPath(v)) return false;
517
518 /* path was found
519 * walk through the path back to the origin */
520 Node *node = Yapf().GetBestNode();
521 while (node->parent != nullptr) {
522 node = node->parent;
523 }
524
525 /* check if it was reversed origin */
526 bool reversed = (node->cost != 0);
527 return reversed;
528 }
529};
530
531template <class Tpf_, class Ttrack_follower, template <class Types> class TdestinationT, template <class Types> class TfollowT>
532 struct CYapfRail_TypesT {
533 typedef CYapfRail_TypesT<Tpf_, Ttrack_follower, TdestinationT, TfollowT> Types;
534
535 typedef Tpf_ Tpf;
536 typedef Ttrack_follower TrackFollower;
537 typedef CRailNodeList NodeList;
538 typedef Train VehicleType;
539 typedef CYapfBaseT<Types> PfBase;
540 typedef TfollowT<Types> PfFollow;
541 typedef CYapfOriginTileTwoWayT<Types> PfOrigin;
542 typedef TdestinationT<Types> PfDestination;
543 typedef CYapfSegmentCostCacheGlobalT<Types> PfCache;
544 typedef CYapfCostRailT<Types> PfCost;
545};
546
547template <typename Types>
548 struct CYapfRailBase : CYapfT<Types> {
549 typedef typename Types::NodeList::Item Node;
550
559 void PruneIntermediateNodeBranch(Node *n)
560 {
561 bool intermediate_on_branch = false;
562 while (n != nullptr && !n->segment->end_segment_reason.Test(EndSegmentReason::ChoiceFollows)) {
563 if (n == this->best_intermediate_node) intermediate_on_branch = true;
564 n = n->parent;
565 }
566 if (intermediate_on_branch) this->best_intermediate_node = n;
567 }
568};
569
570 struct CYapfRail : CYapfRailBase<CYapfRail_TypesT<CYapfRail , CFollowTrackRail , CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
571 struct CYapfRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfRailNo90 , CFollowTrackRailNo90, CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
572
573 struct CYapfAnyDepotRail : CYapfRailBase<CYapfRail_TypesT<CYapfAnyDepotRail, CFollowTrackRail , CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
574 struct CYapfAnyDepotRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfAnyDepotRailNo90, CFollowTrackRailNo90, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
575
576 struct CYapfAnySafeTileRail : CYapfRailBase<CYapfRail_TypesT<CYapfAnySafeTileRail , CFollowTrackFreeRail , CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
577 struct CYapfAnySafeTileRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfAnySafeTileRailNo90, CFollowTrackFreeRailNo90, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
578
579
580 Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
581{
582 Trackdir td_ret = _settings_game.pf.forbid_90_deg
583 ? CYapfRailNo90::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest)
584 : CYapfRail::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
585
586 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks);
587}
588
589 bool YapfTrainCheckReverse(const Train *v)
590{
591 const Train *last_veh = v->Last();
592
593 /* get trackdirs of both ends */
594 Trackdir td = v->GetVehicleTrackdir();
595 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
596
597 /* tiles where front and back are */
598 TileIndex tile = v->tile;
599 TileIndex tile_rev = last_veh->tile;
600
601 int reverse_penalty = 0;
602
603 if (v->track == TRACK_BIT_WORMHOLE) {
604 /* front in tunnel / on bridge */
605 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
606
607 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
608 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
609
610 /* Current position of the train in the wormhole */
611 TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos);
612
613 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
614 * Note: Negative penalties are ok for the start tile. */
615 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
616 }
617
618 if (last_veh->track == TRACK_BIT_WORMHOLE) {
619 /* back in tunnel / on bridge */
620 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
621
622 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
623 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
624
625 /* Current position of the last wagon in the wormhole */
626 TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos);
627
628 /* Add distance to drive in the wormhole as penalty for the revere path. */
629 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
630 }
631
632 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
633 if (reverse_penalty == 0) reverse_penalty = 1;
634
635 bool reverse = _settings_game.pf.forbid_90_deg
636 ? CYapfRailNo90::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty)
637 : CYapfRail::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
638
639 return reverse;
640}
641
642 FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_penalty)
643{
644 const Train *last_veh = v->Last();
645
646 PBSTileInfo origin = FollowTrainReservation(v);
647 TileIndex last_tile = last_veh->tile;
648 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
649
650 return _settings_game.pf.forbid_90_deg
651 ? CYapfAnyDepotRailNo90::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY)
652 : CYapfAnyDepotRail::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY);
653}
654
655 bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
656{
657 return _settings_game.pf.forbid_90_deg
658 ? CYapfAnySafeTileRailNo90::stFindNearestSafeTile(v, tile, td, override_railtype)
659 : CYapfAnySafeTileRail::stFindNearestSafeTile(v, tile, td, override_railtype);
660}
661
663int CSegmentCostCacheBase::s_rail_change_counter = 0;
664
665 void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
666{
667 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);
668}
CYapfBaseT
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:48
CYapfCostRailT
Definition yapf_costrail.hpp:21
CYapfFollowAnyDepotRailT
Definition yapf_rail.cpp:210
CYapfFollowAnyDepotRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:212
CYapfFollowAnyDepotRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:219
CYapfFollowAnyDepotRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:230
CYapfFollowAnyDepotRailT::TransportTypeChar
char TransportTypeChar() const
return debug report character to identify the transportation type
Definition yapf_rail.cpp:239
CYapfFollowAnyDepotRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:214
CYapfFollowAnyDepotRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:215
CYapfFollowAnySafeTileRailT
Definition yapf_rail.cpp:301
CYapfFollowAnySafeTileRailT::TransportTypeChar
char TransportTypeChar() const
Return debug report character to identify the transportation type.
Definition yapf_rail.cpp:330
CYapfFollowAnySafeTileRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:306
CYapfFollowAnySafeTileRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:303
CYapfFollowAnySafeTileRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:321
CYapfFollowAnySafeTileRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:305
CYapfFollowAnySafeTileRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:310
CYapfFollowRailT
Definition yapf_rail.cpp:383
CYapfFollowRailT::Key
Node::Key Key
key to hash tables
Definition yapf_rail.cpp:388
CYapfFollowRailT::Yapf
Tpf & Yapf()
to access inherited path finder
Definition yapf_rail.cpp:392
CYapfFollowRailT::TransportTypeChar
char TransportTypeChar() const
return debug report character to identify the transportation type
Definition yapf_rail.cpp:412
CYapfFollowRailT::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:385
CYapfFollowRailT::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:387
CYapfFollowRailT::PfFollowNode
void PfFollowNode(Node &old_node)
Called by YAPF to move from the given node to the next tile.
Definition yapf_rail.cpp:403
CYapfOriginTileTwoWayT
YAPF origin provider base class - used when there are two tile/trackdir origins.
Definition yapf_common.hpp:48
CYapfReserveTrack
Definition yapf_rail.cpp:36
CYapfReserveTrack::SetReservationTarget
void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
Set the target to where the reservation should be extended.
Definition yapf_rail.cpp:142
CYapfReserveTrack::Node
Types::NodeList::Item Node
this will be our node type
Definition yapf_rail.cpp:40
CYapfReserveTrack::res_fail_tile
TileIndex res_fail_tile
The tile where the reservation failed.
Definition yapf_rail.cpp:53
CYapfReserveTrack::UnreserveSingleTrack
bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
Unreserve a single track/platform.
Definition yapf_rail.cpp:125
CYapfReserveTrack::ReserveRailStationPlatform
bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
Reserve a railway platform.
Definition yapf_rail.cpp:70
CYapfReserveTrack::ReserveSingleTrack
bool ReserveSingleTrack(TileIndex tile, Trackdir td)
Try to reserve a single track/platform.
Definition yapf_rail.cpp:90
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:57
CYapfReserveTrack::res_fail_td
Trackdir res_fail_td
The trackdir where the reservation failed.
Definition yapf_rail.cpp:54
CYapfReserveTrack::res_dest_node
Node * res_dest_node
The reservation target node.
Definition yapf_rail.cpp:52
CYapfReserveTrack::origin_tile
TileIndex origin_tile
Tile our reservation will originate from.
Definition yapf_rail.cpp:55
CYapfReserveTrack::res_dest_tile
TileIndex res_dest_tile
The reservation target tile.
Definition yapf_rail.cpp:50
CYapfReserveTrack::TryReservePath
bool TryReservePath(PBSTileInfo *target, TileIndex origin)
Try to reserve the path till the reservation target.
Definition yapf_rail.cpp:163
CYapfReserveTrack::Yapf
Tpf & Yapf()
to access inherited pathfinder
Definition yapf_rail.cpp:44
CYapfReserveTrack::FindSafePositionOnNode
void FindSafePositionOnNode(Node *node)
Check the node for a possible reservation target.
Definition yapf_rail.cpp:150
CYapfReserveTrack::res_dest_td
Trackdir res_dest_td
The reservation target trackdir.
Definition yapf_rail.cpp:51
CYapfReserveTrack::Tpf
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:38
CYapfSegmentCostCacheGlobalT
CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost caching functi...
Definition yapf_costcache.hpp:103
CYapfT
YAPF template that uses Ttypes template argument to determine all YAPF components (base classes) from...
Definition yapf_common.hpp:94
FileHandle::Open
static std::optional< FileHandle > Open(const std::string &filename, std::string_view mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1171
NodeList
Hash table based node list multi-container class.
Definition nodelist.hpp:21
Debug
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
DiagDirection
DiagDirection
Enumeration for diagonal directions.
Definition direction_type.h:78
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:2128
DistanceManhattan
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:169
TileVirtXY
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:416
TileAdd
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:470
TileOffsByDiagDir
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:583
TileIndexDiff
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
TriggerStationRandomisation
void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger station randomisation.
Definition newgrf_station.cpp:949
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:289
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:427
UnreserveRailTrack
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition pbs.cpp:144
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:381
SetSignalStateByTrackdir
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition rail_map.h:448
HasPbsSignalOnTrackdir
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition rail_map.h:462
GetSignalStateByTrackdir
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition rail_map.h:437
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
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
IsRailWaypointTile
bool IsRailWaypointTile(Tile t)
Is this tile a station tile and a rail waypoint?
Definition station_map.h:123
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
StationRandomTrigger::PathReservation
@ PathReservation
Trigger platform when train reserves path.
StationAnimationTrigger::PathReservation
@ PathReservation
Trigger platform when train reserves path.
BaseStation::GetByTile
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
Definition base_station_base.h:160
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:46
CYapfAnyDepotRailNo90
Definition yapf_rail.cpp:574
CYapfAnyDepotRail
Definition yapf_rail.cpp:573
CYapfAnySafeTileRailNo90
Definition yapf_rail.cpp:577
CYapfAnySafeTileRail
Definition yapf_rail.cpp:576
CYapfRailBase
Definition yapf_rail.cpp:548
CYapfRailBase::PruneIntermediateNodeBranch
void PruneIntermediateNodeBranch(Node *n)
In some cases an intermediate node branch should be pruned.
Definition yapf_rail.cpp:559
CYapfRailNo90
Definition yapf_rail.cpp:571
CYapfRail_TypesT
Definition yapf_rail.cpp:532
CYapfRail
Definition yapf_rail.cpp:570
DumpTarget
Class that represents the dump-into-string target.
Definition dbg_helpers.h:109
DumpTarget::m_out
std::string m_out
the output string
Definition dbg_helpers.h:132
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:639
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:493
SpecializedVehicle::Last
T * Last()
Get the last vehicle in the chain.
Definition vehicle_base.h:1037
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:91
Train::GetVehicleTrackdir
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition train_cmd.cpp:4226
Vehicle::y_pos
int32_t y_pos
y coordinate.
Definition vehicle_base.h:266
Vehicle::x_pos
int32_t x_pos
x coordinate.
Definition vehicle_base.h:265
Vehicle::tile
TileIndex tile
Current tile index.
Definition vehicle_base.h:225
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:66
INVALID_TRACKDIR
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:85
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:665
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:655
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:580
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:642
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:589
EndSegmentReason::ChoiceFollows
@ ChoiceFollows
the next tile contains a choice (the track splits to more than one segments)