diff --git a/src/pbs.cpp b/src/pbs.cpp index e466bf773f..f276edd4be 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -657,6 +657,23 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) return nullptr; } +bool ValidateLookAhead(const Train *v) +{ + TileIndex tile = v->lookahead->reservation_end_tile; + Trackdir trackdir = v->lookahead->reservation_end_trackdir; + + if (HasBit(v->lookahead->flags, TRLF_TB_EXIT_FREE)) { + if (!likely(IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && TrackdirEntersTunnelBridge(tile, trackdir))) { + return false; + } + } + if (HasBit(v->lookahead->flags, TRLF_DEPOT_END) && !IsRailDepotTile(tile)) return false; + + TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)); + if (!HasTrackdir(trackdirbits, trackdir)) return false; + + return true; +} /** * Follow a train reservation to the last tile. diff --git a/src/pbs.h b/src/pbs.h index c72f36b547..6a2309edcc 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -141,6 +141,7 @@ enum FollowTrainReservationFlags { }; DECLARE_ENUM_AS_BIT_SET(FollowTrainReservationFlags) +bool ValidateLookAhead(const Train *v); PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = nullptr, FollowTrainReservationFlags flags = FTRF_NONE); void ApplyAvailableFreeTunnelBridgeTiles(TrainReservationLookAhead *lookahead, int free_tiles, TileIndex tile, TileIndex end); void TryCreateLookAheadForTrainInTunnelBridge(Train *t); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 42b3084a46..593ac3f692 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -67,10 +67,11 @@ struct ChooseTrainTrackLookAheadState { /** Flags for ChooseTrainTrack */ enum ChooseTrainTrackFlags { - CTTF_NONE = 0, ///< No flags - CTTF_FORCE_RES = 0x01, ///< Force a reservation to be made - CTTF_MARK_STUCK = 0x02, ///< The train has to be marked as stuck when needed - CTTF_NON_LOOKAHEAD = 0x04, ///< Any lookahead should not be used, if necessary reset the lookahead state + CTTF_NONE = 0, ///< No flags + CTTF_FORCE_RES = 0x01, ///< Force a reservation to be made + CTTF_MARK_STUCK = 0x02, ///< The train has to be marked as stuck when needed + CTTF_NON_LOOKAHEAD = 0x04, ///< Any lookahead should not be used, if necessary reset the lookahead state + CTTF_NO_LOOKAHEAD_VALIDATE = 0x08, ///< Don't validate the lookahead state as it has already been done }; DECLARE_ENUM_AS_BIT_SET(ChooseTrainTrackFlags) @@ -90,6 +91,11 @@ static void TrainEnterStation(Train *v, StationID station); static void UnreserveBridgeTunnelTile(TileIndex tile); static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile); +inline void ClearLookAheadIfInvalid(Train *v) +{ + if (v->lookahead != nullptr && !ValidateLookAhead(v)) v->lookahead.reset(); +} + static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; @@ -2984,6 +2990,8 @@ static FindDepotData FindClosestTrainDepot(Train *v, int max_distance) if (IsRailDepotTile(v->tile)) return FindDepotData(v->tile, 0); + if (v->lookahead != nullptr && !ValidateLookAhead(v)) return FindDepotData(); + PBSTileInfo origin = FollowTrainReservation(v, nullptr, FTRF_OKAY_UNUSED); if (IsRailDepotTile(origin.tile)) return FindDepotData(origin.tile, 0); @@ -3900,7 +3908,7 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td } SetTunnelBridgeExitSignalState(exit_tile, SIGNAL_STATE_GREEN); - ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), force_res ? CTTF_FORCE_RES : CTTF_NONE, nullptr, lookahead_state); + ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), CTTF_NO_LOOKAHEAD_VALIDATE | (force_res ? CTTF_FORCE_RES : CTTF_NONE), nullptr, lookahead_state); if (reserved_bits == GetReservedTrackbits(ft.m_new_tile)) { /* next tile is still not reserved, so unreserve exit and restore signal state */ @@ -3921,12 +3929,14 @@ static void TryLongReserveChooseTrainTrack(Train *v, TileIndex tile, Trackdir td CFollowTrackRail ft(v); if (ft.Follow(tile, td) && HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits), !long_enough)) { // We reserved up to a LR signal, reserve past it as well. recursion - ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), force_res ? CTTF_FORCE_RES : CTTF_NONE, nullptr, lookahead_state); + ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), CTTF_NO_LOOKAHEAD_VALIDATE | (force_res ? CTTF_FORCE_RES : CTTF_NONE), nullptr, lookahead_state); } } static void TryLongReserveChooseTrainTrackFromReservationEnd(Train *v, bool no_reserve_vehicle_tile) { + ClearLookAheadIfInvalid(v); + PBSTileInfo origin = FollowTrainReservation(v, nullptr, FTRF_OKAY_UNUSED); if (IsRailDepotTile(origin.tile)) return; @@ -4012,6 +4022,10 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, v->lookahead.reset(); } + if (!(flags & CTTF_NO_LOOKAHEAD_VALIDATE)) { + ClearLookAheadIfInvalid(v); + } + PBSTileInfo origin = FollowTrainReservation(v, nullptr, FTRF_OKAY_UNUSED); PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); DiagDirection dest_enterdir = enterdir; @@ -4186,6 +4200,8 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) { assert(v->IsFrontEngine()); + ClearLookAheadIfInvalid(v); + if (v->lookahead != nullptr && HasBit(v->lookahead->flags, TRLF_DEPOT_END)) return true; /* We have to handle depots specially as the track follower won't look