From 3e83dcedfd61aebe9ec8a900bf3b49edddfcc31c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 12 Mar 2024 17:28:44 +0000 Subject: [PATCH] Codechange: Allocate houses dynamically instead of from a fixed array. This uses vectors for HouseSpecs and global/town building counts. --- src/genworld.cpp | 2 + src/house.h | 15 ++------ src/misc.cpp | 1 - src/newgrf_commons.cpp | 6 ++- src/newgrf_house.cpp | 87 ++++++++++++++++++++++++++++++++++-------- src/newgrf_house.h | 1 + src/table/town_land.h | 2 +- src/town.h | 4 +- src/town_cmd.cpp | 15 +------- 9 files changed, 87 insertions(+), 46 deletions(-) diff --git a/src/genworld.cpp b/src/genworld.cpp index d6b8de88ff..d5281a2f81 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -26,6 +26,7 @@ #include "void_map.h" #include "town.h" #include "newgrf.h" +#include "newgrf_house.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "progress.h" @@ -311,6 +312,7 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti /* Load the right landscape stuff, and the NewGRFs! */ GfxLoadSprites(); + InitializeBuildingCounts(); LoadStringWidthTable(); /* Re-init the windowing system */ diff --git a/src/house.h b/src/house.h index a463b632ec..65ce03786b 100644 --- a/src/house.h +++ b/src/house.h @@ -31,12 +31,6 @@ static const HouseID INVALID_HOUSE_ID = 0xFFFF; static const uint HOUSE_NUM_ACCEPTS = 16; ///< Max number of cargoes accepted by a tile -/** - * There can only be as many classes as there are new houses, plus one for - * NO_CLASS, as the original houses don't have classes. - */ -static const uint HOUSE_CLASS_MAX = NUM_HOUSES - NEW_HOUSE_OFFSET + 1; - enum BuildingFlags { TILE_NO_FLAG = 0, TILE_SIZE_1x1 = 1U << 0, @@ -123,14 +117,11 @@ struct HouseSpec { uint8_t minimum_life; ///< The minimum number of years this house will survive before the town rebuilds it CargoTypes watched_cargoes; ///< Cargo types watched for acceptance. + HouseID Index() const; Money GetRemovalCost() const; - static inline HouseSpec *Get(size_t house_id) - { - assert(house_id < NUM_HOUSES); - extern HouseSpec _house_specs[]; - return &_house_specs[house_id]; - } + static std::vector &Specs(); + static HouseSpec *Get(size_t house_id); }; /** diff --git a/src/misc.cpp b/src/misc.cpp index d6467a1812..9137c075b6 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -148,7 +148,6 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InitializeTrees(); InitializeIndustries(); InitializeObjects(); - InitializeBuildingCounts(); InitializeNPF(); diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index d178920542..9589e31ef4 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -165,7 +165,11 @@ void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs) return; } - *HouseSpec::Get(house_id) = *hs; + auto &house_specs = HouseSpec::Specs(); + + /* Now that we know we can use the given id, copy the spec to its final destination. */ + if (house_id >= house_specs.size()) house_specs.resize(house_id + 1); + house_specs[house_id] = *hs; /* Now add the overrides. */ for (int i = 0; i < this->max_offset; i++) { diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 0321ce0fc3..ac18c4fbe2 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -24,8 +24,8 @@ #include "safeguards.h" -static BuildingCounts _building_counts; -static std::array _class_mapping; +static BuildingCounts _building_counts{}; +static std::vector _class_mapping{}; HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID); @@ -40,6 +40,48 @@ static const GRFFile *GetHouseSpecGrf(HouseID house_id) return (hs != nullptr) ? hs->grf_prop.grffile : nullptr; } +extern const HouseSpec _original_house_specs[NEW_HOUSE_OFFSET]; +std::vector _house_specs; + +/** + * Get a reference to all HouseSpecs. + * @return Reference to vector of all HouseSpecs. + */ +std::vector &HouseSpec::Specs() +{ + return _house_specs; +} + +/** + * Get the spec for a house ID. + * @param house_id The ID of the house. + * @return The HouseSpec associated with the ID. + */ +HouseSpec *HouseSpec::Get(size_t house_id) +{ + /* Empty house if index is out of range -- this might happen if NewGRFs are changed. */ + static HouseSpec empty = {}; + + assert(house_id < NUM_HOUSES); + if (house_id >= _house_specs.size()) return ∅ + return &_house_specs[house_id]; +} + +/* Reset and initialise house specs. */ +void ResetHouses() +{ + _house_specs.clear(); + _house_specs.reserve(std::size(_original_house_specs)); + + ResetHouseClassIDs(); + + /* Copy default houses. */ + _house_specs.insert(std::end(_house_specs), std::begin(_original_house_specs), std::end(_original_house_specs)); + + /* Reset any overrides that have been set. */ + _house_mngr.ResetOverride(); +} + /** * Construct a resolver for a house. * @param house_id House to query. @@ -74,32 +116,47 @@ uint32_t HouseResolverObject::GetDebugID() const void ResetHouseClassIDs() { - _class_mapping = {}; + _class_mapping.clear(); + + /* Add initial entry for HOUSE_NO_CLASS. */ + _class_mapping.emplace_back(); } HouseClassID AllocateHouseClassID(uint8_t grf_class_id, uint32_t grfid) { /* Start from 1 because 0 means that no class has been assigned. */ - for (int i = 1; i != lengthof(_class_mapping); i++) { - HouseClassMapping *map = &_class_mapping[i]; + auto it = std::find_if(std::next(std::begin(_class_mapping)), std::end(_class_mapping), [grf_class_id, grfid](const HouseClassMapping &map) { return map.class_id == grf_class_id && map.grfid == grfid; }); - if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i; + /* HouseClass not found, allocate a new one. */ + if (it == std::end(_class_mapping)) it = _class_mapping.insert(it, {.grfid = grfid, .class_id = grf_class_id}); - if (map->class_id == 0 && map->grfid == 0) { - map->class_id = grf_class_id; - map->grfid = grfid; - return (HouseClassID)i; - } - } - return HOUSE_NO_CLASS; + return static_cast(std::distance(std::begin(_class_mapping), it)); } +/** + * Initialise building counts for a town. + * @param t Town cache to initialise. + */ +void InitializeBuildingCounts(Town *t) +{ + t->cache.building_counts.id_count.clear(); + t->cache.building_counts.class_count.clear(); + t->cache.building_counts.id_count.resize(HouseSpec::Specs().size()); + t->cache.building_counts.class_count.resize(_class_mapping.size()); +} + +/** + * Initialise global building counts and all town building counts. + */ void InitializeBuildingCounts() { - memset(&_building_counts, 0, sizeof(_building_counts)); + _building_counts.id_count.clear(); + _building_counts.class_count.clear(); + _building_counts.id_count.resize(HouseSpec::Specs().size()); + _building_counts.class_count.resize(_class_mapping.size()); for (Town *t : Town::Iterate()) { - memset(&t->cache.building_counts, 0, sizeof(t->cache.building_counts)); + InitializeBuildingCounts(t); } } diff --git a/src/newgrf_house.h b/src/newgrf_house.h index 868116c7f9..1987406777 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -91,6 +91,7 @@ void ResetHouseClassIDs(); HouseClassID AllocateHouseClassID(uint8_t grf_class_id, uint32_t grfid); void InitializeBuildingCounts(); +void InitializeBuildingCounts(Town *t); void IncreaseBuildingCount(Town *t, HouseID house_id); void DecreaseBuildingCount(Town *t, HouseID house_id); diff --git a/src/table/town_land.h b/src/table/town_land.h index 2ba1bc173b..586a94b3a8 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -1817,7 +1817,7 @@ static_assert(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); bf, ba, true, GRFFileProps(INVALID_HOUSE_ID), 0, {COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN}, \ 16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0} /** House specifications from original data */ -static const HouseSpec _original_house_specs[] = { +extern const HouseSpec _original_house_specs[] = { /** * remove_rating_decrease * | mail_generation diff --git a/src/town.h b/src/town.h index 618093dec4..28ffa5047d 100644 --- a/src/town.h +++ b/src/town.h @@ -19,8 +19,8 @@ template struct BuildingCounts { - T id_count[NUM_HOUSES]; - T class_count[HOUSE_CLASS_MAX]; + std::vector id_count; + std::vector class_count; }; static const uint CUSTOM_TOWN_NUMBER_DIFFICULTY = 4; ///< value for custom town number in difficulty settings diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 3ebe90087e..b85d077d92 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -1941,6 +1941,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32_t townnameparts, TownSi UpdateTownRadius(t); t->flags = 0; t->cache.population = 0; + InitializeBuildingCounts(t); /* Spread growth across ticks so even if there are many * similar towns they're unlikely to grow all in one tick */ t->grow_counter = t->index % Ticks::TOWN_GROWTH_TICKS; @@ -3969,17 +3970,3 @@ extern const TileTypeProcs _tile_type_town_procs = { GetFoundation_Town, // get_foundation_proc TerraformTile_Town, // terraform_tile_proc }; - - -HouseSpec _house_specs[NUM_HOUSES]; - -void ResetHouses() -{ - ResetHouseClassIDs(); - - auto insert = std::copy(std::begin(_original_house_specs), std::end(_original_house_specs), std::begin(_house_specs)); - std::fill(insert, std::end(_house_specs), HouseSpec{}); - - /* Reset any overrides that have been set. */ - _house_mngr.ResetOverride(); -}