From 92ca965ef7755f2a0fad01c1089ff811db6007b5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 15 Oct 2020 20:37:57 +0100 Subject: [PATCH] Fix PBS rail type handling with incorrect GRF rail type compatibility --- src/pbs.cpp | 8 ++++---- src/rail.h | 3 +++ src/rail_cmd.cpp | 23 ++++++++++++++++++++++- src/table/railtypes.h | 12 ++++++++++++ src/train_cmd.cpp | 8 ++++---- 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/pbs.cpp b/src/pbs.cpp index b9ab51636e..37a6fc2366 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -369,7 +369,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false); FindTrainOnTrackInfo ftoti; - ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir); + ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->all_compatible_railtypes, tile, trackdir); ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg); if (train_on_res != nullptr) { FindVehicleOnPos(ftoti.res.tile, VEH_TRAIN, &ftoti, FindTrainOnTrackEnum); @@ -406,7 +406,7 @@ Train *GetTrainForReservation(TileIndex tile, Track track) assert_msg_tile(HasReservedTracks(tile, TrackToTrackBits(track)), tile, "track: %u", track); Trackdir trackdir = TrackToTrackdir(track); - RailTypes rts = GetRailTypeInfo(GetTileRailTypeByTrack(tile, track))->compatible_railtypes; + RailTypes rts = GetRailTypeInfo(GetTileRailTypeByTrack(tile, track))->all_compatible_railtypes; /* Follow the path from tile to both ends, one of the end tiles should * have a train on it. We need FollowReservation to ignore one-way signals @@ -514,7 +514,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo } /* Check next tile. For performance reasons, we check for 90 degree turns ourself. */ - CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); + CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->all_compatible_railtypes); /* End of track? */ if (!ft.Follow(tile, trackdir)) { @@ -621,7 +621,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo } /* Check the next tile, if it's a PBS signal, it has to be free as well. */ - CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); + CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->all_compatible_railtypes); if (!ft.Follow(tile, trackdir)) return true; diff --git a/src/rail.h b/src/rail.h index 36a8641f58..0fed9ca0fa 100644 --- a/src/rail.h +++ b/src/rail.h @@ -194,6 +194,9 @@ public: /** bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel */ RailTypes compatible_railtypes; + /** bitmask of all directly or indirectly reachable railtypes in either direction via compatible_railtypes */ + RailTypes all_compatible_railtypes; + /** * Bridge offset */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 8fdd322048..dd3fe0503e 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -69,7 +69,7 @@ void ResetRailTypes() {0,0,0,0,0,0,0,0,{}}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0}, - 0, RAILTYPES_NONE, RAILTYPES_NONE, 0, 0, 0, RTFB_NONE, 0, 0, 0, 0, 0, 0, + 0, RAILTYPES_NONE, RAILTYPES_NONE, RAILTYPES_NONE, 0, 0, 0, RTFB_NONE, 0, 0, 0, 0, 0, 0, RailTypeLabelList(), 0, 0, RAILTYPES_NONE, RAILTYPES_NONE, 0, {}, {} }; for (; i < lengthof(_railtypes); i++) _railtypes[i] = empty_railtype; @@ -149,6 +149,27 @@ void InitRailTypes() } } std::sort(_sorted_railtypes.begin(), _sorted_railtypes.end(), CompareRailTypes); + + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + _railtypes[rt].all_compatible_railtypes = _railtypes[rt].compatible_railtypes; + } + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + RailTypes compatible = _railtypes[rt].all_compatible_railtypes; + RailTypes to_check = compatible; + while (to_check) { + RailType i = (RailType)FindFirstBit64(to_check); + to_check = KillFirstBit(to_check); + RailTypes new_types = _railtypes[i].compatible_railtypes & (~compatible); + to_check |= new_types; + compatible |= new_types; + } + RailTypes to_update = compatible; + while (to_update) { + RailType i = (RailType)FindFirstBit64(to_update); + to_update = KillFirstBit(to_update); + _railtypes[i].all_compatible_railtypes = compatible; + } + } } /** diff --git a/src/table/railtypes.h b/src/table/railtypes.h index 25a1fdfa16..7ff8776fb1 100644 --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -65,6 +65,9 @@ static const RailtypeInfo _original_railtypes[] = { /* Compatible railtypes */ RAILTYPES_RAIL | RAILTYPES_ELECTRIC, + /* Computed compatible railtypes */ + RAILTYPES_NONE, + /* bridge offset */ 0, @@ -169,6 +172,9 @@ static const RailtypeInfo _original_railtypes[] = { /* Compatible railtypes */ RAILTYPES_ELECTRIC | RAILTYPES_RAIL, + /* Computed compatible railtypes */ + RAILTYPES_NONE, + /* bridge offset */ 0, @@ -269,6 +275,9 @@ static const RailtypeInfo _original_railtypes[] = { /* Compatible Railtypes */ RAILTYPES_MONO, + /* Computed compatible railtypes */ + RAILTYPES_NONE, + /* bridge offset */ 16, @@ -369,6 +378,9 @@ static const RailtypeInfo _original_railtypes[] = { /* Compatible Railtypes */ RAILTYPES_MAGLEV, + /* Computed compatible railtypes */ + RAILTYPES_NONE, + /* bridge offset */ 24, diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index a5d2a6f1e9..81d015f2be 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2221,7 +2221,7 @@ void ReverseTrainDirection(Train *v) TileIndex next_tile = TileVirtXY(v->x_pos, v->y_pos) + TileOffsByDiagDir(axial_dir); if (next_tile == v->tile || next_tile == GetOtherTunnelBridgeEnd(v->tile)) { Trackdir exit_td = TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(next_tile)), ReverseDiagDir(GetTunnelBridgeDirection(next_tile))); - CFollowTrackRail ft(GetTileOwner(next_tile), GetRailTypeInfo(v->railtype)->compatible_railtypes); + CFollowTrackRail ft(GetTileOwner(next_tile), GetRailTypeInfo(v->railtype)->all_compatible_railtypes); if (ft.Follow(next_tile, exit_td)) { TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); if (reserved == TRACKDIR_BIT_NONE) { @@ -2871,7 +2871,7 @@ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_t /* Do not attempt to unreserve out of a signalled tunnel/bridge entrance, as this would unreserve the reservations of another train coming in */ if (IsTunnelBridgeWithSignalSimulation(tile) && TrackdirExitsTunnelBridge(tile, td) && IsTunnelBridgeSignalSimulationEntranceOnly(tile)) return; - CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); + CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->all_compatible_railtypes); while (ft.Follow(tile, td)) { tile = ft.m_new_tile; TrackdirBits bits = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile)); @@ -3919,7 +3919,7 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile) t->tile = tile; t->track = TRACK_BIT_WORMHOLE; t->direction = TrackdirToDirection(td); - CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->compatible_railtypes); + CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->all_compatible_railtypes); if (ft.Follow(tile, td)) { TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); if (reserved == TRACKDIR_BIT_NONE) { @@ -3952,7 +3952,7 @@ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile) } SigSegState seg_state = (_settings_game.pf.reserve_paths || IsTunnelBridgePBS(tile)) ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner); if (seg_state != SIGSEG_PBS) { - CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->compatible_railtypes); + CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->all_compatible_railtypes); if (ft.Follow(tile, TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)), ReverseDiagDir(GetTunnelBridgeDirection(tile))))) { if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);