OpenTTD Source 20260421-master-gc2fbc6fdeb
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
9
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"
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.output_buffer.data(), 1, dmp1.output_buffer.size(), *f1);
32 fwrite(dmp2.output_buffer.data(), 1, dmp2.output_buffer.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
76 {
77 TileIndex start = tile;
79
80 do {
81 if (HasStationReservation(tile)) return false;
82 SetRailStationReservation(tile, true);
84 tile = TileAdd(tile, diff);
85 } while (IsCompatibleTrainStationTile(tile, start) && tile != this->origin_tile);
86
87 auto *st = Station::GetByTile(start);
89 TriggerStationAnimation(st, start, StationAnimationTrigger::PathReservation);
90
91 return true;
92 }
93
101 {
102 Trackdir rev_td = ReverseTrackdir(td);
103 if (IsRailStationTile(tile)) {
104 if (!ReserveRailStationPlatform(tile, TrackdirToExitdir(rev_td))) {
105 /* Platform could not be reserved, undo. */
106 this->res_fail_tile = tile;
107 this->res_fail_td = td;
108 }
109 } else {
110 if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) {
111 /* Tile couldn't be reserved, undo. */
112 this->res_fail_tile = tile;
113 this->res_fail_td = td;
114 return false;
115 }
116
117 /* Green path signal opposing the path? Turn to red. */
118 if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
119 this->signals_set_to_red.emplace_back(tile, rev_td);
122 }
123
124 if (IsRailWaypointTile(tile)) {
125 auto *st = BaseStation::GetByTile(tile);
127 TriggerStationAnimation(st, tile, StationAnimationTrigger::PathReservation);
128 }
129 }
130
131 return tile != this->res_dest_tile || td != this->res_dest_td;
132 }
133
141 {
142 if (IsRailStationTile(tile)) {
143 TileIndex start = tile;
145 while ((tile != this->res_fail_tile || td != this->res_fail_td) && IsCompatibleTrainStationTile(tile, start)) {
146 SetRailStationReservation(tile, false);
147 tile = TileAdd(tile, diff);
148 }
149 } else if (tile != this->res_fail_tile || td != this->res_fail_td) {
151 }
152 return (tile != this->res_dest_tile || td != this->res_dest_td) && (tile != this->res_fail_tile || td != this->res_fail_td);
153 }
154
155public:
162 inline void SetReservationTarget(Node *node, TileIndex tile, Trackdir td)
163 {
164 this->res_dest_node = node;
165 this->res_dest_tile = tile;
166 this->res_dest_td = td;
167 }
168
173 inline void FindSafePositionOnNode(Node *node)
174 {
175 assert(node->parent != nullptr);
176
177 /* We will never pass more than two signals, no need to check for a safe tile. */
178 if (node->parent->num_signals_passed >= 2) return;
179
180 if (!node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::FindSafePositionProc)) {
181 this->res_dest_node = node;
182 }
183 }
184
192 {
193 this->res_fail_tile = INVALID_TILE;
194 this->origin_tile = origin;
195
196 if (target != nullptr) {
197 target->tile = this->res_dest_tile;
198 target->trackdir = this->res_dest_td;
199 target->okay = false;
200 }
201
202 /* Don't bother if the target is reserved. */
203 if (!IsWaitingPositionFree(Yapf().GetVehicle(), this->res_dest_tile, this->res_dest_td)) return false;
204
205 this->signals_set_to_red.clear();
206 for (Node *node = this->res_dest_node; node->parent != nullptr; node = node->parent) {
207 node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
208 if (this->res_fail_tile != INVALID_TILE) {
209 /* Reservation failed, undo. */
210 Node *fail_node = this->res_dest_node;
211 TileIndex stop_tile = this->res_fail_tile;
212 do {
213 /* If this is the node that failed, stop at the failed tile. */
214 this->res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE;
215 fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
216 } while (fail_node != node && (fail_node = fail_node->parent) != nullptr);
217
218 /* Re-instate green path signals we turned to red. */
219 for (auto [sig_tile, td] : this->signals_set_to_red) {
221 }
222
223 return false;
224 }
225 }
226
227 if (target != nullptr) target->okay = true;
228
229 if (Yapf().CanUseGlobalCache(*this->res_dest_node)) {
231 }
232
233 return true;
234 }
235};
236
237template <class Types>
239public:
240 typedef typename Types::Tpf Tpf;
241 typedef typename Types::TrackFollower TrackFollower;
242 typedef typename Types::NodeList::Item Node;
243 typedef typename Node::Key Key;
244
245protected:
247 inline Tpf &Yapf()
248 {
249 return *static_cast<Tpf *>(this);
250 }
251
252public:
254 inline void PfFollowNode(Node &old_node)
255 {
256 TrackFollower follower{Yapf().GetVehicle()};
257 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
258 Yapf().AddMultipleNodes(&old_node, follower);
259 }
260 }
261
263 inline char TransportTypeChar() const
264 {
265 return 't';
266 }
267
268 static FindDepotData stFindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
269 {
270 Tpf pf1;
271 /*
272 * With caching enabled it simply cannot get a reliable result when you
273 * have limited the distance a train may travel. This means that the
274 * cached result does not match uncached result in all cases and that
275 * causes desyncs. So disable caching when finding for a depot that is
276 * nearby. This only happens with automatic servicing of vehicles,
277 * so it will only impact performance when you do not manually set
278 * depot orders and you do not disable automatic servicing.
279 */
280 if (max_penalty != 0) pf1.DisableCache(true);
281 FindDepotData result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
282
283 if (_debug_desync_level >= 2) {
284 Tpf pf2;
285 pf2.DisableCache(true);
286 FindDepotData result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty);
287 if (result1.tile != result2.tile || (result1.reverse != result2.reverse)) {
288 Debug(desync, 2, "warning: FindNearestDepotTwoWay cache mismatch: {} vs {}",
289 result1.tile != INVALID_TILE ? "T" : "F",
290 result2.tile != INVALID_TILE ? "T" : "F");
291 DumpState(pf1, pf2);
292 }
293 }
294
295 return result1;
296 }
297
298 inline FindDepotData FindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty)
299 {
300 /* set origin and destination nodes */
301 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
302 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
303 Yapf().SetDestination(v);
304 Yapf().SetMaxCost(max_penalty);
305
306 /* find the best path */
307 if (!Yapf().FindPath(v)) return FindDepotData();
308
309 /* Some path found. */
310 Node *n = Yapf().GetBestNode();
311
312 /* walk through the path back to the origin */
313 Node *node = n;
314 while (node->parent != nullptr) {
315 node = node->parent;
316 }
317
318 /* if the origin node is our front vehicle tile/Trackdir then we didn't reverse
319 * but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed) */
320 return FindDepotData(n->GetLastTile(), n->cost, node->cost != 0);
321 }
322};
323
324template <class Types>
326public:
327 typedef typename Types::Tpf Tpf;
328 typedef typename Types::TrackFollower TrackFollower;
329 typedef typename Types::NodeList::Item Node;
330 typedef typename Node::Key Key;
331
332protected:
334 inline Tpf &Yapf()
335 {
336 return *static_cast<Tpf *>(this);
337 }
338
339public:
341 inline void PfFollowNode(Node &old_node)
342 {
343 TrackFollower follower{Yapf().GetVehicle(), Yapf().GetCompatibleRailTypes()};
344 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()) && follower.MaskReservedTracks()) {
345 Yapf().AddMultipleNodes(&old_node, follower);
346 }
347 }
348
350 inline char TransportTypeChar() const
351 {
352 return 't';
353 }
354
355 static bool stFindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype)
356 {
357 /* Create pathfinder instance */
358 Tpf pf1;
359 bool result1;
360 if (_debug_desync_level < 2) {
361 result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false);
362 } else {
363 bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true);
364 Tpf pf2;
365 pf2.DisableCache(true);
366 result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false);
367 if (result1 != result2) {
368 Debug(desync, 2, "warning: FindSafeTile cache mismatch: {} vs {}", result2 ? "T" : "F", result1 ? "T" : "F");
369 DumpState(pf1, pf2);
370 }
371 }
372
373 return result1;
374 }
375
376 bool FindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype, bool dont_reserve)
377 {
378 /* Set origin and destination. */
379 Yapf().SetOrigin(t1, td);
380 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
381 Yapf().SetDestination(v, override_railtype);
382
383 if (!Yapf().FindPath(v)) return false;
384
385 /* Found a destination, set as reservation target. */
386 Node *node = Yapf().GetBestNode();
387 this->SetReservationTarget(node, node->GetLastTile(), node->GetLastTrackdir());
388
389 /* Walk through the path back to the origin. */
390 Node *prev = nullptr;
391 while (node->parent != nullptr) {
392 prev = node;
393 node = node->parent;
394
395 this->FindSafePositionOnNode(prev);
396 }
397
398 return dont_reserve || this->TryReservePath(nullptr, node->GetLastTile());
399 }
400};
401
402template <class Types>
403class CYapfFollowRailT : public CYapfReserveTrack<Types> {
404public:
405 typedef typename Types::Tpf Tpf;
406 typedef typename Types::TrackFollower TrackFollower;
407 typedef typename Types::NodeList::Item Node;
408 typedef typename Node::Key Key;
409
410protected:
412 inline Tpf &Yapf()
413 {
414 return *static_cast<Tpf *>(this);
415 }
416
417public:
419 inline void PfFollowNode(Node &old_node)
420 {
421 TrackFollower follower{Yapf().GetVehicle()};
422 if (follower.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) {
423 Yapf().AddMultipleNodes(&old_node, follower);
424 }
425 }
426
428 inline char TransportTypeChar() const
429 {
430 return 't';
431 }
432
433 static Trackdir stChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
434 {
435 /* create pathfinder instance */
436 Tpf pf1;
437 Trackdir result1;
438
439 if (_debug_desync_level < 2) {
440 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
441 } else {
442 result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, nullptr, nullptr);
443 Tpf pf2;
444 pf2.DisableCache(true);
445 Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
446 if (result1 != result2) {
447 Debug(desync, 2, "warning: ChooseRailTrack cache mismatch: {} vs {}", result1, result2);
448 DumpState(pf1, pf2);
449 }
450 }
451
452 return result1;
453 }
454
455 inline Trackdir ChooseRailTrack(const Train *v, TileIndex, DiagDirection, TrackBits, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
456 {
457 if (target != nullptr) target->tile = INVALID_TILE;
458 if (dest != nullptr) *dest = INVALID_TILE;
459
460 /* set origin and destination nodes */
461 PBSTileInfo origin = FollowTrainReservation(v);
462 Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1);
463 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(true);
464 Yapf().SetDestination(v);
465
466 /* find the best path */
467 path_found = Yapf().FindPath(v);
468
469 /* if path not found - return INVALID_TRACKDIR */
470 Trackdir next_trackdir = INVALID_TRACKDIR;
471 Node *node = Yapf().GetBestNode();
472 if (node != nullptr) {
473 /* reserve till end of path */
474 this->SetReservationTarget(node, node->GetLastTile(), node->GetLastTrackdir());
475
476 /* path was found or at least suggested
477 * walk through the path back to the origin */
478 Node *prev = nullptr;
479 while (node->parent != nullptr) {
480 prev = node;
481 node = node->parent;
482
483 this->FindSafePositionOnNode(prev);
484 }
485
486 /* If the best PF node has no parent, then there is no (valid) best next trackdir to return.
487 * This occurs when the PF is called while the train is already at its destination. */
488 if (prev == nullptr) return INVALID_TRACKDIR;
489
490 /* return trackdir from the best origin node (one of start nodes) */
491 Node &best_next_node = *prev;
492 next_trackdir = best_next_node.GetTrackdir();
493
494 if (reserve_track && path_found) {
495 if (dest != nullptr) *dest = Yapf().GetBestNode()->GetLastTile();
496 this->TryReservePath(target, node->GetLastTile());
497 }
498 }
499
500 /* Treat the path as found if stopped on the first two way signal(s). */
501 path_found |= Yapf().stopped_on_first_two_way_signal;
502 return next_trackdir;
503 }
504
505 static bool stCheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
506 {
507 Tpf pf1;
508 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
509
510 if (_debug_desync_level >= 2) {
511 Tpf pf2;
512 pf2.DisableCache(true);
513 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
514 if (result1 != result2) {
515 Debug(desync, 2, "warning: CheckReverseTrain cache mismatch: {} vs {}", result1 ? "T" : "F", result2 ? "T" : "F");
516 DumpState(pf1, pf2);
517 }
518 }
519
520 return result1;
521 }
522
523 inline bool CheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
524 {
525 /* create pathfinder instance
526 * set origin and destination nodes */
527 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty);
528 Yapf().SetTreatFirstRedTwoWaySignalAsEOL(false);
529 Yapf().SetDestination(v);
530
531 /* find the best path */
532 if (!Yapf().FindPath(v)) return false;
533
534 /* path was found
535 * walk through the path back to the origin */
536 Node *node = Yapf().GetBestNode();
537 while (node->parent != nullptr) {
538 node = node->parent;
539 }
540
541 /* check if it was reversed origin */
542 bool reversed = (node->cost != 0);
543 return reversed;
544 }
545};
546
547template <class Tpf_, class Ttrack_follower, template <class Types> class TdestinationT, template <class Types> class TfollowT>
550
551 typedef Tpf_ Tpf;
552 typedef Ttrack_follower TrackFollower;
553 typedef CRailNodeList NodeList;
554 typedef Train VehicleType;
555 typedef CYapfBaseT<Types> PfBase;
556 typedef TfollowT<Types> PfFollow;
557 typedef CYapfOriginTileTwoWayT<Types> PfOrigin;
558 typedef TdestinationT<Types> PfDestination;
560 typedef CYapfCostRailT<Types> PfCost;
561};
562
563template <typename Types>
564struct CYapfRailBase : CYapfT<Types> {
565 typedef typename Types::NodeList::Item Node;
566
577 {
578 bool intermediate_on_branch = false;
579 while (n != nullptr && !n->segment->end_segment_reason.Test(EndSegmentReason::ChoiceFollows)) {
580 if (n == this->best_intermediate_node) intermediate_on_branch = true;
581 n = n->parent;
582 }
583 if (intermediate_on_branch) this->best_intermediate_node = n;
584 }
585};
586
587struct CYapfRail : CYapfRailBase<CYapfRail_TypesT<CYapfRail , CFollowTrackRail , CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
588struct CYapfRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfRailNo90 , CFollowTrackRailNo90, CYapfDestinationTileOrStationRailT, CYapfFollowRailT>> {};
589
590struct CYapfAnyDepotRail : CYapfRailBase<CYapfRail_TypesT<CYapfAnyDepotRail, CFollowTrackRail , CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
591struct CYapfAnyDepotRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfAnyDepotRailNo90, CFollowTrackRailNo90, CYapfDestinationAnyDepotRailT , CYapfFollowAnyDepotRailT>> {};
592
593struct CYapfAnySafeTileRail : CYapfRailBase<CYapfRail_TypesT<CYapfAnySafeTileRail , CFollowTrackFreeRail , CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
594struct CYapfAnySafeTileRailNo90 : CYapfRailBase<CYapfRail_TypesT<CYapfAnySafeTileRailNo90, CFollowTrackFreeRailNo90, CYapfDestinationAnySafeTileRailT , CYapfFollowAnySafeTileRailT>> {};
595
596
597Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target, TileIndex *dest)
598{
599 Trackdir td_ret = _settings_game.pf.forbid_90_deg
600 ? CYapfRailNo90::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest)
601 : CYapfRail::stChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target, dest);
602
603 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks);
604}
605
607{
608 const Train *moving_front = v->GetMovingFront();
609 const Train *moving_back = v->GetMovingBack();
610
611 /* get trackdirs of both ends */
612 Trackdir td = moving_front->GetVehicleTrackdir();
613 Trackdir td_rev = ReverseTrackdir(moving_back->GetVehicleTrackdir());
614
615 /* tiles where front and back are */
616 TileIndex tile = moving_front->tile;
617 TileIndex tile_rev = moving_back->tile;
618
619 int reverse_penalty = 0;
620
621 /* Consider whether the train might back up at reduced speed. */
622 if (_settings_game.difficulty.train_flip_reverse_allowed == TrainFlipReversingAllowed::None && !v->Last()->CanLeadTrain()) {
623 constexpr int DRIVING_BACKWARDS_PENALTY = 100 * YAPF_TILE_LENGTH;
624
626 /* We're currently driving forwards at full speed, and would rather not reverse if possible. */
627 reverse_penalty += DRIVING_BACKWARDS_PENALTY;
628 }
629 }
630
631 if (moving_front->track == TRACK_BIT_WORMHOLE) {
632 /* front in tunnel / on bridge */
633 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
634
635 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
636 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
637
638 /* Current position of the train in the wormhole */
639 TileIndex cur_tile = TileVirtXY(moving_front->x_pos, moving_front->y_pos);
640
641 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
642 * Note: Negative penalties are ok for the start tile. */
643 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
644 }
645
646 if (moving_back->track == TRACK_BIT_WORMHOLE) {
647 /* back in tunnel / on bridge */
648 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
649
650 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
651 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
652
653 /* Current position of the last wagon in the wormhole */
654 TileIndex cur_tile = TileVirtXY(moving_back->x_pos, moving_back->y_pos);
655
656 /* Add distance to drive in the wormhole as penalty for the revere path. */
657 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
658 }
659
660 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
661 if (reverse_penalty == 0) reverse_penalty = 1;
662
663 bool reverse = _settings_game.pf.forbid_90_deg
664 ? CYapfRailNo90::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty)
665 : CYapfRail::stCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
666
667 return reverse;
668}
669
671{
672 const Train *moving_back = v->GetMovingBack();
673
675 TileIndex last_tile = moving_back->tile;
676 Trackdir td_rev = ReverseTrackdir(moving_back->GetVehicleTrackdir());
677
678 return _settings_game.pf.forbid_90_deg
679 ? CYapfAnyDepotRailNo90::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY)
680 : CYapfAnyDepotRail::stFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY);
681}
682
683bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
684{
685 return _settings_game.pf.forbid_90_deg
686 ? CYapfAnySafeTileRailNo90::stFindNearestSafeTile(v, tile, td, override_railtype)
687 : CYapfAnySafeTileRail::stFindNearestSafeTile(v, tile, td, override_railtype);
688}
689
692
694{
695 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);
696}
@ DrivingBackwards
Vehicle is driving backwards.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
CYapfBaseT - A-star type path finder base class.
Definition yapf_base.hpp:48
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
Tpf & Yapf()
Access the 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()
Access the inherited path finder.
Node::Key Key
key to hash tables
Tpf & Yapf()
Access the 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:75
bool ReserveSingleTrack(TileIndex tile, Trackdir td)
Reserve a single track/platform.
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()
Access the inherited path finder.
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:1172
#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:169
static TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:407
constexpr TileIndex TileAdd(TileIndex tile, TileIndexDiff offset)
Adds a given offset to a tile.
Definition map_func.h:461
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
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.
Header file for NewGRF stations.
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.
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:441
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition pbs.cpp:144
PBSTileInfo FollowTrainReservation(const Train *consist, Vehicle **train_on_res)
Follow a train reservation to the last tile.
Definition pbs.cpp:301
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:395
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition rail_map.h:520
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition rail_map.h:535
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition rail_map.h:506
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
@ None
Trains cannot flip anywhere and must back up if the track ends.
@ 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.
Definition of base types and functions in a cross-platform compatible way.
VehicleFlags vehicle_flags
Used for gradual loading and other miscellaneous things (.
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
void PruneIntermediateNodeBranch(Node *n)
In some cases an intermediate node branch should be pruned.
Class that represents the dump-into-string target.
std::string output_buffer
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.
bool CanLeadTrain() const
Check if this vehicle can lead a train.
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
T * GetMovingFront() const
Get the moving front of the vehicle chain.
T * Last()
Get the last vehicle in the chain.
T * GetMovingBack() const
Get the moving back of the vehicle chain.
'Train' is either a loco or a wagon.
Definition train.h:97
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
TrackBits track
On which track the train currently is.
Definition train.h:110
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
TileIndex tile
Current tile index.
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
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:441
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.
Functions related to (drawing on) viewports.
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.
@ ChoiceFollows
the next tile contains a choice (the track splits to more than one segments)
Definition yapf_type.hpp:23