diff --git a/src/openttd.cpp b/src/openttd.cpp index 4261abe5c6..56ecf4072e 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1341,8 +1341,8 @@ void CheckCaches(bool force_check, std::function log) const CargoTypes old_town_cargoes_accepted = _town_cargoes_accepted; - extern void RebuildTownCaches(); - RebuildTownCaches(); + extern void RebuildTownCaches(bool cargo_update_required); + RebuildTownCaches(false); RebuildSubsidisedSourceAndDestinationCache(); Station::RecomputeCatchmentForAll(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 1a333eff71..4ed0ae9136 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3093,17 +3093,21 @@ bool AfterLoadGame() * which is done by StartupEngines(). */ if (gcf_res != GLC_ALL_GOOD) StartupEngines(); - if (IsSavegameVersionBefore(SLV_166)) { + if (SlXvIsFeatureMissing(XSLFI_TOWN_CARGO_MATRIX)) { /* Update cargo acceptance map of towns. */ + Town *town; + FOR_ALL_TOWNS(town) { + town->cargo_accepted.Clear(); + } for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_HOUSE)) continue; Town::Get(GetTownIndex(t))->cargo_accepted.Add(t); } - Town *town; FOR_ALL_TOWNS(town) { UpdateTownCargoes(town); } + UpdateTownCargoBitmap(); } /* Set some breakdown-related variables to the correct values. */ diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 7a88d6e9b0..afdab325fb 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -107,6 +107,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_LINKGRAPH_MODES, XSCF_NULL, 1, 1, "linkgraph_modes", nullptr, nullptr, nullptr }, { XSLFI_GAME_EVENTS, XSCF_NULL, 1, 1, "game_events", nullptr, nullptr, nullptr }, { XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr }, + { XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 1, 1, "town_cargo_matrix", nullptr, nullptr, nullptr }, { XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL" }, { 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 6d6fa9ad82..2011fab96a 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -74,6 +74,7 @@ enum SlXvFeatureIndex { XSLFI_LINKGRAPH_MODES, ///< Linkgraph additional distribution modes XSLFI_GAME_EVENTS, ///< Game event flags XSLFI_ROAD_LAYOUT_CHANGE_CTR, ///< Road layout change counter + XSLFI_TOWN_CARGO_MATRIX, ///< Town cargo matrix savegame format changes XSLFI_DEBUG, ///< Debugging info XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 87d033c869..da95f531b5 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -24,7 +24,7 @@ /** * Rebuild all the cached variables of towns. */ -void RebuildTownCaches() +void RebuildTownCaches(bool cargo_update_required) { Town *town; InitializeBuildingCounts(); @@ -51,7 +51,11 @@ void RebuildTownCaches() /* Update the population and num_house dependent values */ FOR_ALL_TOWNS(town) { UpdateTownRadius(town); - UpdateTownCargoes(town); + if (cargo_update_required) { + UpdateTownCargoes(town); + } else { + UpdateTownCargoTotal(town); + } } UpdateTownCargoBitmap(); } @@ -66,6 +70,8 @@ void RebuildTownCaches() */ void UpdateHousesAndTowns() { + bool cargo_update_required = false; + for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; @@ -75,6 +81,7 @@ void UpdateHousesAndTowns() * replace it with the substitute original house type. */ house_id = _house_mngr.GetSubstituteID(house_id); SetHouseType(t, house_id); + cargo_update_required = true; } } @@ -104,15 +111,19 @@ void UpdateHousesAndTowns() /* If not all tiles of this house are present remove the house. * The other tiles will get removed later in this loop because * their north tile is not the correct type anymore. */ - if (!valid_house) DoClearSquare(t); + if (!valid_house) { + DoClearSquare(t); + cargo_update_required = true; + } } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) { /* This tile should be part of a multi-tile building but the * north tile of this house isn't on the map. */ DoClearSquare(t); + cargo_update_required = true; } } - RebuildTownCaches(); + RebuildTownCaches(cargo_update_required); } /** Save and load of towns. */ @@ -273,7 +284,7 @@ static void RealSave_Town(Town *t) SlObject(&t->cargo_accepted, GetTileMatrixDesc()); if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; - SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32); + SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64); } } @@ -313,16 +324,24 @@ static void Load_TOWN() SlErrorCorrupt("Invalid town name generator"); } - if (IsSavegameVersionBefore(SLV_166)) continue; + if (!IsSavegameVersionBefore(SLV_166) && SlXvIsFeatureMissing(XSLFI_TOWN_CARGO_MATRIX)) { + SlSkipBytes(4); // tile + uint16 w = SlReadUint16(); + uint16 h = SlReadUint16(); + if (w != 0) { + SlSkipBytes(4 * (w / 4 * h / 4)); + } + } + if (SlXvIsFeaturePresent(XSLFI_TOWN_CARGO_MATRIX)) { + SlObject(&t->cargo_accepted, GetTileMatrixDesc()); + if (t->cargo_accepted.area.w != 0) { + uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; + t->cargo_accepted.data = MallocT(arr_len); + SlArray(t->cargo_accepted.data, arr_len, SLE_UINT64); - SlObject(&t->cargo_accepted, GetTileMatrixDesc()); - if (t->cargo_accepted.area.w != 0) { - uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; - t->cargo_accepted.data = MallocT(arr_len); - SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32); - - /* Rebuild total cargo acceptance. */ - UpdateTownCargoTotal(t); + /* Rebuild total cargo acceptance. */ + UpdateTownCargoTotal(t); + } } } } diff --git a/src/tilematrix_type.hpp b/src/tilematrix_type.hpp index 78cde1643c..2547e817c7 100644 --- a/src/tilematrix_type.hpp +++ b/src/tilematrix_type.hpp @@ -76,6 +76,13 @@ public: free(this->data); } + void Clear() + { + this->area = TileArea(INVALID_TILE, 0, 0); + free(this->data); + this->data = nullptr; + } + /** * Get the total covered area. * @return The area covered by the matrix. diff --git a/src/town.h b/src/town.h index 061f048e1f..8d44e9ae1c 100644 --- a/src/town.h +++ b/src/town.h @@ -93,7 +93,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { /* Cargo production and acceptance stats. */ CargoTypes cargo_produced; ///< Bitmap of all cargoes produced by houses in this town. - AcceptanceMatrix cargo_accepted; ///< Bitmap of cargoes accepted by houses for each 4*4 map square of the town. + AcceptanceMatrix cargo_accepted; ///< Bitmap of cargoes accepted by houses for each 4*4 (really 6*6) map square of the town. CargoTypes cargo_accepted_total; ///< NOSAVE: Bitmap of all cargoes accepted by houses in this town. StationList stations_near; ///< NOSAVE: List of nearby stations. diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index a490183d69..4e7f609056 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -964,14 +964,12 @@ void UpdateTownCargoTotal(Town *t) * @param start Update the values around this tile. * @param update_total Set to true if the total cargo acceptance should be updated. */ -static void UpdateTownCargoes(Town *t, TileIndex start, bool update_total = true) +static void UpdateTownCargoesSingleGridArea(Town *t, TileIndex start, bool update_total = true) { CargoArray accepted, produced; CargoTypes dummy = 0; - /* Gather acceptance for all houses in an area around the start tile. - * The area is composed of the square the tile is in, extended one square in all - * directions as the coverage area of a single station is bigger than just one square. */ + /* Gather acceptance for all houses in an area around the start tile. */ TileArea area = AcceptanceMatrix::GetAreaForTile(start, 1); TILE_AREA_LOOP(tile, area) { if (!IsTileType(tile, MP_HOUSE) || GetTownIndex(tile) != t->index) continue; @@ -991,6 +989,18 @@ static void UpdateTownCargoes(Town *t, TileIndex start, bool update_total = true if (update_total) UpdateTownCargoTotal(t); } +static void UpdateTownCargoesHouse(Town *t, TileIndex start, bool x_two_tiles, bool y_two_tiles, bool update_total = true) +{ + TileIndex lower = TileAddWrap(start, -1, -1); + TileIndex upper = TileAddWrap(start, x_two_tiles ? 2 : 1, y_two_tiles ? 2 : 1); + for (uint x = TileX(lower) & ~(AcceptanceMatrix::GRID - 1); x <= TileX(upper); x += AcceptanceMatrix::GRID) { + for (uint y = TileY(lower) & ~(AcceptanceMatrix::GRID - 1); y <= TileY(upper); y += AcceptanceMatrix::GRID) { + UpdateTownCargoesSingleGridArea(t, TileXY(x, y), false); + } + } + if (update_total) UpdateTownCargoTotal(t); +} + /** Update cargo acceptance for the complete town. * @param t The town to update. */ @@ -1003,7 +1013,7 @@ void UpdateTownCargoes(Town *t) /* Update acceptance for each grid square. */ TILE_AREA_LOOP_STEP(tile, area, AcceptanceMatrix::GRID) { - UpdateTownCargoes(t, tile, false); + UpdateTownCargoesSingleGridArea(t, tile, false); } /* Update the total acceptance. */ @@ -2643,7 +2653,7 @@ static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte random_bit MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits); UpdateTownRadius(t); UpdateTownGrowthRate(t); - UpdateTownCargoes(t, tile); + UpdateTownCargoesHouse(t, tile, hs->building_flags & BUILDING_2_TILES_X, hs->building_flags & BUILDING_2_TILES_Y); } /** @@ -2852,7 +2862,7 @@ void ClearTownHouse(Town *t, TileIndex tile) UpdateTownRadius(t); /* Update cargo acceptance. */ - UpdateTownCargoes(t, tile); + UpdateTownCargoesHouse(t, tile, eflags & BUILDING_2_TILES_X, eflags & BUILDING_2_TILES_Y); } /**