Realistic braking: Cache train overall z position

Refresh cache at a variable rate depending on train length and
weight distribution
This commit is contained in:
Jonathan G Rennison
2022-06-03 00:41:41 +01:00
parent c238bd5012
commit 99ee4b13ce
9 changed files with 57 additions and 16 deletions

View File

@@ -931,6 +931,8 @@ void TryCreateLookAheadForTrainInTunnelBridge(Train *t)
t->lookahead->reservation_end_position = GetTileMarginInFrontOfTrain(t); t->lookahead->reservation_end_position = GetTileMarginInFrontOfTrain(t);
t->lookahead->flags = 0; t->lookahead->flags = 0;
t->lookahead->speed_restriction = t->speed_restriction; 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 (IsTunnel(t->tile) && Tunnel::GetByTile(t->tile)->is_chunnel) SetBit(t->lookahead->flags, TRLF_CHUNNEL);
if (IsTunnelBridgeSignalSimulationEntrance(t->tile)) { if (IsTunnelBridgeSignalSimulationEntrance(t->tile)) {
@@ -1002,6 +1004,8 @@ void FillTrainReservationLookAhead(Train *v)
v->lookahead->tunnel_bridge_reserved_tiles = 0; v->lookahead->tunnel_bridge_reserved_tiles = 0;
v->lookahead->flags = 0; v->lookahead->flags = 0;
v->lookahead->speed_restriction = v->speed_restriction; v->lookahead->speed_restriction = v->speed_restriction;
v->lookahead->cached_zpos = v->CalculateOverallZPos();
v->lookahead->zpos_refresh_remaining = v->GetZPosCacheUpdateInterval();
FillLookAheadCurveDataFromTrainPosition(v); FillLookAheadCurveDataFromTrainPosition(v);
tile = v->tile; tile = v->tile;
trackdir = v->GetVehicleTrackdir(); trackdir = v->GetVehicleTrackdir();

View File

@@ -90,6 +90,8 @@ struct TrainReservationLookAhead {
uint16 speed_restriction; uint16 speed_restriction;
std::deque<TrainReservationLookAheadItem> items; std::deque<TrainReservationLookAheadItem> items;
std::deque<TrainReservationLookAheadCurve> curves; std::deque<TrainReservationLookAheadCurve> 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 int32 RealEndPosition() const
{ {

View File

@@ -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)) { if (SlXvIsFeatureMissing(XSLFI_INFLATION_FIXED_DATES)) {
_settings_game.economy.inflation_fixed_dates = !IsSavegameVersionBefore(SLV_GS_INDUSTRY_CONTROL); _settings_game.economy.inflation_fixed_dates = !IsSavegameVersionBefore(SLV_GS_INDUSTRY_CONTROL);
} }

View File

@@ -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_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_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_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_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_WATER_FLOODING, XSCF_NULL, 2, 2, "water_flooding", nullptr, nullptr, nullptr },
{ XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr }, { XSLFI_MORE_HOUSES, XSCF_NULL, 2, 2, "more_houses", nullptr, nullptr, nullptr },

View File

@@ -1392,6 +1392,8 @@ const SaveLoadTable GetVehicleLookAheadDescription()
SLE_VAR(TrainReservationLookAhead, flags, SLE_UINT16), SLE_VAR(TrainReservationLookAhead, flags, SLE_UINT16),
SLE_VAR(TrainReservationLookAhead, speed_restriction, 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, 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; return _vehicle_look_ahead_desc;

View File

@@ -211,7 +211,7 @@ class NIHVehicle : public NIHelper {
if (t->lookahead != nullptr) { if (t->lookahead != nullptr) {
output.print(" Look ahead:"); output.print(" Look ahead:");
const TrainReservationLookAhead &l = *t->lookahead; 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) { auto print_braking_speed = [&](int position, int end_speed, int end_z) {
if (!t->UsingRealisticBraking()) return; if (!t->UsingRealisticBraking()) return;
@@ -229,6 +229,11 @@ class NIHVehicle : public NIHelper {
} }
output.print(buffer); 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", 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); 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)) { if (HasBit(l.flags, TRLF_DEPOT_END)) {

View File

@@ -212,6 +212,13 @@ public:
int GetCurrentMaxSpeed() const; int GetCurrentMaxSpeed() const;
uint8 GetZPosCacheUpdateInterval() const
{
return Clamp<uint16>(std::min<uint16>(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; } bool UsingRealisticBraking() const { return this->tcache.cached_tflags & TCF_RL_BRAKING; }
/** /**
@@ -494,7 +501,7 @@ struct TrainDecelerationStats {
int z_pos; int z_pos;
const Train *t; const Train *t;
TrainDecelerationStats(const Train *t); TrainDecelerationStats(const Train *t, int z_pos);
}; };
CommandCost CmdMoveRailVehicle(TileIndex, DoCommandFlag , uint32, uint32, const char *); CommandCost CmdMoveRailVehicle(TileIndex, DoCommandFlag , uint32, uint32, const char *);

View File

@@ -807,19 +807,11 @@ int PredictStationStoppingLocation(const Train *v, const Order *order, int stati
return stop + adjust; 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->deceleration_x2 = 2 * t->tcache.cached_deceleration;
this->uncapped_deceleration_x2 = 2 * t->tcache.cached_uncapped_decel; 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 = z_pos;
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->t = t; this->t = t;
} }
@@ -977,6 +969,7 @@ static void ApplyLookAheadItem(const Train *v, const TrainReservationLookAheadIt
static void AdvanceLookAheadPosition(Train *v) static void AdvanceLookAheadPosition(Train *v)
{ {
v->lookahead->current_position++; 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) { 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 */ /* 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->UsingRealisticBraking()) {
if (this->lookahead != nullptr) { 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)) { 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); 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 { } else {
@@ -1135,6 +1132,19 @@ int Train::GetCurrentMaxSpeed() const
return std::min(info.strict_max_speed, info.advisory_max_speed); 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. */ /** Update acceleration of the train from the cached power and weight. */
void Train::UpdateAcceleration() 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; 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; bool found_signal = false;
int signal_speed = 0; int signal_speed = 0;
@@ -5231,7 +5241,7 @@ inline void DecreaseReverseDistance(Train *v)
int ReversingDistanceTargetSpeed(const Train *v) int ReversingDistanceTargetSpeed(const Train *v)
{ {
if (v->UsingRealisticBraking()) { 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); return GetRealisticBrakingSpeedForDistance(stats, v->reverse_distance - 1, 0, 0);
} }
int target_speed; int target_speed;

View File

@@ -3418,6 +3418,7 @@ void Vehicle::LeaveStation()
} }
SetBit(Train::From(this)->flags, VRF_LEAVING_STATION); 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)) { if (this->type == VEH_ROAD && !(this->vehstatus & VS_CRASHED)) {
/* Trigger road stop animation */ /* Trigger road stop animation */
@@ -3477,6 +3478,7 @@ void Vehicle::AdvanceLoadingInStation()
HideFillingPercent(&this->fill_percent_te_id); HideFillingPercent(&this->fill_percent_te_id);
this->current_order.MakeLoadingAdvance(this->last_station_visited); this->current_order.MakeLoadingAdvance(this->last_station_visited);
this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); 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(); this->MarkDirty();
} }