From debc504e59b6d4b3db7f7e2ff407f6c6be6c2a2d Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Thu, 17 Jun 2021 15:52:45 +0200 Subject: [PATCH 01/25] Add a setting for train speed adaptation Prior to this change, without realistic breaking, trains would continuously run into the train in front of them. This makes them adjust their speed based on trains in front of them --- src/lang/english.txt | 2 ++ src/settings_gui.cpp | 1 + src/settings_type.h | 1 + src/table/settings.ini | 13 ++++++-- src/train.h | 1 + src/train_cmd.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index eba78574a4..01d86510c5 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1811,6 +1811,8 @@ STR_CONFIG_SETTING_NOSERVICE :Disable servici STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Enable train speed adaption: {STRING2} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :If enabled, faster trains behind slower trains adjust their speed. STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Road vehicles slow down in curves: {STRING2} STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :When enabled, road vehicles slow down in curves. (Only with realistic acceleration) STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 48416d33a3..179a12e642 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1923,6 +1923,7 @@ static SettingsContainer &GetSettingsTree() physics->Add(new SettingEntry("vehicle.train_braking_model")); physics->Add(new SettingEntry("vehicle.train_slope_steepness")); physics->Add(new SettingEntry("vehicle.wagon_speed_limits")); + physics->Add(new SettingEntry("vehicle.train_speed_adaption")); physics->Add(new SettingEntry("vehicle.freight_trains")); physics->Add(new SettingEntry("vehicle.roadveh_acceleration_model")); physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness")); diff --git a/src/settings_type.h b/src/settings_type.h index e2f245a7d1..95fbe4b1f8 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -572,6 +572,7 @@ struct VehicleSettings { uint8 train_slope_steepness; ///< Steepness of hills for trains when using realistic acceleration uint8 roadveh_slope_steepness; ///< Steepness of hills for road vehicles when using realistic acceleration bool wagon_speed_limits; ///< enable wagon speed limits + bool train_speed_adaption; ///< Faster trains behind slower trains slow down bool slow_road_vehicles_in_curves; ///< Road vehicles slow down in curves. bool disable_elrails; ///< when true, the elrails are disabled UnitID max_trains; ///< max trains in game per company diff --git a/src/table/settings.ini b/src/table/settings.ini index f1c3aec765..007fe47a88 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -1676,9 +1676,18 @@ cat = SC_BASIC patxname = ""slow_road_vehicles_in_curves.vehicle.slow_road_vehicles_in_curves"" ;; vehicle.train_speed_adaption -[SDT_NULL] -length = 1 +[SDT_XREF] extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP) +xref = ""vehicle.train_speed_adaption"" + +[SDT_BOOL] +base = GameSettings +var = vehicle.train_speed_adaption +def = true +str = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION +strhelp = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT +cat = SC_EXPERT +patxname = ""train_speed_adaption.vehicle.train_speed_adaption"" [SDT_BOOL] base = GameSettings diff --git a/src/train.h b/src/train.h index 6fd5186dd6..c33f7317e4 100644 --- a/src/train.h +++ b/src/train.h @@ -190,6 +190,7 @@ struct Train FINAL : public GroundVehicle { }; private: + int GetAtcMaxSpeed(int current_max_speed) const; MaxSpeedInfo GetCurrentMaxSpeedInfoInternal(bool update_state) const; public: diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2e0a813910..6238fb13b8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -951,6 +951,80 @@ static void AdvanceLookAheadPosition(Train *v) } } +/** + * Calculates the maximum speed based on any train in front of this train. + */ +int Train::GetAtcMaxSpeed(int current_max_speed) const +{ + if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption) { + int atc_speed = current_max_speed; + + CFollowTrackRail ft(this); + Trackdir old_td = this->GetVehicleTrackdir(); + + if (ft.Follow(this->tile, this->GetVehicleTrackdir())) { + /* Basic idea: Follow the track for 20 tiles or 3 signals (i.e. at most two signal blocks) looking for other trains. */ + /* If we find one (that meets certain restrictions), we limit the max speed to the speed of that train. */ + int num_tiles = 0; + int num_signals = 0; + + do { + old_td = ft.m_old_td; + + /* If we are on a depot or rail station tile stop searching */ + if (IsDepotTile(ft.m_new_tile) || IsRailStationTile(ft.m_new_tile)) + break; + + /* Increment signal counter if we're on a signal */ + if (IsTileType(ft.m_new_tile, MP_RAILWAY) && ///< Tile has rails + KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track + HasSignalOnTrack(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits)))) { ///< Tile has signal + num_signals++; + } + + /* Check if tile has train/is reserved */ + if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track + HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { ///< Tile is reserved + Train* other_train = GetTrainForReservation(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits))); + + + if (other_train != nullptr && + other_train != this && ///< Other train is not this train + other_train->GetAccelerationStatus() != AS_BRAKE) { ///< Other train is not braking + atc_speed = other_train->GetCurrentSpeed(); + break; + } + } + + /* Decide what in direction to continue: reservation, straight or "first/only" direction. */ + /* Abort if there's no reservation even though the tile contains multiple tracks. */ + const TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); + + if (reserved != TRACKDIR_BIT_NONE) { + // There is a reservation to follow. + old_td = FindFirstTrackdir(reserved); + } + else if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { + // Tile has more than one track and we have no reservation. Bail out. + break; + } + else { + // There was no reservation but there is only one direction to follow, so follow it. + old_td = FindFirstTrackdir(ft.m_new_td_bits); + } + + num_tiles++; + } while (num_tiles < 20 && num_signals < 3 && ft.Follow(ft.m_new_tile, old_td)); + } + + /* Check that the ATC speed is sufficiently large. + Avoids assertion error in UpdateSpeed(). */ + current_max_speed = std::max(25, std::min(current_max_speed, atc_speed)); + } + + return current_max_speed; +} + /** * Calculates the maximum speed information of the vehicle under its current conditions. * @return Maximum speed information of the vehicle. @@ -961,6 +1035,8 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); + max_speed = GetAtcMaxSpeed(max_speed); + if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); int advisory_max_speed = max_speed; From 02278f7a6fb99a2cbc3538396da07761db91fa68 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Fri, 18 Jun 2021 06:25:43 +0200 Subject: [PATCH 02/25] Try something This doesn't work but hey... it's broken already in combination with realistic breaking --- src/train_cmd.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6238fb13b8..84322ad2fb 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -987,7 +987,6 @@ int Train::GetAtcMaxSpeed(int current_max_speed) const HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { ///< Tile is reserved Train* other_train = GetTrainForReservation(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits))); - if (other_train != nullptr && other_train != this && ///< Other train is not this train other_train->GetAccelerationStatus() != AS_BRAKE) { ///< Other train is not braking @@ -1005,8 +1004,12 @@ int Train::GetAtcMaxSpeed(int current_max_speed) const old_td = FindFirstTrackdir(reserved); } else if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { - // Tile has more than one track and we have no reservation. Bail out. - break; + bool path_found = false; + old_td = TrackToTrackdir(YapfTrainChooseTrack(this, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), path_found, false, nullptr)); + if(!path_found || old_td == INVALID_TRACKDIR) { + // Tile has more than one track and we have no path. Bail out. + break; + } } else { // There was no reservation but there is only one direction to follow, so follow it. From 5d20b9397c3e444941ff7a4c8619618268a9354f Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Fri, 18 Jun 2021 06:34:04 +0200 Subject: [PATCH 03/25] Revert "Try something" This reverts commit 475a097f36a70383d50ee68dac38b5ce087a1eb1. --- src/train_cmd.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 84322ad2fb..6238fb13b8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -987,6 +987,7 @@ int Train::GetAtcMaxSpeed(int current_max_speed) const HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { ///< Tile is reserved Train* other_train = GetTrainForReservation(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits))); + if (other_train != nullptr && other_train != this && ///< Other train is not this train other_train->GetAccelerationStatus() != AS_BRAKE) { ///< Other train is not braking @@ -1004,12 +1005,8 @@ int Train::GetAtcMaxSpeed(int current_max_speed) const old_td = FindFirstTrackdir(reserved); } else if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { - bool path_found = false; - old_td = TrackToTrackdir(YapfTrainChooseTrack(this, ft.m_new_tile, ft.m_exitdir, TrackdirBitsToTrackBits(ft.m_new_td_bits), path_found, false, nullptr)); - if(!path_found || old_td == INVALID_TRACKDIR) { - // Tile has more than one track and we have no path. Bail out. - break; - } + // Tile has more than one track and we have no reservation. Bail out. + break; } else { // There was no reservation but there is only one direction to follow, so follow it. From 61669868bf975d0ad5403d6aa1014976e8fbfec1 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Fri, 18 Jun 2021 06:42:15 +0200 Subject: [PATCH 04/25] Removed change and updated signal count --- src/train_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6238fb13b8..2c3c0bb4b8 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1014,7 +1014,7 @@ int Train::GetAtcMaxSpeed(int current_max_speed) const } num_tiles++; - } while (num_tiles < 20 && num_signals < 3 && ft.Follow(ft.m_new_tile, old_td)); + } while (num_tiles < 20 && num_signals < 4 && ft.Follow(ft.m_new_tile, old_td)); } /* Check that the ATC speed is sufficiently large. From c1bf236a267b867c95181ebf61ecb78e3da3133f Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sat, 19 Jun 2021 23:01:12 +0200 Subject: [PATCH 05/25] Rewrite the ATC logic Now signals store speed information with a timeout for this data's validity --- src/train.h | 3 +- src/train_cmd.cpp | 158 ++++++++++++++++++++++++---------------------- src/vehicle.cpp | 1 + 3 files changed, 87 insertions(+), 75 deletions(-) diff --git a/src/train.h b/src/train.h index c33f7317e4..b303523cc5 100644 --- a/src/train.h +++ b/src/train.h @@ -147,6 +147,7 @@ struct Train FINAL : public GroundVehicle { uint16 reverse_distance; uint16 tunnel_bridge_signal_num; uint16 speed_restriction; + uint16 signal_speed_restriction; /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Train() : GroundVehicleBase() {} @@ -190,7 +191,7 @@ struct Train FINAL : public GroundVehicle { }; private: - int GetAtcMaxSpeed(int current_max_speed) const; + int GetAtcMaxSpeed() const; MaxSpeedInfo GetCurrentMaxSpeedInfoInternal(bool update_state) const; public: diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2c3c0bb4b8..c71ce6916c 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -76,6 +76,40 @@ enum ChooseTrainTrackFlags { }; DECLARE_ENUM_AS_BIT_SET(ChooseTrainTrackFlags) +struct SignalSpeedKey +{ + TileIndex signal_tile; + Track signal_track; + Trackdir last_passing_train_dir; + + bool operator==(const SignalSpeedKey& other) const + { + return signal_tile == other.signal_tile && + signal_track == other.signal_track && + last_passing_train_dir == other.last_passing_train_dir; + } +}; + +struct SignalSpeedKeyHashFunc +{ + std::size_t operator() (const SignalSpeedKey &key) const + { + 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); + + return (h1 ^ h2) ^ h3; + } +}; + +struct SignalSpeedValue +{ + uint16 train_speed; + Date time_stamp; +}; + +static std::unordered_map _signal_speeds(1 << 16); + static void TryLongReserveChooseTrainTrackFromReservationEnd(Train *v, bool no_reserve_vehicle_tile = false); static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, ChooseTrainTrackFlags flags, bool *p_got_reservation, ChooseTrainTrackLookAheadState lookahead_state = {}); static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse); @@ -954,75 +988,13 @@ static void AdvanceLookAheadPosition(Train *v) /** * Calculates the maximum speed based on any train in front of this train. */ -int Train::GetAtcMaxSpeed(int current_max_speed) const +int Train::GetAtcMaxSpeed() const { - if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption) { - int atc_speed = current_max_speed; - - CFollowTrackRail ft(this); - Trackdir old_td = this->GetVehicleTrackdir(); - - if (ft.Follow(this->tile, this->GetVehicleTrackdir())) { - /* Basic idea: Follow the track for 20 tiles or 3 signals (i.e. at most two signal blocks) looking for other trains. */ - /* If we find one (that meets certain restrictions), we limit the max speed to the speed of that train. */ - int num_tiles = 0; - int num_signals = 0; - - do { - old_td = ft.m_old_td; - - /* If we are on a depot or rail station tile stop searching */ - if (IsDepotTile(ft.m_new_tile) || IsRailStationTile(ft.m_new_tile)) - break; - - /* Increment signal counter if we're on a signal */ - if (IsTileType(ft.m_new_tile, MP_RAILWAY) && ///< Tile has rails - KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track - HasSignalOnTrack(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits)))) { ///< Tile has signal - num_signals++; - } - - /* Check if tile has train/is reserved */ - if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE && ///< Tile has exactly *one* track - HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { ///< Tile is reserved - Train* other_train = GetTrainForReservation(ft.m_new_tile, TrackBitsToTrack(TrackdirBitsToTrackBits(ft.m_new_td_bits))); - - - if (other_train != nullptr && - other_train != this && ///< Other train is not this train - other_train->GetAccelerationStatus() != AS_BRAKE) { ///< Other train is not braking - atc_speed = other_train->GetCurrentSpeed(); - break; - } - } - - /* Decide what in direction to continue: reservation, straight or "first/only" direction. */ - /* Abort if there's no reservation even though the tile contains multiple tracks. */ - const TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); - - if (reserved != TRACKDIR_BIT_NONE) { - // There is a reservation to follow. - old_td = FindFirstTrackdir(reserved); - } - else if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { - // Tile has more than one track and we have no reservation. Bail out. - break; - } - else { - // There was no reservation but there is only one direction to follow, so follow it. - old_td = FindFirstTrackdir(ft.m_new_td_bits); - } - - num_tiles++; - } while (num_tiles < 20 && num_signals < 4 && ft.Follow(ft.m_new_tile, old_td)); - } - - /* Check that the ATC speed is sufficiently large. - Avoids assertion error in UpdateSpeed(). */ - current_max_speed = std::max(25, std::min(current_max_speed, atc_speed)); + if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption && this->signal_speed_restriction != 0) { + return std::max(25, this->signal_speed_restriction); } - return current_max_speed; + return UINT32_MAX; } /** @@ -1035,7 +1007,7 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); - max_speed = GetAtcMaxSpeed(max_speed); + max_speed = std::min(max_speed, GetAtcMaxSpeed()); if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); @@ -1404,6 +1376,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const v->vehstatus = VS_HIDDEN | VS_DEFPAL; v->reverse_distance = 0; v->speed_restriction = 0; + v->signal_speed_restriction = 0; v->SetWagon(); @@ -4520,6 +4493,7 @@ static void TrainEnterStation(Train *v, StationID station) v->current_order.MakeWaiting(); v->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); v->cur_speed = 0; + v->signal_speed_restriction = 0; return; } @@ -5576,7 +5550,29 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } if (update_signals_crossing) { + if (v->IsFrontEngine()) { + if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { + const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); + const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); + 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 (_date - found_speed_restriction->second.time_stamp < 6) { + v->signal_speed_restriction = std::max(25, found_speed_restriction->second.train_speed); + } else { + _signal_speeds.erase(speed_key); + v->signal_speed_restriction = 0; + } + } + } + switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir, true)) { case CHANGED_NORMAL_TO_PBS_BLOCK: /* We are entering a block with PBS signals right now, but @@ -5614,17 +5610,31 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) TrainMovedChangeSignal(v, gp.old_tile, ReverseDiagDir(enterdir), false); if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile); - if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile) && IsRestrictedSignal(gp.old_tile)) { + if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); + if (HasSignalOnTrack(gp.old_tile, track)) { - 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); + 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()->GetDisplaySpeed(), + speed_value.time_stamp = _date + }; + _signal_speeds[speed_key] = speed_value; + + if (IsRestrictedSignal(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); + } } } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 995a6e0410..cd2d212f8d 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2417,6 +2417,7 @@ void VehicleEnterDepot(Vehicle *v) ClrBit(t->flags, VRF_TOGGLE_REVERSE); t->ConsistChanged(CCF_ARRANGE); t->reverse_distance = 0; + t->signal_speed_restriction = 0; t->lookahead.reset(); if (!(t->vehstatus & VS_CRASHED)) { t->crash_anim_pos = 0; From 86cfefba082c1020d26706a24df4ddd227ffb7bb Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 01:16:17 +0200 Subject: [PATCH 06/25] Fix signed unsigned overflow --- src/train_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index c71ce6916c..5c4ebc8abd 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -994,7 +994,7 @@ int Train::GetAtcMaxSpeed() const return std::max(25, this->signal_speed_restriction); } - return UINT32_MAX; + return INT32_MAX; } /** From 669770f209074e0af61bdf8b84eba7ed06531b17 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Sun, 20 Jun 2021 04:02:23 +0200 Subject: [PATCH 07/25] Fix a few issues and reset everything on start of new game --- src/date.cpp | 5 +++- src/misc.cpp | 4 ++- src/train_cmd.cpp | 68 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/date.cpp b/src/date.cpp index 05cf97656f..40d35ddba6 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -39,6 +39,8 @@ YearMonthDay _game_load_cur_date_ymd; DateFract _game_load_date_fract; uint8 _game_load_tick_skip_counter; +extern void ClearOutOfDateSignalSpeedRestrictions(); + /** * Set the date. * @param date New date @@ -280,7 +282,8 @@ static void OnNewDay() if (!_settings_time.time_in_minutes || _settings_client.gui.date_with_time > 0) { SetWindowWidgetDirty(WC_STATUS_BAR, 0, WID_S_LEFT); } - EnginesDailyLoop(); + EnginesDailyLoop(); + ClearOutOfDateSignalSpeedRestrictions(); /* Refresh after possible snowline change */ SetWindowClassesDirty(WC_TOWN_VIEW); diff --git a/src/misc.cpp b/src/misc.cpp index b72d98ef9f..7741645fcd 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -43,6 +43,7 @@ extern TileIndex _cur_tileloop_tile; +extern void ClearAllSignalSpeedRestrictions(); extern void MakeNewgameSettingsLive(); void InitializeSound(); @@ -116,7 +117,8 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin RebuildViewportKdtree(); FreeSignalPrograms(); - FreeSignalDependencies(); + FreeSignalDependencies(); + ClearAllSignalSpeedRestrictions(); ClearZoningCaches(); IntialiseOrderDestinationRefcountMap(); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 5c4ebc8abd..1c982e5c42 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -90,6 +90,12 @@ struct SignalSpeedKey } }; +struct SignalSpeedValue +{ + uint16 train_speed; + DateTicksScaled time_stamp; +}; + struct SignalSpeedKeyHashFunc { std::size_t operator() (const SignalSpeedKey &key) const @@ -102,12 +108,6 @@ struct SignalSpeedKeyHashFunc } }; -struct SignalSpeedValue -{ - uint16 train_speed; - Date time_stamp; -}; - static std::unordered_map _signal_speeds(1 << 16); static void TryLongReserveChooseTrainTrackFromReservationEnd(Train *v, bool no_reserve_vehicle_tile = false); @@ -126,6 +126,46 @@ static void TrainEnterStation(Train *v, StationID station); static void UnreserveBridgeTunnelTile(TileIndex tile); static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile); +/** Return the scaled date ticks by which the speed restriction + * at the current position of the train is going to be invalid */ +static DateTicksScaled GetSpeedRestrictionTimeout(const Train *t) +{ + const int64 look_ahead_distance = 16; // In tiles + const int64 velocity = std::max(25, t->cur_speed); + + // This is a guess. I cannot figure out how the game actually calculates ticks_per_tile. + // If anybody has the correct value here, let me know. + const int64 ticks_per_tile = 2232 / velocity; + + const int64 ticks = ticks_per_tile * look_ahead_distance; + + return _scaled_date_ticks + ticks; +} + +/** Checks if the timeout of the specified signal speed restriction value has passed */ +static bool IsOutOfDate(const SignalSpeedValue& value) +{ + return _scaled_date_ticks > value.time_stamp; +} + +/** Removes all speed restrictions from all signals */ +void ClearAllSignalSpeedRestrictions() +{ + _signal_speeds.clear(); +} + +/** 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(); ) { + if (IsOutOfDate(key_value_pair->second)) { + key_value_pair = _signal_speeds.erase(key_value_pair); + } else { + ++key_value_pair; + } + } +} + inline void ClearLookAheadIfInvalid(Train *v) { if (v->lookahead != nullptr && !ValidateLookAhead(v)) v->lookahead.reset(); @@ -988,10 +1028,10 @@ static void AdvanceLookAheadPosition(Train *v) /** * Calculates the maximum speed based on any train in front of this train. */ -int Train::GetAtcMaxSpeed() const +int32 Train::GetAtcMaxSpeed() const { if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption && this->signal_speed_restriction != 0) { - return std::max(25, this->signal_speed_restriction); + return std::max(25, this->signal_speed_restriction); } return INT32_MAX; @@ -5564,12 +5604,14 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const auto found_speed_restriction = _signal_speeds.find(speed_key); if (found_speed_restriction != _signal_speeds.end()) { - if (_date - found_speed_restriction->second.time_stamp < 6) { - v->signal_speed_restriction = std::max(25, found_speed_restriction->second.train_speed); - } else { + if (IsOutOfDate(found_speed_restriction->second)) { _signal_speeds.erase(speed_key); 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; } } @@ -5622,8 +5664,8 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) speed_key.last_passing_train_dir = v->GetVehicleTrackdir() }; SignalSpeedValue speed_value = { - speed_value.train_speed = v->First()->GetDisplaySpeed(), - speed_value.time_stamp = _date + speed_value.train_speed = v->First()->cur_speed, + speed_value.time_stamp = GetSpeedRestrictionTimeout(v->First()) }; _signal_speeds[speed_key] = speed_value; From 837e82f60c1ff533b4491db2ea7aff3e0daf511c Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 01:22:50 +0200 Subject: [PATCH 08/25] Add German translation --- src/lang/german.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lang/german.txt b/src/lang/german.txt index f1724dd482..a7b9f7f878 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1737,6 +1737,10 @@ STR_CONFIG_SETTING_NOSERVICE :Wartung deaktiv STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Schicke Fahrzeuge nicht zur Wartung, wenn Pannen ausgeschaltet sind STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Berücksichtige Waggonhöchstgeschwindigkeit: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Begrenze die Höchstgeschwindigkeit eines Zuges durch die jeweiligen Höchstgeschwindigkeiten der mitgeführten Waggons +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Zuggeschwindigkeitsanpassung aktivieren: {STRING2} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :Wenn aktiviert, passen schnellere Züge hinter langsameren Zügen ihre Geschwindigkeit an. +STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Straßenfahrzeuge werden in Kurven langsamer: {STRING2} +STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :Wenn aktiviert, verlangsamen Straßenfahrzeuge in Kurven. (Nur im Beschleunigungsmodell „Realistisch“) STR_CONFIG_SETTING_DISABLE_ELRAILS :Deaktiviere elektrifizierte Strecken: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Erlaube Elektrolokomotiven das Fahren auf nicht elektrifizierten Gleisen From 2c9619ba108ea7b5babf81ac9549d4bd9f7b70e7 Mon Sep 17 00:00:00 2001 From: Andreas Schmitt Date: Mon, 21 Jun 2021 07:52:26 +0200 Subject: [PATCH 09/25] Fix string parameter --- src/lang/german.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/german.txt b/src/lang/german.txt index a7b9f7f878..7c1ba02162 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1737,9 +1737,9 @@ STR_CONFIG_SETTING_NOSERVICE :Wartung deaktiv STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Schicke Fahrzeuge nicht zur Wartung, wenn Pannen ausgeschaltet sind STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Berücksichtige Waggonhöchstgeschwindigkeit: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Begrenze die Höchstgeschwindigkeit eines Zuges durch die jeweiligen Höchstgeschwindigkeiten der mitgeführten Waggons -STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Zuggeschwindigkeitsanpassung aktivieren: {STRING2} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Zuggeschwindigkeitsanpassung aktivieren: {STRING} STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :Wenn aktiviert, passen schnellere Züge hinter langsameren Zügen ihre Geschwindigkeit an. -STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Straßenfahrzeuge werden in Kurven langsamer: {STRING2} +STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Straßenfahrzeuge werden in Kurven langsamer: {STRING} STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :Wenn aktiviert, verlangsamen Straßenfahrzeuge in Kurven. (Nur im Beschleunigungsmodell „Realistisch“) STR_CONFIG_SETTING_DISABLE_ELRAILS :Deaktiviere elektrifizierte Strecken: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Erlaube Elektrolokomotiven das Fahren auf nicht elektrifizierten Gleisen From 28e39c90451437396fd44472487452fd57ade007 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:09:24 +0100 Subject: [PATCH 10/25] Fix trailing whitespace --- src/date.cpp | 2 +- src/misc.cpp | 2 +- src/train_cmd.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/date.cpp b/src/date.cpp index 40d35ddba6..5aa378b976 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -282,7 +282,7 @@ static void OnNewDay() if (!_settings_time.time_in_minutes || _settings_client.gui.date_with_time > 0) { SetWindowWidgetDirty(WC_STATUS_BAR, 0, WID_S_LEFT); } - EnginesDailyLoop(); + EnginesDailyLoop(); ClearOutOfDateSignalSpeedRestrictions(); /* Refresh after possible snowline change */ diff --git a/src/misc.cpp b/src/misc.cpp index 7741645fcd..809bc5f3b2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -117,7 +117,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin RebuildViewportKdtree(); FreeSignalPrograms(); - FreeSignalDependencies(); + FreeSignalDependencies(); ClearAllSignalSpeedRestrictions(); ClearZoningCaches(); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 1c982e5c42..3cdd3f1eb3 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -138,7 +138,7 @@ static DateTicksScaled GetSpeedRestrictionTimeout(const Train *t) const int64 ticks_per_tile = 2232 / velocity; const int64 ticks = ticks_per_tile * look_ahead_distance; - + return _scaled_date_ticks + ticks; } @@ -5592,7 +5592,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (update_signals_crossing) { if (v->IsFrontEngine()) { - if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { + if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); @@ -5614,7 +5614,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->signal_speed_restriction = 0; } } - + switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir, true)) { case CHANGED_NORMAL_TO_PBS_BLOCK: /* We are entering a block with PBS signals right now, but From 1819a4218beb0b47af7dbff13162d0493b964168 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:18:38 +0100 Subject: [PATCH 11/25] Clear signal speed restriction at game shutdown --- src/misc.cpp | 1 + src/openttd.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/misc.cpp b/src/misc.cpp index 809bc5f3b2..279df3f8cf 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -118,6 +118,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin FreeSignalPrograms(); FreeSignalDependencies(); + ClearAllSignalSpeedRestrictions(); ClearZoningCaches(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 9909c5e719..eceee5c07c 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -439,6 +439,9 @@ static void ShutdownGame() FreeSignalPrograms(); FreeSignalDependencies(); + extern void ClearAllSignalSpeedRestrictions(); + ClearAllSignalSpeedRestrictions(); + ClearZoningCaches(); ClearOrderDestinationRefcountMap(); From e15acd3af859bed7545f769e46b1a8a7fa3ac3d5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:19:16 +0100 Subject: [PATCH 12/25] Avoid train speed adaption overhead when setting not enabled --- src/train_cmd.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 3cdd3f1eb3..94faf2e5ef 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1030,7 +1030,7 @@ static void AdvanceLookAheadPosition(Train *v) */ int32 Train::GetAtcMaxSpeed() const { - if (!(this->vehstatus & VS_CRASHED) && _settings_game.vehicle.train_speed_adaption && this->signal_speed_restriction != 0) { + if (!(this->vehstatus & VS_CRASHED) && this->signal_speed_restriction != 0) { return std::max(25, this->signal_speed_restriction); } @@ -1047,7 +1047,7 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); - max_speed = std::min(max_speed, GetAtcMaxSpeed()); + if (_settings_game.vehicle.train_speed_adaption) max_speed = std::min(max_speed, GetAtcMaxSpeed()); if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); @@ -5592,7 +5592,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (update_signals_crossing) { if (v->IsFrontEngine()) { - if (IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { + if (_settings_game.vehicle.train_speed_adaption && IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); @@ -5658,16 +5658,18 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const Track track = TrackdirToTrack(rev_trackdir); if (HasSignalOnTrack(gp.old_tile, track)) { - 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; + if (_settings_game.vehicle.train_speed_adaption) { + 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; + } if (IsRestrictedSignal(gp.old_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); From 879a23811f532c921c7749d55522ecf74b835358 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:40:04 +0100 Subject: [PATCH 13/25] Clear state when setting changed --- src/settings.cpp | 9 +++++++++ src/table/settings.ini | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/settings.cpp b/src/settings.cpp index 1b42726e7d..64110c8523 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1541,6 +1541,15 @@ static bool PublicRoadsSettingChange(int32 p1) { return true; } +static bool TrainSpeedAdaptionChanged(int32 p1) { + extern void ClearAllSignalSpeedRestrictions(); + ClearAllSignalSpeedRestrictions(); + for (Train *t : Train::Iterate()) { + t->signal_speed_restriction = 0; + } + return true; +} + /** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */ static void ValidateSettings() { diff --git a/src/table/settings.ini b/src/table/settings.ini index 007fe47a88..85faa7459f 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -64,6 +64,7 @@ static bool ClimateThresholdModeChanged(int32 p1); static bool VelocityUnitsChanged(int32 p1); static bool ChangeTrackTypeSortMode(int32 p1); static bool PublicRoadsSettingChange(int32 p1); +static bool TrainSpeedAdaptionChanged(int32 p1); static bool UpdateClientName(int32 p1); static bool UpdateServerPassword(int32 p1); @@ -1687,6 +1688,7 @@ def = true str = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION strhelp = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT cat = SC_EXPERT +proc = TrainSpeedAdaptionChanged patxname = ""train_speed_adaption.vehicle.train_speed_adaption"" [SDT_BOOL] From 3bba9ef37add21be5a49eb2f92325c144edade2f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:47:18 +0100 Subject: [PATCH 14/25] Fix setting name --- src/lang/english.txt | 4 ++-- src/lang/german.txt | 4 ++-- src/settings.cpp | 2 +- src/settings_gui.cpp | 2 +- src/settings_type.h | 2 +- src/table/settings.ini | 15 +++++++-------- src/train_cmd.cpp | 6 +++--- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 01d86510c5..7f75fc5bdb 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1811,8 +1811,8 @@ STR_CONFIG_SETTING_NOSERVICE :Disable servici STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train -STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Enable train speed adaption: {STRING2} -STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :If enabled, faster trains behind slower trains adjust their speed. +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION :Enable train speed adaptation: {STRING2} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION_HELPTEXT :When enabled, faster trains adjust their speed to match slower trains in front. STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Road vehicles slow down in curves: {STRING2} STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :When enabled, road vehicles slow down in curves. (Only with realistic acceleration) STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} diff --git a/src/lang/german.txt b/src/lang/german.txt index 7c1ba02162..014fd75f1b 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1737,8 +1737,8 @@ STR_CONFIG_SETTING_NOSERVICE :Wartung deaktiv STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Schicke Fahrzeuge nicht zur Wartung, wenn Pannen ausgeschaltet sind STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Berücksichtige Waggonhöchstgeschwindigkeit: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Begrenze die Höchstgeschwindigkeit eines Zuges durch die jeweiligen Höchstgeschwindigkeiten der mitgeführten Waggons -STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION :Zuggeschwindigkeitsanpassung aktivieren: {STRING} -STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT :Wenn aktiviert, passen schnellere Züge hinter langsameren Zügen ihre Geschwindigkeit an. +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION :Zuggeschwindigkeitsanpassung aktivieren: {STRING} +STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION_HELPTEXT :Wenn aktiviert, passen schnellere Züge hinter langsameren Zügen ihre Geschwindigkeit an. STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES :Straßenfahrzeuge werden in Kurven langsamer: {STRING} STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT :Wenn aktiviert, verlangsamen Straßenfahrzeuge in Kurven. (Nur im Beschleunigungsmodell „Realistisch“) STR_CONFIG_SETTING_DISABLE_ELRAILS :Deaktiviere elektrifizierte Strecken: {STRING} diff --git a/src/settings.cpp b/src/settings.cpp index 64110c8523..8037788f3e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1541,7 +1541,7 @@ static bool PublicRoadsSettingChange(int32 p1) { return true; } -static bool TrainSpeedAdaptionChanged(int32 p1) { +static bool TrainSpeedAdaptationChanged(int32 p1) { extern void ClearAllSignalSpeedRestrictions(); ClearAllSignalSpeedRestrictions(); for (Train *t : Train::Iterate()) { diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 179a12e642..302ef2c806 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1923,7 +1923,7 @@ static SettingsContainer &GetSettingsTree() physics->Add(new SettingEntry("vehicle.train_braking_model")); physics->Add(new SettingEntry("vehicle.train_slope_steepness")); physics->Add(new SettingEntry("vehicle.wagon_speed_limits")); - physics->Add(new SettingEntry("vehicle.train_speed_adaption")); + physics->Add(new SettingEntry("vehicle.train_speed_adaptation")); physics->Add(new SettingEntry("vehicle.freight_trains")); physics->Add(new SettingEntry("vehicle.roadveh_acceleration_model")); physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness")); diff --git a/src/settings_type.h b/src/settings_type.h index 95fbe4b1f8..4e8dbb92d4 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -572,7 +572,7 @@ struct VehicleSettings { uint8 train_slope_steepness; ///< Steepness of hills for trains when using realistic acceleration uint8 roadveh_slope_steepness; ///< Steepness of hills for road vehicles when using realistic acceleration bool wagon_speed_limits; ///< enable wagon speed limits - bool train_speed_adaption; ///< Faster trains behind slower trains slow down + bool train_speed_adaptation; ///< Faster trains slow down when behind slower trains bool slow_road_vehicles_in_curves; ///< Road vehicles slow down in curves. bool disable_elrails; ///< when true, the elrails are disabled UnitID max_trains; ///< max trains in game per company diff --git a/src/table/settings.ini b/src/table/settings.ini index 85faa7459f..f9797b1e15 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -64,7 +64,7 @@ static bool ClimateThresholdModeChanged(int32 p1); static bool VelocityUnitsChanged(int32 p1); static bool ChangeTrackTypeSortMode(int32 p1); static bool PublicRoadsSettingChange(int32 p1); -static bool TrainSpeedAdaptionChanged(int32 p1); +static bool TrainSpeedAdaptationChanged(int32 p1); static bool UpdateClientName(int32 p1); static bool UpdateServerPassword(int32 p1); @@ -1676,20 +1676,19 @@ strhelp = STR_CONFIG_SETTING_SLOW_ROAD_VEHICLES_IN_CURVES_HELPTEXT cat = SC_BASIC patxname = ""slow_road_vehicles_in_curves.vehicle.slow_road_vehicles_in_curves"" -;; vehicle.train_speed_adaption [SDT_XREF] extver = SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP) -xref = ""vehicle.train_speed_adaption"" +xref = ""vehicle.train_speed_adaptation"" [SDT_BOOL] base = GameSettings -var = vehicle.train_speed_adaption +var = vehicle.train_speed_adaptation def = true -str = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION -strhelp = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTION_HELPTEXT +str = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION +strhelp = STR_CONFIG_SETTING_TRAIN_SPEED_ADAPTATION_HELPTEXT cat = SC_EXPERT -proc = TrainSpeedAdaptionChanged -patxname = ""train_speed_adaption.vehicle.train_speed_adaption"" +proc = TrainSpeedAdaptationChanged +patxname = ""train_speed_adaptation.vehicle.train_speed_adaptation"" [SDT_BOOL] base = GameSettings diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 94faf2e5ef..4976412f9d 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1047,7 +1047,7 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); - if (_settings_game.vehicle.train_speed_adaption) max_speed = std::min(max_speed, GetAtcMaxSpeed()); + if (_settings_game.vehicle.train_speed_adaptation) max_speed = std::min(max_speed, GetAtcMaxSpeed()); if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); @@ -5592,7 +5592,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (update_signals_crossing) { if (v->IsFrontEngine()) { - if (_settings_game.vehicle.train_speed_adaption && IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { + if (_settings_game.vehicle.train_speed_adaptation && IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); @@ -5658,7 +5658,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const Track track = TrackdirToTrack(rev_trackdir); if (HasSignalOnTrack(gp.old_tile, track)) { - if (_settings_game.vehicle.train_speed_adaption) { + if (_settings_game.vehicle.train_speed_adaptation) { SignalSpeedKey speed_key = { speed_key.signal_tile = gp.old_tile, speed_key.signal_track = track, From 84f973880b7ee9437cd1001ea7289455e75eec2a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 03:59:31 +0100 Subject: [PATCH 15/25] Add signal speed restriction to vehicle debug info --- src/table/newgrf_debug_data.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 779761f666..d27392adaa 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -162,8 +162,11 @@ class NIHVehicle : public NIHelper { seprintf(buffer, lastof(buffer), " T cache: veh weight: %u, user data: %u, curve speed: %u", t->tcache.cached_veh_weight, t->tcache.user_def_data, t->tcache.cached_max_curve_speed); print(buffer); - seprintf(buffer, lastof(buffer), " Wait counter: %u, rev distance: %u, TBSN: %u, speed restriction: %u", - t->wait_counter, t->reverse_distance, t->tunnel_bridge_signal_num, t->speed_restriction); + seprintf(buffer, lastof(buffer), " Wait counter: %u, rev distance: %u, TBSN: %u", + t->wait_counter, t->reverse_distance, t->tunnel_bridge_signal_num); + print(buffer); + seprintf(buffer, lastof(buffer), " Speed restriction: %u, signal speed restriction (ATC): %u", + t->speed_restriction, t->signal_speed_restriction); print(buffer); seprintf(buffer, lastof(buffer), " Railtype: %u, compatible_railtypes: 0x" OTTD_PRINTFHEX64, t->railtype, t->compatible_railtypes); From ee2d77ecab2105bb99194b5b318fe69bc91487ca Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 04:00:49 +0100 Subject: [PATCH 16/25] Move train speed adaptation structs to separate header file --- src/train_cmd.cpp | 35 ++---------------------- src/train_speed_adaptation.h | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 33 deletions(-) create mode 100644 src/train_speed_adaptation.h diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 4976412f9d..490f3e9f42 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -44,6 +44,7 @@ #include "scope.h" #include "core/checksum_func.hpp" #include "debug_settings.h" +#include "train_speed_adaptation.h" #include "table/strings.h" #include "table/train_cmd.h" @@ -76,39 +77,7 @@ enum ChooseTrainTrackFlags { }; DECLARE_ENUM_AS_BIT_SET(ChooseTrainTrackFlags) -struct SignalSpeedKey -{ - TileIndex signal_tile; - Track signal_track; - Trackdir last_passing_train_dir; - - bool operator==(const SignalSpeedKey& other) const - { - return signal_tile == other.signal_tile && - signal_track == other.signal_track && - last_passing_train_dir == other.last_passing_train_dir; - } -}; - -struct SignalSpeedValue -{ - uint16 train_speed; - DateTicksScaled time_stamp; -}; - -struct SignalSpeedKeyHashFunc -{ - std::size_t operator() (const SignalSpeedKey &key) const - { - 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); - - return (h1 ^ h2) ^ h3; - } -}; - -static std::unordered_map _signal_speeds(1 << 16); +std::unordered_map _signal_speeds(1 << 16); static void TryLongReserveChooseTrainTrackFromReservationEnd(Train *v, bool no_reserve_vehicle_tile = false); static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, ChooseTrainTrackFlags flags, bool *p_got_reservation, ChooseTrainTrackLookAheadState lookahead_state = {}); diff --git a/src/train_speed_adaptation.h b/src/train_speed_adaptation.h new file mode 100644 index 0000000000..4f4c3e20b2 --- /dev/null +++ b/src/train_speed_adaptation.h @@ -0,0 +1,53 @@ +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file train_speed_adaptation.h Train speed adaptation data structures. */ + +#ifndef TRAIN_SPEED_ADAPTATION_H +#define TRAIN_SPEED_ADAPTATION_H + +#include "date_type.h" +#include "track_type.h" +#include "tile_type.h" + +#include + +struct SignalSpeedKey +{ + TileIndex signal_tile; + Track signal_track; + Trackdir last_passing_train_dir; + + bool operator==(const SignalSpeedKey& other) const + { + return signal_tile == other.signal_tile && + signal_track == other.signal_track && + last_passing_train_dir == other.last_passing_train_dir; + } +}; + +struct SignalSpeedValue +{ + uint16 train_speed; + DateTicksScaled time_stamp; +}; + +struct SignalSpeedKeyHashFunc +{ + std::size_t operator() (const SignalSpeedKey &key) const + { + 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); + + return (h1 ^ h2) ^ h3; + } +}; + +extern std::unordered_map _signal_speeds; + +#endif /* TRAIN_SPEED_ADAPTATION_H */ From fb0403dcee0f626cdfae02a928a7b146a5a5e0fb Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 04:41:21 +0100 Subject: [PATCH 17/25] Add save/load support for train speed adaptation --- src/CMakeLists.txt | 1 + src/saveload/CMakeLists.txt | 1 + src/saveload/extended_ver_sl.cpp | 1 + src/saveload/extended_ver_sl.h | 1 + src/saveload/saveload.cpp | 2 ++ src/saveload/vehicle_sl.cpp | 1 + 6 files changed, 7 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 38ba2f104a..be29ccdd19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -479,6 +479,7 @@ add_files( train.h train_cmd.cpp train_gui.cpp + train_speed_adaptation.h transparency.h transparency_gui.cpp transparency_gui.h diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt index 0fb209b624..af8909fcde 100644 --- a/src/saveload/CMakeLists.txt +++ b/src/saveload/CMakeLists.txt @@ -48,6 +48,7 @@ add_files( tbtr_template_veh_sl.cpp town_sl.cpp tracerestrict_sl.cpp + train_speed_adaptation.cpp tunnel_sl.cpp vehicle_sl.cpp waypoint_sl.cpp diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index ec53a3fde9..4223b31974 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -151,6 +151,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_WATER_FLOODING, XSCF_NULL, 2, 2, "water_flooding", nullptr, nullptr, nullptr }, { 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_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 1cc9c89de1..b752241491 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -105,6 +105,7 @@ enum SlXvFeatureIndex { XSLFI_WATER_FLOODING, ///< Water flooding map bit XSLFI_MORE_HOUSES, ///< More house types XSLFI_CUSTOM_TOWN_ZONE, ///< Custom town zones + XSLFI_TRAIN_SPEED_ADAPTATION, ///< Train speed adaptation XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index ef2d58280e..8feaae1486 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -288,6 +288,7 @@ extern const ChunkHandler _template_replacement_chunk_handlers[]; extern const ChunkHandler _template_vehicle_chunk_handlers[]; extern const ChunkHandler _bridge_signal_chunk_handlers[]; extern const ChunkHandler _tunnel_chunk_handlers[]; +extern const ChunkHandler _train_speed_adaptation_chunk_handlers[]; extern const ChunkHandler _debug_chunk_handlers[]; /** Array of all chunks in a savegame, \c nullptr terminated. */ @@ -333,6 +334,7 @@ static const ChunkHandler * const _chunk_handlers[] = { _template_vehicle_chunk_handlers, _bridge_signal_chunk_handlers, _tunnel_chunk_handlers, + _train_speed_adaptation_chunk_handlers, _debug_chunk_handlers, nullptr, }; diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 7583249a7b..c9d348bbef 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -807,6 +807,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDNULL(11, SLV_2, SLV_144), // old reserved space SLE_CONDVAR_X(Train, reverse_distance, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REVERSE_AT_WAYPOINT)), SLE_CONDVAR_X(Train, speed_restriction, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPEED_RESTRICTION)), + SLE_CONDVAR_X(Train, signal_speed_restriction, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRAIN_SPEED_ADAPTATION)), SLE_CONDVAR_X(Train, critical_breakdown_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 2)), SLE_END() From c4a596b75664d2dfb91b198b8fb30f7941e463e5 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 09:30:09 +0100 Subject: [PATCH 18/25] Fix missing file from fb0403dc --- src/saveload/train_speed_adaptation.cpp | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/saveload/train_speed_adaptation.cpp diff --git a/src/saveload/train_speed_adaptation.cpp b/src/saveload/train_speed_adaptation.cpp new file mode 100644 index 0000000000..21dfa39441 --- /dev/null +++ b/src/saveload/train_speed_adaptation.cpp @@ -0,0 +1,51 @@ +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file train_speed_adaptation.cpp Code handling saving and loading of data for train speed adaptation */ + +#include "../stdafx.h" +#include "../train_speed_adaptation.h" +#include "saveload.h" + +using SignalSpeedType = std::pair; + +static const SaveLoad _train_speed_adaptation_map_desc[] = { + SLE_VAR(SignalSpeedType, first.signal_track, SLE_UINT8), + 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), + SLE_END() +}; + +static void Load_TSAS() +{ + int index; + SignalSpeedType data; + while ((index = SlIterateArray()) != -1) { + const_cast(data.first).signal_tile = index; + SlObject(&data, _train_speed_adaptation_map_desc); + _signal_speeds.insert(data); + } +} + +static void RealSave_TSAS(SignalSpeedType *data) +{ + SlObject(data, _train_speed_adaptation_map_desc); +} + +static void Save_TSAS() +{ + for (auto &it : _signal_speeds) { + SlSetArrayIndex(it.first.signal_tile); + SignalSpeedType *data = ⁢ + SlAutolength((AutolengthProc*) RealSave_TSAS, data); + } +} + +extern const ChunkHandler _train_speed_adaptation_chunk_handlers[] = { + { 'TSAS', Save_TSAS, Load_TSAS, nullptr, nullptr, CH_SPARSE_ARRAY | CH_LAST}, +}; From 93be7633012c569bf6d97c345c074b28502331b2 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 22:12:29 +0100 Subject: [PATCH 19/25] Update ticks per tile constant --- src/train_cmd.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 490f3e9f42..a06a6a1bd4 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -102,9 +102,8 @@ static DateTicksScaled GetSpeedRestrictionTimeout(const Train *t) const int64 look_ahead_distance = 16; // In tiles const int64 velocity = std::max(25, t->cur_speed); - // This is a guess. I cannot figure out how the game actually calculates ticks_per_tile. - // If anybody has the correct value here, let me know. - const int64 ticks_per_tile = 2232 / velocity; + // This assumes travel along the X or Y map axis, not diagonally. See GetAdvanceDistance, GetAdvanceSpeed. + const int64 ticks_per_tile = (192 * 16 * 4 / 3) / velocity; const int64 ticks = ticks_per_tile * look_ahead_distance; From 62075c88de4ffba8cb9d734d11309183da25899a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 22:22:28 +0100 Subject: [PATCH 20/25] Apply ATC speed restriction as advisory to prevent instant braking Remove redundant function --- src/train.h | 1 - src/train_cmd.cpp | 17 +++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/train.h b/src/train.h index b303523cc5..b5c34f1152 100644 --- a/src/train.h +++ b/src/train.h @@ -191,7 +191,6 @@ struct Train FINAL : public GroundVehicle { }; private: - int GetAtcMaxSpeed() const; MaxSpeedInfo GetCurrentMaxSpeedInfoInternal(bool update_state) const; public: diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index a06a6a1bd4..f674ab7350 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -993,18 +993,6 @@ static void AdvanceLookAheadPosition(Train *v) } } -/** - * Calculates the maximum speed based on any train in front of this train. - */ -int32 Train::GetAtcMaxSpeed() const -{ - if (!(this->vehstatus & VS_CRASHED) && this->signal_speed_restriction != 0) { - return std::max(25, this->signal_speed_restriction); - } - - return INT32_MAX; -} - /** * Calculates the maximum speed information of the vehicle under its current conditions. * @return Maximum speed information of the vehicle. @@ -1015,8 +1003,6 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con this->gcache.cached_max_track_speed : std::min(this->tcache.cached_max_curve_speed, this->gcache.cached_max_track_speed); - if (_settings_game.vehicle.train_speed_adaptation) max_speed = std::min(max_speed, GetAtcMaxSpeed()); - if (this->current_order.IsType(OT_LOADING_ADVANCE)) max_speed = std::min(max_speed, 15); int advisory_max_speed = max_speed; @@ -1080,6 +1066,9 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con if (this->speed_restriction != 0) { advisory_max_speed = std::min(advisory_max_speed, this->speed_restriction); } + if (this->signal_speed_restriction != 0 && _settings_game.vehicle.train_speed_adaptation) { + advisory_max_speed = std::min(advisory_max_speed, this->signal_speed_restriction); + } if (this->reverse_distance > 1) { advisory_max_speed = std::min(advisory_max_speed, ReversingDistanceTargetSpeed(this)); } From e16c29ef7d6a0b3017cc502bf868ac3c404c1c58 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 23:06:41 +0100 Subject: [PATCH 21/25] Use already found iterator for erasing from hash map --- src/train_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index f674ab7350..aee4d70391 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -5562,7 +5562,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (found_speed_restriction != _signal_speeds.end()) { if (IsOutOfDate(found_speed_restriction->second)) { - _signal_speeds.erase(speed_key); + _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); From 5fb3eb0bb9b7815b935abf6bcfd319a77bf54790 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 27 Jun 2021 23:07:32 +0100 Subject: [PATCH 22/25] Adjust signal speed restriction timeouts when date or day length changed --- src/settings.cpp | 5 +++++ src/train_cmd.cpp | 7 +++++++ src/vehicle.cpp | 3 +++ 3 files changed, 15 insertions(+) diff --git a/src/settings.cpp b/src/settings.cpp index 8037788f3e..a3d7d1b744 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1793,7 +1793,12 @@ static bool ImprovedBreakdownsSettingChanged(int32 p1) static bool DayLengthChanged(int32 p1) { + const DateTicksScaled old_scaled_date_ticks = _scaled_date_ticks; SetScaledTickVariables(); + + extern void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta); + AdjustAllSignalSpeedRestrictionTickValues(_scaled_date_ticks - old_scaled_date_ticks); + MarkWholeScreenDirty(); return true; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index aee4d70391..b5702dcd79 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -122,6 +122,13 @@ void ClearAllSignalSpeedRestrictions() _signal_speeds.clear(); } +void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta) +{ + for (auto &it : _signal_speeds) { + it.second.time_stamp += delta; + } +} + /** Removes all speed restrictions which have passed their timeout from all signals */ void ClearOutOfDateSignalSpeedRestrictions() { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index cd2d212f8d..67d9ac3681 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -4310,4 +4310,7 @@ void ShiftVehicleDates(int interval) for (Vehicle *v : Vehicle::Iterate()) { v->date_of_last_service += interval; } + + extern void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta); + AdjustAllSignalSpeedRestrictionTickValues(interval * DAY_TICKS * _settings_game.economy.day_length_factor); } From 11e49ef99ec12e9b56825a61842aa8a653132d0a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 28 Jun 2021 00:04:12 +0100 Subject: [PATCH 23/25] Only apply signal speed restrictions from the front direction --- src/train_cmd.cpp | 56 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index b5702dcd79..8bca24a8de 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -5559,23 +5559,25 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (_settings_game.vehicle.train_speed_adaptation && IsTileType(gp.old_tile, MP_RAILWAY) && HasSignals(gp.old_tile)) { const TrackdirBits rev_tracks = TrackBitsToTrackdirBits(GetTrackBits(gp.old_tile)) & DiagdirReachesTrackdirs(ReverseDiagDir(enterdir)); const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); - 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 (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; + 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 = std::max(25, found_speed_restriction->second.train_speed); + v->signal_speed_restriction = 0; } - } else { - v->signal_speed_restriction = 0; } } @@ -5621,20 +5623,20 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const Trackdir rev_trackdir = FindFirstTrackdir(rev_tracks); const Track track = TrackdirToTrack(rev_trackdir); - if (HasSignalOnTrack(gp.old_tile, track)) { - if (_settings_game.vehicle.train_speed_adaptation) { - 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; - } + 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; + } + if (HasSignalOnTrack(gp.old_tile, track)) { if (IsRestrictedSignal(gp.old_tile)) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.old_tile, track); if (prog && prog->actions_used_flags & TRPAUF_SLOT_RELEASE_BACK) { From fb4e10626efb546f64fec170993dd4c56aef2458 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 3 Jul 2021 22:50:43 +0100 Subject: [PATCH 24/25] Make look ahead distance vaiable with speed, within a reasonable range --- src/train_cmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 8bca24a8de..a208e32851 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -99,8 +99,8 @@ static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile); * at the current position of the train is going to be invalid */ static DateTicksScaled GetSpeedRestrictionTimeout(const Train *t) { - const int64 look_ahead_distance = 16; // In tiles const int64 velocity = std::max(25, t->cur_speed); + const int64 look_ahead_distance = Clamp(t->cur_speed / 8, 6, 16); // In tiles, varying between 6 and 16 depending on current speed // This assumes travel along the X or Y map axis, not diagonally. See GetAdvanceDistance, GetAdvanceSpeed. const int64 ticks_per_tile = (192 * 16 * 4 / 3) / velocity; From 9edc13b8897b257207d334aa198cacedf1235ac7 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 3 Jul 2021 22:56:17 +0100 Subject: [PATCH 25/25] Make sure setting set correctly on loading existing saves --- src/saveload/afterload.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 89cc76bed3..2fe10c3ca0 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -938,6 +938,10 @@ bool AfterLoadGame() _settings_game.vehicle.train_braking_model = TBM_ORIGINAL; } + if (SlXvIsFeatureMissing(XSLFI_TRAIN_SPEED_ADAPTATION)) { + _settings_game.vehicle.train_speed_adaptation = false; + } + AfterLoadEngines(); /* Update all vehicles */