From 909b20ee685714d62ddc070e426e93b70955e9e7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 21 Feb 2022 18:30:43 +0000 Subject: [PATCH] Implement train speed adaptation on signalled tunnels/bridges See: #373 --- src/saveload/extended_ver_sl.cpp | 2 +- src/saveload/train_speed_adaptation.cpp | 13 ++- src/train_cmd.cpp | 141 +++++++++++++++--------- src/train_speed_adaptation.h | 8 +- 4 files changed, 106 insertions(+), 58 deletions(-) diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 6df9dc469b..b0c8beb3ed 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -156,7 +156,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr }, { XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr }, { XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 1, 1, "station_cargo_history", nullptr, nullptr, nullptr }, - { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, + { XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 2, 2, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, { XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr }, { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, diff --git a/src/saveload/train_speed_adaptation.cpp b/src/saveload/train_speed_adaptation.cpp index ce4385b2e4..37b40e2178 100644 --- a/src/saveload/train_speed_adaptation.cpp +++ b/src/saveload/train_speed_adaptation.cpp @@ -14,35 +14,42 @@ using SignalSpeedType = std::pair; static const SaveLoad _train_speed_adaptation_map_desc[] = { - SLE_VAR(SignalSpeedType, first.signal_track, SLE_UINT8), + SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 1, 1)), + SLE_CONDVAR_X(SignalSpeedType, first.signal_track, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION, 2)), SLE_VAR(SignalSpeedType, first.last_passing_train_dir, SLE_UINT8), SLE_VAR(SignalSpeedType, second.train_speed, SLE_UINT16), SLE_VAR(SignalSpeedType, second.time_stamp, SLE_UINT64), }; +static std::vector _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc); + static void Load_TSAS() { + _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc); int index; SignalSpeedType data; while ((index = SlIterateArray()) != -1) { const_cast(data.first).signal_tile = index; - SlObject(&data, _train_speed_adaptation_map_desc); + SlObjectLoadFiltered(&data, _filtered_train_speed_adaptation_map_desc); _signal_speeds.insert(data); } + _filtered_train_speed_adaptation_map_desc.clear(); } static void RealSave_TSAS(SignalSpeedType *data) { - SlObject(data, _train_speed_adaptation_map_desc); + SlObjectSaveFiltered(data, _filtered_train_speed_adaptation_map_desc); } static void Save_TSAS() { + _filtered_train_speed_adaptation_map_desc = SlFilterObject(_train_speed_adaptation_map_desc); for (auto &it : _signal_speeds) { SlSetArrayIndex(it.first.signal_tile); SignalSpeedType *data = ⁢ SlAutolength((AutolengthProc*) RealSave_TSAS, data); } + _filtered_train_speed_adaptation_map_desc.clear(); } extern const ChunkHandler train_speed_adaptation_chunk_handlers[] = { diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index ae180f3670..efe34e32b2 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -133,7 +133,7 @@ void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta) /** Removes all speed restrictions which have passed their timeout from all signals */ void ClearOutOfDateSignalSpeedRestrictions() { - for(auto key_value_pair = _signal_speeds.begin(); key_value_pair != _signal_speeds.end(); ) { + for (auto key_value_pair = _signal_speeds.begin(); key_value_pair != _signal_speeds.end(); ) { if (IsOutOfDate(key_value_pair->second)) { key_value_pair = _signal_speeds.erase(key_value_pair); } else { @@ -5610,28 +5610,38 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->wait_counter = (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE; v->tunnel_bridge_signal_num = 0; - if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) { + if (v->IsFrontEngine() && IsTunnelBridgeSignalSimulationEntrance(old_tile) && (IsTunnelBridgeRestrictedSignal(old_tile) || _settings_game.vehicle.train_speed_adaptation)) { const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile); - const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir)); - if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) { - TraceRestrictProgramResult out; - TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); - input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER; - prog->Execute(v, input, out); - HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir); + if (IsTunnelBridgeRestrictedSignal(old_tile)) { + const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, TrackdirToTrack(trackdir)); + if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) { + TraceRestrictProgramResult out; + TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); + input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER; + prog->Execute(v, input, out); + HandleTraceRestrictSpeedRestrictionAction(out, v, trackdir); + } + } + if (_settings_game.vehicle.train_speed_adaptation) { + SetSignalTrainAdaptationSpeed(v, old_tile, TrackdirToTrack(trackdir)); } } - if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && IsTunnelBridgeRestrictedSignal(old_tile)) { + if (v->Next() == nullptr && IsTunnelBridgeSignalSimulationEntrance(old_tile) && (IsTunnelBridgeRestrictedSignal(old_tile) || _settings_game.vehicle.train_speed_adaptation)) { const Trackdir trackdir = GetTunnelBridgeEntranceTrackdir(old_tile); const Track track = TrackdirToTrack(trackdir); - const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track); - if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { - TraceRestrictProgramResult out; - TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); - input.permitted_slot_operations = TRPISP_RELEASE_BACK; - prog->Execute(first, input, out); + if (IsTunnelBridgeRestrictedSignal(old_tile)) { + const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(old_tile, track); + if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { + TraceRestrictProgramResult out; + TraceRestrictProgramInput input(old_tile, trackdir, nullptr, nullptr); + input.permitted_slot_operations = TRPISP_RELEASE_BACK; + prog->Execute(first, input, out); + } + } + if (_settings_game.vehicle.train_speed_adaptation) { + ApplySignalTrainAdaptationSpeed(v, old_tile, track); } } } @@ -5672,10 +5682,18 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) SetBridgeEntranceSimulatedSignalState(v->tile, v->tunnel_bridge_signal_num, SIGNAL_STATE_RED); MarkSingleBridgeSignalDirty(gp.new_tile, v->tile); } + if (_settings_game.vehicle.train_speed_adaptation && distance == 0 && IsTunnelBridgeSignalSimulationEntrance(v->tile)) { + ApplySignalTrainAdaptationSpeed(v, v->tile, 0x100 + v->tunnel_bridge_signal_num); + } } } if (v->Next() == nullptr) { - if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE) HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2); + if (v->tunnel_bridge_signal_num > 0 && distance == (TILE_SIZE * simulated_wormhole_signals) - TILE_SIZE) { + HandleSignalBehindTrain(v, v->tunnel_bridge_signal_num - 2); + if (_settings_game.vehicle.train_speed_adaptation) { + SetSignalTrainAdaptationSpeed(v, v->tile, 0x100 + v->tunnel_bridge_signal_num - 1); + } + } DiagDirection tunnel_bridge_dir = GetTunnelBridgeDirection(v->tile); Axis axis = DiagDirToAxis(tunnel_bridge_dir); DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis); @@ -5803,26 +5821,14 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); if (HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) { - const Track track = TrackdirToTrack(rev_trackdir); - SignalSpeedKey speed_key = { - speed_key.signal_tile = gp.old_tile, - speed_key.signal_track = track, - speed_key.last_passing_train_dir = v->GetVehicleTrackdir() - }; - const auto found_speed_restriction = _signal_speeds.find(speed_key); - - if (found_speed_restriction != _signal_speeds.end()) { - if (IsOutOfDate(found_speed_restriction->second)) { - _signal_speeds.erase(found_speed_restriction); - v->signal_speed_restriction = 0; - } else { - v->signal_speed_restriction = std::max(25, found_speed_restriction->second.train_speed); - } - } else { - v->signal_speed_restriction = 0; - } + ApplySignalTrainAdaptationSpeed(v, gp.old_tile, TrackdirToTrack(rev_trackdir)); } } + if (_settings_game.vehicle.train_speed_adaptation && IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile)) { + const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); + const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); + ApplySignalTrainAdaptationSpeed(v, gp.old_tile, TrackdirToTrack(rev_trackdir)); + } switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir, true)) { case CHANGED_NORMAL_TO_PBS_BLOCK: @@ -5867,16 +5873,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const Track track = TrackdirToTrack(rev_trackdir); if (_settings_game.vehicle.train_speed_adaptation && HasSignalOnTrackdir(gp.old_tile, ReverseTrackdir(rev_trackdir))) { - SignalSpeedKey speed_key = { - speed_key.signal_tile = gp.old_tile, - speed_key.signal_track = track, - speed_key.last_passing_train_dir = v->GetVehicleTrackdir() - }; - SignalSpeedValue speed_value = { - speed_value.train_speed = v->First()->cur_speed, - speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First()) - }; - _signal_speeds[speed_key] = speed_value; + SetSignalTrainAdaptationSpeed(v, gp.old_tile, track); } if (HasSignalOnTrack(gp.old_tile, track)) { @@ -5892,18 +5889,23 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } } - if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && IsTunnelBridgeRestrictedSignal(gp.old_tile)) { + if (IsTileType(gp.old_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExit(gp.old_tile) && (IsTunnelBridgeRestrictedSignal(gp.old_tile) || _settings_game.vehicle.train_speed_adaptation)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTunnelBridgeTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); if (TrackdirEntersTunnelBridge(gp.old_tile, rev_trackdir)) { - const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); - if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { - TraceRestrictProgramResult out; - TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr); - input.permitted_slot_operations = TRPISP_RELEASE_BACK; - prog->Execute(first, input, out); + if (IsTunnelBridgeRestrictedSignal(gp.old_tile)) { + const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); + if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { + TraceRestrictProgramResult out; + TraceRestrictProgramInput input(gp.old_tile, ReverseTrackdir(rev_trackdir), nullptr, nullptr); + input.permitted_slot_operations = TRPISP_RELEASE_BACK; + prog->Execute(first, input, out); + } + } + if (_settings_game.vehicle.train_speed_adaptation) { + SetSignalTrainAdaptationSpeed(v, gp.old_tile, track); } } } @@ -7271,3 +7273,38 @@ int GetTrainEstimatedMaxAchievableSpeed(const Train *train, const int mass, cons return max_speed; } + +void SetSignalTrainAdaptationSpeed(const Train *v, TileIndex tile, uint16 track) +{ + SignalSpeedKey speed_key = { + speed_key.signal_tile = tile, + speed_key.signal_track = track, + speed_key.last_passing_train_dir = v->GetVehicleTrackdir() + }; + SignalSpeedValue speed_value = { + speed_value.train_speed = v->First()->cur_speed, + speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First()) + }; + _signal_speeds[speed_key] = speed_value; +} + +void ApplySignalTrainAdaptationSpeed(Train *v, TileIndex tile, uint16 track) +{ + SignalSpeedKey speed_key = { + speed_key.signal_tile = tile, + speed_key.signal_track = track, + speed_key.last_passing_train_dir = v->GetVehicleTrackdir() + }; + const auto found_speed_restriction = _signal_speeds.find(speed_key); + + if (found_speed_restriction != _signal_speeds.end()) { + if (IsOutOfDate(found_speed_restriction->second)) { + _signal_speeds.erase(found_speed_restriction); + v->signal_speed_restriction = 0; + } else { + v->signal_speed_restriction = std::max(25, found_speed_restriction->second.train_speed); + } + } else { + v->signal_speed_restriction = 0; + } +} diff --git a/src/train_speed_adaptation.h b/src/train_speed_adaptation.h index 4f4c3e20b2..6407c7b22f 100644 --- a/src/train_speed_adaptation.h +++ b/src/train_speed_adaptation.h @@ -19,7 +19,7 @@ struct SignalSpeedKey { TileIndex signal_tile; - Track signal_track; + uint16 signal_track; Trackdir last_passing_train_dir; bool operator==(const SignalSpeedKey& other) const @@ -42,7 +42,7 @@ struct SignalSpeedKeyHashFunc { const std::size_t h1 = std::hash()(key.signal_tile); const std::size_t h2 = std::hash()(key.last_passing_train_dir); - const std::size_t h3 = std::hash()(key.signal_track); + const std::size_t h3 = std::hash()(key.signal_track); return (h1 ^ h2) ^ h3; } @@ -50,4 +50,8 @@ struct SignalSpeedKeyHashFunc extern std::unordered_map _signal_speeds; +struct Train; +void SetSignalTrainAdaptationSpeed(const Train *v, TileIndex tile, uint16 track); +void ApplySignalTrainAdaptationSpeed(Train *v, TileIndex tile, uint16 track); + #endif /* TRAIN_SPEED_ADAPTATION_H */