diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 89c641bf62..fd61e51b51 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -102,16 +102,25 @@ void GroundVehicle::CargoChanged() { assert(this->First() == this); uint32 weight = 0; + uint64 mass_offset = 0; + uint32 veh_offset = 0; for (T *u = T::From(this); u != nullptr; u = u->Next()) { uint32 current_weight = u->GetWeight(); - if (Type == VEH_TRAIN) Train::From(u)->tcache.cached_veh_weight = current_weight; + if (Type == VEH_TRAIN) { + Train::From(u)->tcache.cached_veh_weight = current_weight; + mass_offset += current_weight * (veh_offset + (Train::From(u)->gcache.cached_veh_length / 2)); + veh_offset += Train::From(u)->gcache.cached_veh_length; + } weight += current_weight; /* Slope steepness is in percent, result in N. */ u->gcache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100; u->InvalidateImageCache(); } ClrBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST); + if (Type == VEH_TRAIN) { + Train::From(this)->tcache.cached_centre_mass = (weight != 0) ? (mass_offset / weight) : (this->gcache.cached_total_length / 2); + } /* Store consist weight in cache. */ this->gcache.cached_weight = std::max(1u, weight); diff --git a/src/openttd.cpp b/src/openttd.cpp index 67b845ea7f..9408421c61 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1646,10 +1646,11 @@ void CheckCaches(bool force_check, std::function log) print_gv_cache_diff("train", gro_cache[length], Train::From(u)->gcache); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { - CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c", + CCLOGV("train cache mismatch: %c%c%c%c%c%c%c%c%c", tra_cache[length].cached_override != Train::From(u)->tcache.cached_override ? 'o' : '-', tra_cache[length].cached_tilt != Train::From(u)->tcache.cached_tilt ? 't' : '-', tra_cache[length].cached_num_engines != Train::From(u)->tcache.cached_num_engines ? 'e' : '-', + tra_cache[length].cached_centre_mass != Train::From(u)->tcache.cached_centre_mass ? 'm' : '-', tra_cache[length].cached_veh_weight != Train::From(u)->tcache.cached_veh_weight ? 'w' : '-', tra_cache[length].cached_uncapped_decel != Train::From(u)->tcache.cached_uncapped_decel ? 'D' : '-', tra_cache[length].cached_deceleration != Train::From(u)->tcache.cached_deceleration ? 'd' : '-', diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 94928a54fa..e3574e0c46 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -1148,6 +1148,7 @@ struct train_venc { GroundVehicleCache gvcache; bool cached_tilt; uint8 cached_num_engines; + uint16 cached_centre_mass; uint16 cached_veh_weight; uint16 cached_uncapped_decel; uint8 cached_deceleration; @@ -1215,6 +1216,7 @@ void Save_VENC() write_gv_cache(t->gcache); SlWriteByte(t->tcache.cached_tilt); SlWriteByte(t->tcache.cached_num_engines); + SlWriteByte(t->tcache.cached_centre_mass); SlWriteUint16(t->tcache.cached_veh_weight); SlWriteUint16(t->tcache.cached_uncapped_decel); SlWriteByte(t->tcache.cached_deceleration); @@ -1275,6 +1277,7 @@ void Load_VENC() read_gv_cache(venc.gvcache); venc.cached_tilt = SlReadByte(); venc.cached_num_engines = SlReadByte(); + venc.cached_centre_mass = SlReadUint16(); venc.cached_veh_weight = SlReadUint16(); venc.cached_uncapped_decel = SlReadUint16(); venc.cached_deceleration = SlReadByte(); @@ -1361,6 +1364,7 @@ void SlProcessVENC() check_gv_cache(t->gcache, venc.gvcache, t); CheckVehicleVENCProp(t->tcache.cached_tilt, venc.cached_tilt, t, "cached_tilt"); CheckVehicleVENCProp(t->tcache.cached_num_engines, venc.cached_num_engines, t, "cached_num_engines"); + CheckVehicleVENCProp(t->tcache.cached_centre_mass, venc.cached_centre_mass, t, "cached_centre_mass"); CheckVehicleVENCProp(t->tcache.cached_veh_weight, venc.cached_veh_weight, t, "cached_veh_weight"); CheckVehicleVENCProp(t->tcache.cached_uncapped_decel, venc.cached_uncapped_decel, t, "cached_uncapped_decel"); CheckVehicleVENCProp(t->tcache.cached_deceleration, venc.cached_deceleration, t, "cached_deceleration"); diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 3ea901f7f8..0ea83db588 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -151,8 +151,8 @@ class NIHVehicle : public NIHelper { } if (v->type == VEH_TRAIN) { const Train *t = Train::From(v); - seprintf(buffer, lastof(buffer), " T cache: tilt: %u, engines: %u, decel: %u, uncapped decel: %u", - t->tcache.cached_tilt, t->tcache.cached_num_engines, t->tcache.cached_deceleration, t->tcache.cached_uncapped_decel); + seprintf(buffer, lastof(buffer), " T cache: tilt: %u, engines: %u, decel: %u, uncapped decel: %u, centre mass: %u", + t->tcache.cached_tilt, t->tcache.cached_num_engines, t->tcache.cached_deceleration, t->tcache.cached_uncapped_decel, t->tcache.cached_centre_mass); print(buffer); 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); diff --git a/src/train.h b/src/train.h index 3d09866e31..85be4c7287 100644 --- a/src/train.h +++ b/src/train.h @@ -99,6 +99,7 @@ struct TrainCache { /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ bool cached_tilt; ///< train can tilt; feature provides a bonus in curves uint8 cached_num_engines; ///< total number of engines, including rear ends of multiheaded engines + uint16 cached_centre_mass; ///< Cached position of the centre of mass, from the front uint16 cached_veh_weight; ///< Cached individual vehicle weight uint16 cached_uncapped_decel; ///< Uncapped cached deceleration for realistic braking lookahead purposes uint8 cached_deceleration; ///< Cached deceleration for realistic braking lookahead purposes diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 9be6b86606..187661190b 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -364,6 +364,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) u->gcache.cached_air_drag = 0; u->gcache.cached_total_length = 0; u->tcache.cached_num_engines = 0; + u->tcache.cached_centre_mass = 0; u->tcache.cached_deceleration = 0; u->tcache.cached_uncapped_decel = 0; u->tcache.cached_tilt = false; @@ -847,8 +848,11 @@ static void LimitSpeedFromLookAhead(int &max_speed, const TrainDecelerationStats if (distance + current_position > position) { /* Speed is too fast, we would overshoot */ if (z_delta < 0 && (position - current_position) < stats.t->gcache.cached_total_length) { - /* Reduce z delta near target to compensate for target z not taking into account that z varies across the whole train */ - z_delta = (z_delta * (position - current_position)) / stats.t->gcache.cached_total_length; + int effective_length = std::min(stats.t->gcache.cached_total_length, stats.t->tcache.cached_centre_mass * 2); + if ((position - current_position) < effective_length) { + /* Reduce z delta near target to compensate for target z not taking into account that z varies across the whole train */ + z_delta = (z_delta * (position - current_position)) / effective_length; + } } max_speed = std::min(max_speed, GetRealisticBrakingSpeedForDistance(stats, position - current_position, end_speed, z_delta)); }