mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-01-31 11:23:21 +00:00
Codechange: Speed up industry generation using industry-type checks. (#13094)
Store a list of industries per industry type. This allows industry generation checks which only consider a specific industry type to check a reduced set of industries, leading to a potential performance increase. This also removes the need to track industry type counts as well.
This commit is contained in:
parent
a951896364
commit
16038879e4
@ -243,28 +243,6 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||||||
static Industry *GetRandom();
|
static Industry *GetRandom();
|
||||||
static void PostDestructor(size_t index);
|
static void PostDestructor(size_t index);
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the count of industries for this type.
|
|
||||||
* @param type IndustryType to increment
|
|
||||||
* @pre type < NUM_INDUSTRYTYPES
|
|
||||||
*/
|
|
||||||
static inline void IncIndustryTypeCount(IndustryType type)
|
|
||||||
{
|
|
||||||
assert(type < NUM_INDUSTRYTYPES);
|
|
||||||
counts[type]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrement the count of industries for this type.
|
|
||||||
* @param type IndustryType to decrement
|
|
||||||
* @pre type < NUM_INDUSTRYTYPES
|
|
||||||
*/
|
|
||||||
static inline void DecIndustryTypeCount(IndustryType type)
|
|
||||||
{
|
|
||||||
assert(type < NUM_INDUSTRYTYPES);
|
|
||||||
counts[type]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the count of industries for this type.
|
* Get the count of industries for this type.
|
||||||
* @param type IndustryType to query
|
* @param type IndustryType to query
|
||||||
@ -273,13 +251,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||||||
static inline uint16_t GetIndustryTypeCount(IndustryType type)
|
static inline uint16_t GetIndustryTypeCount(IndustryType type)
|
||||||
{
|
{
|
||||||
assert(type < NUM_INDUSTRYTYPES);
|
assert(type < NUM_INDUSTRYTYPES);
|
||||||
return counts[type];
|
return static_cast<uint16_t>(std::size(industries[type]));
|
||||||
}
|
|
||||||
|
|
||||||
/** Resets industry counts. */
|
|
||||||
static inline void ResetIndustryCounts()
|
|
||||||
{
|
|
||||||
memset(&counts, 0, sizeof(counts));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const std::string &GetCachedName() const
|
inline const std::string &GetCachedName() const
|
||||||
@ -288,11 +260,10 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
|
|||||||
return this->cached_name;
|
return this->cached_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::array<std::vector<IndustryID>, NUM_INDUSTRYTYPES> industries; ///< List of industries of each type.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void FillCachedName() const;
|
void FillCachedName() const;
|
||||||
|
|
||||||
protected:
|
|
||||||
static uint16_t counts[NUM_INDUSTRYTYPES]; ///< Number of industries per type ingame
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClearAllIndustryCachedNames();
|
void ClearAllIndustryCachedNames();
|
||||||
|
@ -63,7 +63,7 @@ void BuildOilRig(TileIndex tile);
|
|||||||
static uint8_t _industry_sound_ctr;
|
static uint8_t _industry_sound_ctr;
|
||||||
static TileIndex _industry_sound_tile;
|
static TileIndex _industry_sound_tile;
|
||||||
|
|
||||||
uint16_t Industry::counts[NUM_INDUSTRYTYPES];
|
std::array<std::vector<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
|
||||||
|
|
||||||
IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
|
IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
|
||||||
IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
|
IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
|
||||||
@ -189,7 +189,9 @@ Industry::~Industry()
|
|||||||
/* Clear the persistent storage. */
|
/* Clear the persistent storage. */
|
||||||
delete this->psa;
|
delete this->psa;
|
||||||
|
|
||||||
DecIndustryTypeCount(this->type);
|
auto &industries = Industry::industries[type];
|
||||||
|
auto it = std::ranges::lower_bound(industries, this->index);
|
||||||
|
industries.erase(it);
|
||||||
|
|
||||||
DeleteIndustryNews(this->index);
|
DeleteIndustryNews(this->index);
|
||||||
CloseWindowById(WC_INDUSTRY_VIEW, this->index);
|
CloseWindowById(WC_INDUSTRY_VIEW, this->index);
|
||||||
@ -1434,8 +1436,8 @@ static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town *
|
|||||||
|
|
||||||
if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
|
if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
|
||||||
|
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
for (const IndustryID &industry : Industry::industries[type]) {
|
||||||
if (i->type == type && i->town == *t) {
|
if (Industry::Get(industry)->town == *t) {
|
||||||
*t = nullptr;
|
*t = nullptr;
|
||||||
return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
|
return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
|
||||||
}
|
}
|
||||||
@ -1693,35 +1695,13 @@ static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, Indus
|
|||||||
{
|
{
|
||||||
const IndustrySpec *indspec = GetIndustrySpec(type);
|
const IndustrySpec *indspec = GetIndustrySpec(type);
|
||||||
|
|
||||||
/* On a large map with many industries, it may be faster to check an area. */
|
for (IndustryType conflicting_type : indspec->conflicting) {
|
||||||
static const int dmax = 14;
|
if (conflicting_type == IT_INVALID) continue;
|
||||||
if (Industry::GetNumItems() > static_cast<size_t>(dmax * dmax * 2)) {
|
|
||||||
const Industry *i = nullptr;
|
|
||||||
TileArea tile_area = TileArea(tile, 1, 1).Expand(dmax);
|
|
||||||
for (TileIndex atile : tile_area) {
|
|
||||||
if (GetTileType(atile) == MP_INDUSTRY) {
|
|
||||||
const Industry *i2 = Industry::GetByTile(atile);
|
|
||||||
if (i == i2) continue;
|
|
||||||
i = i2;
|
|
||||||
if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue;
|
|
||||||
if (i->type == indspec->conflicting[0] ||
|
|
||||||
i->type == indspec->conflicting[1] ||
|
|
||||||
i->type == indspec->conflicting[2]) {
|
|
||||||
return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CommandCost();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
for (const IndustryID &industry : Industry::industries[conflicting_type]) {
|
||||||
/* Within 14 tiles from another industry is considered close */
|
/* Within 14 tiles from another industry is considered close */
|
||||||
if (DistanceMax(tile, i->location.tile) > 14) continue;
|
if (DistanceMax(tile, Industry::Get(industry)->location.tile) > 14) continue;
|
||||||
|
|
||||||
/* check if there are any conflicting industry types around */
|
|
||||||
if (i->type == indspec->conflicting[0] ||
|
|
||||||
i->type == indspec->conflicting[1] ||
|
|
||||||
i->type == indspec->conflicting[2]) {
|
|
||||||
return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
|
return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1787,7 +1767,10 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
|
|||||||
|
|
||||||
i->location = TileArea(tile, 1, 1);
|
i->location = TileArea(tile, 1, 1);
|
||||||
i->type = type;
|
i->type = type;
|
||||||
Industry::IncIndustryTypeCount(type);
|
|
||||||
|
auto &industries = Industry::industries[type];
|
||||||
|
auto it = std::ranges::lower_bound(industries, i->index);
|
||||||
|
it = industries.emplace(it, i->index);
|
||||||
|
|
||||||
for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
|
for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
|
||||||
if (!IsValidCargoID(indspec->produced_cargo[index])) break;
|
if (!IsValidCargoID(indspec->produced_cargo[index])) break;
|
||||||
@ -2413,8 +2396,10 @@ static void PlaceInitialIndustry(IndustryType type, bool try_hard)
|
|||||||
*/
|
*/
|
||||||
static uint GetCurrentTotalNumberOfIndustries()
|
static uint GetCurrentTotalNumberOfIndustries()
|
||||||
{
|
{
|
||||||
int total = 0;
|
uint total = 0;
|
||||||
for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
|
for (const auto &industries : Industry::industries) {
|
||||||
|
total += static_cast<uint16_t>(std::size(industries));
|
||||||
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3090,7 +3075,7 @@ static IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEco
|
|||||||
|
|
||||||
void InitializeIndustries()
|
void InitializeIndustries()
|
||||||
{
|
{
|
||||||
Industry::ResetIndustryCounts();
|
Industry::industries = {};
|
||||||
_industry_sound_tile = 0;
|
_industry_sound_tile = 0;
|
||||||
|
|
||||||
_industry_builder.Reset();
|
_industry_builder.Reset();
|
||||||
|
@ -92,10 +92,11 @@ uint32_t GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32_t cur_g
|
|||||||
static uint32_t GetClosestIndustry(TileIndex tile, IndustryType type, const Industry *current)
|
static uint32_t GetClosestIndustry(TileIndex tile, IndustryType type, const Industry *current)
|
||||||
{
|
{
|
||||||
uint32_t best_dist = UINT32_MAX;
|
uint32_t best_dist = UINT32_MAX;
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
|
||||||
if (i->type != type || i == current) continue;
|
|
||||||
|
|
||||||
best_dist = std::min(best_dist, DistanceManhattan(tile, i->location.tile));
|
for (const IndustryID &industry : Industry::industries[type]) {
|
||||||
|
if (industry == current->index) continue;
|
||||||
|
|
||||||
|
best_dist = std::min(best_dist, DistanceManhattan(tile, Industry::Get(industry)->location.tile));
|
||||||
}
|
}
|
||||||
|
|
||||||
return best_dist;
|
return best_dist;
|
||||||
@ -145,8 +146,11 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_
|
|||||||
} else {
|
} else {
|
||||||
/* Count only those who match the same industry type and layout filter
|
/* Count only those who match the same industry type and layout filter
|
||||||
* Unfortunately, we have to do it manually */
|
* Unfortunately, we have to do it manually */
|
||||||
for (const Industry *i : Industry::Iterate()) {
|
for (const IndustryID &industry : Industry::industries[ind_index]) {
|
||||||
if (i->type == ind_index && i != current && (i->selected_layout == layout_filter || layout_filter == 0) && (!town_filter || i->town == current->town)) {
|
if (industry == current->index) continue;
|
||||||
|
|
||||||
|
const Industry *i = Industry::Get(industry);
|
||||||
|
if ((layout_filter == 0 || i->selected_layout == layout_filter) && (!town_filter || i->town == current->town)) {
|
||||||
closest_dist = std::min(closest_dist, DistanceManhattan(current->location.tile, i->location.tile));
|
closest_dist = std::min(closest_dist, DistanceManhattan(current->location.tile, i->location.tile));
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -278,9 +282,12 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Distance of nearest industry of given type */
|
/* Distance of nearest industry of given type */
|
||||||
case 0x64:
|
case 0x64: {
|
||||||
if (this->tile == INVALID_TILE) break;
|
if (this->tile == INVALID_TILE) break;
|
||||||
return GetClosestIndustry(this->tile, MapNewGRFIndustryType(parameter, indspec->grf_prop.grffile->grfid), this->industry);
|
IndustryType type = MapNewGRFIndustryType(parameter, indspec->grf_prop.grffile->grfid);
|
||||||
|
if (type >= NUM_INDUSTRYTYPES) return UINT32_MAX;
|
||||||
|
return GetClosestIndustry(this->tile, type, this->industry);
|
||||||
|
}
|
||||||
/* Get town zone and Manhattan distance of closest town */
|
/* Get town zone and Manhattan distance of closest town */
|
||||||
case 0x65: {
|
case 0x65: {
|
||||||
if (this->tile == INVALID_TILE) break;
|
if (this->tile == INVALID_TILE) break;
|
||||||
|
@ -211,7 +211,6 @@ struct INDYChunkHandler : ChunkHandler {
|
|||||||
|
|
||||||
SlIndustryAccepted::ResetOldStructure();
|
SlIndustryAccepted::ResetOldStructure();
|
||||||
SlIndustryProduced::ResetOldStructure();
|
SlIndustryProduced::ResetOldStructure();
|
||||||
Industry::ResetIndustryCounts();
|
|
||||||
|
|
||||||
while ((index = SlIterateArray()) != -1) {
|
while ((index = SlIterateArray()) != -1) {
|
||||||
Industry *i = new (index) Industry();
|
Industry *i = new (index) Industry();
|
||||||
@ -229,7 +228,7 @@ struct INDYChunkHandler : ChunkHandler {
|
|||||||
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
|
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
|
||||||
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
|
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
|
||||||
}
|
}
|
||||||
Industry::IncIndustryTypeCount(i->type);
|
Industry::industries[i->type].push_back(i->index); // Assume savegame indices are sorted.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,7 +874,7 @@ static bool LoadOldIndustry(LoadgameState *ls, int num)
|
|||||||
i->random_colour = RemapTTOColour(i->random_colour);
|
i->random_colour = RemapTTOColour(i->random_colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
Industry::IncIndustryTypeCount(i->type);
|
Industry::industries[i->type].push_back(i->index); // Assume savegame indices are sorted.
|
||||||
} else {
|
} else {
|
||||||
delete i;
|
delete i;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user