From f19829d02945bbd391b5dd4238bdcd682ac56121 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 1 Jul 2024 17:05:39 +0100 Subject: [PATCH] Fix #12831: Delay vehicle cache init to after map upgrades in load Split AfterLoadVehicles into two functions. Vehicle cache init and other functionality requiring an upgraded and valid map is now performed later in the load process. --- src/elrail.cpp | 14 ++++++++++---- src/elrail_func.h | 1 + src/order_base.h | 2 +- src/saveload/afterload.cpp | 25 +++++++++++++------------ src/saveload/saveload_internal.h | 3 ++- src/saveload/vehicle_sl.cpp | 10 +++++++--- src/vehicle_base.h | 2 +- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/elrail.cpp b/src/elrail.cpp index 334a50042d..a7912abb0f 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -598,7 +598,11 @@ void DrawRailCatenary(const TileInfo *ti) void SettingsDisableElrail(int32_t new_value) { bool disable = (new_value != 0); + UpdateDisableElrailSettingState(disable, true); +} +void UpdateDisableElrailSettingState(bool disable, bool update_vehicles) +{ /* pick appropriate railtype for elrail engines depending on setting */ const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC; @@ -626,10 +630,12 @@ void SettingsDisableElrail(int32_t new_value) } /* Fix the total power and acceleration for trains */ - for (Train *t : Train::Iterate()) { - /* power and acceleration is cached only for front engines */ - if (t->IsFrontEngine()) { - t->ConsistChanged(CCF_TRACK); + if (update_vehicles) { + for (Train *t : Train::Iterate()) { + /* power and acceleration is cached only for front engines */ + if (t->IsFrontEngine()) { + t->ConsistChanged(CCF_TRACK); + } } } diff --git a/src/elrail_func.h b/src/elrail_func.h index 4de7292228..f45ee53904 100644 --- a/src/elrail_func.h +++ b/src/elrail_func.h @@ -37,5 +37,6 @@ void DrawRailCatenaryOnTunnel(const TileInfo *ti); void DrawRailCatenaryOnBridge(const TileInfo *ti); void SettingsDisableElrail(int32_t new_value); ///< _settings_game.disable_elrail callback +void UpdateDisableElrailSettingState(bool disable, bool update_vehicles); #endif /* ELRAIL_FUNC_H */ diff --git a/src/order_base.h b/src/order_base.h index b24fcee817..6352cace68 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -258,7 +258,7 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord); */ struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { private: - friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain + friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< For instantiating the shared vehicle chain friend SaveLoadTable GetOrderListDescription(); ///< Saving and loading of order lists. VehicleOrderID num_orders; ///< NOSAVE: How many orders there are in the list. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index e1d06532bb..0744e1585f 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -828,8 +828,8 @@ bool AfterLoadGame() } } - /* Update all vehicles */ - AfterLoadVehicles(true); + /* Update all vehicles: Phase 1 */ + AfterLoadVehiclesPhase1(true); /* make sure there is a town in the game */ if (_game_mode == GM_NORMAL && Town::GetNumItems() == 0) { @@ -1356,11 +1356,6 @@ bool AfterLoadGame() break; } } - - for (Train *v : Train::Iterate()) { - if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(CCF_TRACK); - } - } /* In version 16.1 of the savegame a company can decide if trains, which get @@ -1493,7 +1488,7 @@ bool AfterLoadGame() * preference of a user, let elrails enabled; it can be disabled manually */ if (IsSavegameVersionBefore(SLV_38)) _settings_game.vehicle.disable_elrails = false; /* do the same as when elrails were enabled/disabled manually just now */ - SettingsDisableElrail(_settings_game.vehicle.disable_elrails); + UpdateDisableElrailSettingState(_settings_game.vehicle.disable_elrails, false); InitializeRailGUI(); /* From version 53, the map array was changed for house tiles to allow @@ -2815,9 +2810,6 @@ bool AfterLoadGame() } } - /* The center of train vehicles was changed, fix up spacing. */ - if (IsSavegameVersionBefore(SLV_164)) FixupTrainLengths(); - if (IsSavegameVersionBefore(SLV_165)) { for (Town *t : Town::Iterate()) { /* Set the default cargo requirement for town growth */ @@ -2925,6 +2917,14 @@ bool AfterLoadGame() } } + /* Beyond this point, tile types which can be accessed by vehicles must be in a valid state. */ + + /* Update all vehicles: Phase 2 */ + AfterLoadVehiclesPhase2(true); + + /* The center of train vehicles was changed, fix up spacing. */ + if (IsSavegameVersionBefore(SLV_164)) FixupTrainLengths(); + /* In version 2.2 of the savegame, we have new airports, so status of all aircraft is reset. * This has to be called after all map array updates */ if (IsSavegameVersionBefore(SLV_2, 2)) UpdateOldAircraft(); @@ -3342,7 +3342,8 @@ void ReloadNewGRFData() RecomputePrices(); /* reload vehicles */ ResetVehicleHash(); - AfterLoadVehicles(false); + AfterLoadVehiclesPhase1(false); + AfterLoadVehiclesPhase2(false); StartupEngines(); GroupStatistics::UpdateAfterLoad(); /* update station graphics */ diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index e311c5c4aa..7e35000c7f 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -24,7 +24,8 @@ void ResetOldWaypoints(); void MoveBuoysToWaypoints(); void MoveWaypointsToBaseStations(); -void AfterLoadVehicles(bool part_of_load); +void AfterLoadVehiclesPhase1(bool part_of_load); +void AfterLoadVehiclesPhase2(bool part_of_load); void FixupTrainLengths(); void AfterLoadStations(); void AfterLoadRoadStops(); diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 4e42de3962..91936f387c 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -251,8 +251,8 @@ static void CheckValidVehicles() extern uint8_t _age_cargo_skip_counter; // From misc_sl.cpp -/** Called after load to update coordinates */ -void AfterLoadVehicles(bool part_of_load) +/** Called after load for phase 1 of vehicle initialisation */ +void AfterLoadVehiclesPhase1(bool part_of_load) { for (Vehicle *v : Vehicle::Iterate()) { /* Reinstate the previous pointer */ @@ -408,9 +408,13 @@ void AfterLoadVehicles(bool part_of_load) } CheckValidVehicles(); +} +/** Called after load for phase 2 of vehicle initialisation */ +void AfterLoadVehiclesPhase2(bool part_of_load) +{ for (Vehicle *v : Vehicle::Iterate()) { - assert(v->first != nullptr); + assert(v->First() != nullptr); v->trip_occupancy = CalcPercentVehicleFilled(v, nullptr); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index ac6392cf32..8243fdbd59 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -254,7 +254,7 @@ private: public: friend void FixOldVehicles(); - friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the #previous and #first pointers while loading + friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< So we can set the #previous and #first pointers while loading friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading /* So we can use private/protected variables in the saveload code */ friend class SlVehicleCommon;