diff --git a/src/pbs.cpp b/src/pbs.cpp index dee990a654..440dd1847e 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -931,6 +931,8 @@ void TryCreateLookAheadForTrainInTunnelBridge(Train *t) t->lookahead->reservation_end_position = GetTileMarginInFrontOfTrain(t); t->lookahead->flags = 0; t->lookahead->speed_restriction = t->speed_restriction; + t->lookahead->cached_zpos = t->CalculateOverallZPos(); + t->lookahead->zpos_refresh_remaining = t->GetZPosCacheUpdateInterval(); if (IsTunnel(t->tile) && Tunnel::GetByTile(t->tile)->is_chunnel) SetBit(t->lookahead->flags, TRLF_CHUNNEL); if (IsTunnelBridgeSignalSimulationEntrance(t->tile)) { @@ -1002,6 +1004,8 @@ void FillTrainReservationLookAhead(Train *v) v->lookahead->tunnel_bridge_reserved_tiles = 0; v->lookahead->flags = 0; v->lookahead->speed_restriction = v->speed_restriction; + v->lookahead->cached_zpos = v->CalculateOverallZPos(); + v->lookahead->zpos_refresh_remaining = v->GetZPosCacheUpdateInterval(); FillLookAheadCurveDataFromTrainPosition(v); tile = v->tile; trackdir = v->GetVehicleTrackdir(); diff --git a/src/pbs.h b/src/pbs.h index 398ecbd37d..283a99587e 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -90,6 +90,8 @@ struct TrainReservationLookAhead { uint16 speed_restriction; std::deque items; std::deque curves; + int32 cached_zpos = 0; ///< Cached z position as used in TrainDecelerationStats + uint8 zpos_refresh_remaining = 0; ///< Remaining position updates before next refresh of cached_zpos int32 RealEndPosition() const { diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 542040cb34..ba5e1dfb25 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3956,6 +3956,15 @@ bool AfterLoadGame() } } + if (!SlXvIsFeaturePresent(XSLFI_REALISTIC_TRAIN_BRAKING, 6) && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { + for (Train *t : Train::Iterate()) { + if (t->lookahead != nullptr) { + t->lookahead->cached_zpos = t->CalculateOverallZPos(); + t->lookahead->zpos_refresh_remaining = t->GetZPosCacheUpdateInterval(); + } + } + } + if (SlXvIsFeatureMissing(XSLFI_INFLATION_FIXED_DATES)) { _settings_game.economy.inflation_fixed_dates = !IsSavegameVersionBefore(SLV_GS_INDUSTRY_CONTROL); } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 868785e426..61d03787e6 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -151,7 +151,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_ANIMATED_TILE_EXTRA, XSCF_NULL, 1, 1, "animated_tile_extra", nullptr, nullptr, nullptr }, { XSLFI_NEWGRF_INFO_EXTRA, XSCF_NULL, 1, 1, "newgrf_info_extra", nullptr, nullptr, nullptr }, { XSLFI_INDUSTRY_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 1, 1, "industry_cargo_adj", nullptr, nullptr, nullptr }, - { XSLFI_REALISTIC_TRAIN_BRAKING,XSCF_NULL, 5, 5, "realistic_train_braking", nullptr, nullptr, "VLKA" }, + { XSLFI_REALISTIC_TRAIN_BRAKING,XSCF_NULL, 6, 6, "realistic_train_braking", nullptr, nullptr, "VLKA" }, { XSLFI_INFLATION_FIXED_DATES, XSCF_IGNORABLE_ALL, 1, 1, "inflation_fixed_dates", nullptr, nullptr, nullptr }, { XSLFI_WATER_FLOODING, XSCF_NULL, 2, 2, "water_flooding", nullptr, nullptr, nullptr }, { XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr }, diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 4c99988710..6f70e39de7 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -1392,6 +1392,8 @@ const SaveLoadTable GetVehicleLookAheadDescription() SLE_VAR(TrainReservationLookAhead, flags, SLE_UINT16), SLE_VAR(TrainReservationLookAhead, speed_restriction, SLE_UINT16), SLE_CONDVAR_X(TrainReservationLookAhead, next_extend_position, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 5)), + SLE_CONDVAR_X(TrainReservationLookAhead, cached_zpos, SLE_INT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 6)), + SLE_CONDVAR_X(TrainReservationLookAhead, zpos_refresh_remaining, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REALISTIC_TRAIN_BRAKING, 6)), }; return _vehicle_look_ahead_desc; diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 159f413841..6c3ff1245e 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -211,7 +211,7 @@ class NIHVehicle : public NIHelper { if (t->lookahead != nullptr) { output.print(" Look ahead:"); const TrainReservationLookAhead &l = *t->lookahead; - TrainDecelerationStats stats(t); + TrainDecelerationStats stats(t, l.cached_zpos); auto print_braking_speed = [&](int position, int end_speed, int end_z) { if (!t->UsingRealisticBraking()) return; @@ -229,6 +229,11 @@ class NIHVehicle : public NIHelper { } output.print(buffer); + const int overall_zpos = t->CalculateOverallZPos(); + seprintf(buffer, lastof(buffer), " Cached zpos: %u (actual: %u, delta: %d), positions to refresh: %u", + l.cached_zpos, overall_zpos, (l.cached_zpos - overall_zpos), l.zpos_refresh_remaining); + output.print(buffer); + b = buffer + seprintf(buffer, lastof(buffer), " Reservation ends at %X (%u x %u), trackdir: %02X, z: %d", l.reservation_end_tile, TileX(l.reservation_end_tile), TileY(l.reservation_end_tile), l.reservation_end_trackdir, l.reservation_end_z); if (HasBit(l.flags, TRLF_DEPOT_END)) { diff --git a/src/train.h b/src/train.h index 77d7935ced..dc3644118e 100644 --- a/src/train.h +++ b/src/train.h @@ -212,6 +212,13 @@ public: int GetCurrentMaxSpeed() const; + uint8 GetZPosCacheUpdateInterval() const + { + return Clamp(std::min(this->gcache.cached_total_length / 4, this->tcache.cached_centre_mass / 2), 2, 32); + } + + uint32 CalculateOverallZPos() const; + bool UsingRealisticBraking() const { return this->tcache.cached_tflags & TCF_RL_BRAKING; } /** @@ -494,7 +501,7 @@ struct TrainDecelerationStats { int z_pos; const Train *t; - TrainDecelerationStats(const Train *t); + TrainDecelerationStats(const Train *t, int z_pos); }; CommandCost CmdMoveRailVehicle(TileIndex, DoCommandFlag , uint32, uint32, const char *); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e85b261263..0722d14ca6 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -807,19 +807,11 @@ int PredictStationStoppingLocation(const Train *v, const Order *order, int stati return stop + adjust; } -TrainDecelerationStats::TrainDecelerationStats(const Train *t) +TrainDecelerationStats::TrainDecelerationStats(const Train *t, int z_pos) { this->deceleration_x2 = 2 * t->tcache.cached_deceleration; this->uncapped_deceleration_x2 = 2 * t->tcache.cached_uncapped_decel; - if (likely(HasBit(t->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST))) { - this->z_pos = t->z_pos; - } else { - int64 sum = 0; - for (const Train *u = t; u != nullptr; u = u->Next()) { - sum += ((int)u->z_pos * (int)u->tcache.cached_veh_weight); - } - this->z_pos = sum / t->gcache.cached_weight; - } + this->z_pos = z_pos; this->t = t; } @@ -977,6 +969,7 @@ static void ApplyLookAheadItem(const Train *v, const TrainReservationLookAheadIt static void AdvanceLookAheadPosition(Train *v) { v->lookahead->current_position++; + if (v->lookahead->zpos_refresh_remaining > 0) v->lookahead->zpos_refresh_remaining--; if (v->lookahead->current_position > v->lookahead->reservation_end_position + 8) { /* Beyond end of lookahead, delete it, it will be recreated later with a new reservation */ @@ -1102,7 +1095,11 @@ Train::MaxSpeedInfo Train::GetCurrentMaxSpeedInfoInternal(bool update_state) con if (this->UsingRealisticBraking()) { if (this->lookahead != nullptr) { - TrainDecelerationStats stats(this); + if (update_state && this->lookahead->zpos_refresh_remaining == 0) { + this->lookahead->cached_zpos = this->CalculateOverallZPos(); + this->lookahead->zpos_refresh_remaining = this->GetZPosCacheUpdateInterval(); + } + TrainDecelerationStats stats(this, this->lookahead->cached_zpos); if (HasBit(this->lookahead->flags, TRLF_DEPOT_END)) { LimitSpeedFromLookAhead(max_speed, stats, this->lookahead->current_position, this->lookahead->reservation_end_position - TILE_SIZE, 61, this->lookahead->reservation_end_z - stats.z_pos); } else { @@ -1135,6 +1132,19 @@ int Train::GetCurrentMaxSpeed() const return std::min(info.strict_max_speed, info.advisory_max_speed); } +uint32 Train::CalculateOverallZPos() const +{ + if (likely(HasBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST))) { + return this->z_pos; + } else { + int64 sum = 0; + for (const Train *u = this; u != nullptr; u = u->Next()) { + sum += ((int)u->z_pos * (int)u->tcache.cached_veh_weight); + } + return sum / this->gcache.cached_weight; + } +} + /** Update acceleration of the train from the cached power and weight. */ void Train::UpdateAcceleration() { @@ -3980,7 +3990,7 @@ static bool IsReservationLookAheadLongEnough(const Train *v, const ChooseTrainTr if (v->lookahead->reservation_end_position >= v->lookahead->current_position + v->reverse_distance - 1) return true; } - TrainDecelerationStats stats(v); + TrainDecelerationStats stats(v, v->lookahead->cached_zpos); bool found_signal = false; int signal_speed = 0; @@ -5231,7 +5241,7 @@ inline void DecreaseReverseDistance(Train *v) int ReversingDistanceTargetSpeed(const Train *v) { if (v->UsingRealisticBraking()) { - TrainDecelerationStats stats(v); + TrainDecelerationStats stats(v, v->lookahead != nullptr ? v->lookahead->cached_zpos : v->CalculateOverallZPos()); return GetRealisticBrakingSpeedForDistance(stats, v->reverse_distance - 1, 0, 0); } int target_speed; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index ca0f107793..b1ea521057 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3418,6 +3418,7 @@ void Vehicle::LeaveStation() } SetBit(Train::From(this)->flags, VRF_LEAVING_STATION); + if (Train::From(this)->lookahead != nullptr) Train::From(this)->lookahead->zpos_refresh_remaining = 0; } if (this->type == VEH_ROAD && !(this->vehstatus & VS_CRASHED)) { /* Trigger road stop animation */ @@ -3477,6 +3478,7 @@ void Vehicle::AdvanceLoadingInStation() HideFillingPercent(&this->fill_percent_te_id); this->current_order.MakeLoadingAdvance(this->last_station_visited); this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); + if (Train::From(this)->lookahead != nullptr) Train::From(this)->lookahead->zpos_refresh_remaining = 0; this->MarkDirty(); }