OpenTTD Source 20250818-master-g1850ad1aa2
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"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>
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:
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
71 {
72 TileIndex start = tile;
74
75 do {
76 if (HasStationReservation(tile)) return false;
77 SetRailStationReservation(tile, true);
79 tile = TileAdd(tile, diff);
80 } while (IsCompatibleTrainStationTile(tile, start) && tile != this->origin_tile);
81
82 auto *st = Station::GetByTile(start);
84 TriggerStationAnimation(st, start, StationAnimationTrigger::PathReservation);
85
86 return true;
87 }
88
91 {
92 Trackdir rev_td = ReverseTrackdir(td);
93 if (IsRailStationTile(tile)) {
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);
112 }
113
114 if (IsRailWaypointTile(tile)) {
115 auto *st = BaseStation::GetByTile(tile);
117 TriggerStationAnimation(st, tile, StationAnimationTrigger::PathReservation);
118 }
119 }
120
121 return tile != this->res_dest_tile || td != this->res_dest_td;
122 }
123
126 {
127 if (IsRailStationTile(tile)) {
128 TileIndex start = tile;
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) {
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
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) {
193 }
194
195 return false;
196 }
197 }
198
199 if (target != nullptr) target->okay = true;
200
201 if (Yapf().CanUseGlobalCache(*this->res_dest_node)) {
203 }
204
205 return true;
206 }
207};
208
209template <class Types>
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 F(Yapf().GetVehicle());
233 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
234 Yapf().AddMultipleNodes(&old_node, F);
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>
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 F(Yapf().GetVehicle(), Yapf().GetCompatibleRailTypes());
324 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()) && F.MaskReservedTracks()) {
325 Yapf().AddMultipleNodes(&old_node, F);
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(false);
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>
383class 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 F(Yapf().GetVehicle());
406 if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
407 Yapf().AddMultipleNodes(&old_node, F);
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 */
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, class Tnode_list, template <class Types> class TdestinationT, template <class Types> class TfollowT>
534
535 typedef Tpf_ Tpf;
536 typedef Ttrack_follower TrackFollower;
537 typedef Tnode_list NodeList;
538 typedef Train VehicleType;
540 typedef TfollowT<Types> PfFollow;
542 typedef TdestinationT<Types> PfDestination;
545};
546
547struct CYapfRail1 : CYapfT<CYapfRail_TypesT<CYapfRail1 , CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
548struct CYapfRail2 : CYapfT<CYapfRail_TypesT<CYapfRail2 , CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
549
550struct CYapfAnyDepotRail1 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail1, CFollowTrackRail , CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
551struct CYapfAnyDepotRail2 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail2, CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
552
553struct CYapfAnySafeTileRail1 : CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail1, CFollowTrackFreeRail , CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
554struct CYapfAnySafeTileRail2 : CYapfT<CYapfRail_TypesT<CYapfAnySafeTileRail2, CFollowTrackFreeRailNo90, CRailNodeListTrackDir, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
555
556
557Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
558{
560 ? CYapfRail2::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest)
561 : CYapfRail1::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
562
563 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks);
564}
565
567{
568 const Train *last_veh = v->Last();
569
570 /* get trackdirs of both ends */
572 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
573
574 /* tiles where front and back are */
575 TileIndex tile = v->tile;
576 TileIndex tile_rev = last_veh->tile;
577
578 int reverse_penalty = 0;
579
580 if (v->track == TRACK_BIT_WORMHOLE) {
581 /* front in tunnel / on bridge */
582 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
583
584 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
585 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
586
587 /* Current position of the train in the wormhole */
588 TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos);
589
590 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
591 * Note: Negative penalties are ok for the start tile. */
592 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
593 }
594
595 if (last_veh->track == TRACK_BIT_WORMHOLE) {
596 /* back in tunnel / on bridge */
597 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
598
599 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
600 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
601
602 /* Current position of the last wagon in the wormhole */
603 TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos);
604
605 /* Add distance to drive in the wormhole as penalty for the revere path. */
606 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
607 }
608
609 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
610 if (reverse_penalty == 0) reverse_penalty = 1;
611
612 bool reverse = _settings_game.pf.forbid_90_deg
613 ? CYapfRail2::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty)
614 : CYapfRail1::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
615
616 return reverse;
617}
618
620{
621 const Train *last_veh = v->Last();
622
624 TileIndex last_tile = last_veh->tile;
625 Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
626
628 ? CYapfAnyDepotRail2::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY)
629 : CYapfAnyDepotRail1::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY);
630}
631
632bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
633{
635 ? CYapfAnySafeTileRail2::stFindNearestSafeTile(v, tile, td, override_railtype)
636 : CYapfAnySafeTileRail1::stFindNearestSafeTile(v, tile, td, override_railtype);
637}
638
641
643{
644 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);
645}
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:49
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
Definition yapf_rail.cpp:40
TileIndex res_fail_tile
The tile where the reservation failed.
Definition yapf_rail.cpp:53
bool UnreserveSingleTrack(TileIndex tile, Trackdir td)
Unreserve a single track/platform.
bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir)
Reserve a railway platform.
Definition yapf_rail.cpp:70
bool ReserveSingleTrack(TileIndex tile, Trackdir td)
Try to reserve a single track/platform.
Definition yapf_rail.cpp:90
std::vector< std::pair< TileIndex, Trackdir > > signals_set_to_red
List of signals turned red during a path reservation.
Definition yapf_rail.cpp:57
Trackdir res_fail_td
The trackdir where the reservation failed.
Definition yapf_rail.cpp:54
Node * res_dest_node
The reservation target node.
Definition yapf_rail.cpp:52
TileIndex origin_tile
Tile our reservation will originate from.
Definition yapf_rail.cpp:55
TileIndex res_dest_tile
The reservation target tile.
Definition yapf_rail.cpp:50
bool TryReservePath(PBSTileInfo *target, TileIndex origin)
Try to reserve the path till the reservation target.
Tpf & Yapf()
to access inherited pathfinder
Definition yapf_rail.cpp:44
void FindSafePositionOnNode(Node *node)
Check the node for a possible reservation target.
Trackdir res_dest_td
The reservation target trackdir.
Definition yapf_rail.cpp:51
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Definition yapf_rail.cpp:38
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, std::string_view mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1168
Hash table based node list multi-container class.
Definition nodelist.hpp:21
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
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.
Definition map.cpp:142
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:456
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:569
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:403
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
void TriggerStationRandomisation(BaseStation *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger station randomisation.
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.
Definition pbs.cpp:289
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
Definition pbs.cpp:80
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
Definition pbs.cpp:427
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition pbs.cpp:144
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
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition rail_map.h:448
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition rail_map.h:462
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition rail_map.h:437
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
@ SIGNAL_STATE_RED
The signal is red.
Definition signal_type.h:43
@ SIGNAL_STATE_GREEN
The signal is green.
Definition signal_type.h:44
bool IsRailWaypointTile(Tile t)
Is this tile a station tile and a rail waypoint?
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.
@ PathReservation
Trigger platform when train reserves path.
@ PathReservation
Trigger platform when train reserves path.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
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
Node of the link graph.
Definition linkgraph.h:90
This struct contains information about the end of a reserved path.
Definition pbs.h:26
Trackdir trackdir
The reserved trackdir on the tile.
Definition pbs.h:28
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
Definition pbs.h:27
bool okay
True if tile is a safe waiting position, false otherwise.
Definition pbs.h:29
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.
Definition train.h:91
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.
Definition tile_type.h:95
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition track_func.h:262
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition track_func.h:247
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition track_func.h:177
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
Allow incrementing of Track variables.
Definition track_type.h:35
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels)
Definition track_type.h:52
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:85
Track
These are used to specify a single track.
Definition track_type.h:19
@ INVALID_TRACK
Flag for an invalid track.
Definition track_type.h:28
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.