Speed up authority and advertisement zoning

This commit is contained in:
Pavel Stupnikov
2019-02-12 17:36:40 +03:00
parent 6f1b0682da
commit c2d889eab3
2 changed files with 95 additions and 3 deletions

View File

@@ -5,11 +5,99 @@
#include "viewport_func.h"
#include "town.h"
#include "zoning.h"
#include "genworld.h"
#include <algorithm>
#include <vector>
Zoning _zoning = {CHECKNOTHING, CHECKNOTHING};
static const SpriteID INVALID_SPRITE_ID = UINT_MAX;
//RED GREEN BLACK LIGHT_BLUE ORANGE WHITE YELLOW PURPLE
TileIndex _closest_cache_ref = INVALID_TILE;
const uint CLOSEST_CACHE_THRESHOLD = 128;
std::vector<std::pair<uint, Town*>> _closest_cache;
void RebuildClosestHash(TileIndex tile) {
_closest_cache_ref = INVALID_TILE;
_closest_cache.clear();
Town *t;
FOR_ALL_TOWNS(t) {
_closest_cache.push_back(std::make_pair(
DistanceManhattan(t->xy, tile), t));
}
std::sort(
_closest_cache.begin(), _closest_cache.end(),
[](auto &a, auto &b) -> bool {
return a.first < b.first;
}
);
_closest_cache_ref = tile;
}
Town *CMCalcClosestTownFromTile(TileIndex tile, uint threshold = INT_MAX)
{
if (_closest_cache_ref == INVALID_TILE
|| DistanceManhattan(_closest_cache_ref, tile) > CLOSEST_CACHE_THRESHOLD) {
RebuildClosestHash(tile);
// RebuildClosestHash(TileXY(
// TileX(tile) + CLOSEST_CACHE_THRESHOLD / 2,
// TileY(tile) + CLOSEST_CACHE_THRESHOLD / 2));
}
int ref_dist = DistanceManhattan(_closest_cache_ref, tile);
uint best = threshold;
Town *best_town = NULL;
for (auto p: _closest_cache) {
if (p.first > best + ref_dist)
break;
uint dist = DistanceManhattan(tile, p.second->xy);
if (dist < best) {
best = dist;
best_town = p.second;
}
}
return best_town;
}
// Copy ClosestTownFromTile but uses CMCalcClosestTownFromTile
Town *CMClosestTownFromTile(TileIndex tile, uint threshold)
{
switch (GetTileType(tile)) {
case MP_ROAD:
if (IsRoadDepot(tile)) return CalcClosestTownFromTile(tile, threshold);
if (!HasTownOwnedRoad(tile)) {
TownID tid = GetTownIndex(tile);
if (tid == (TownID)INVALID_TOWN) {
/* in the case we are generating "many random towns", this value may be INVALID_TOWN */
if (_generating_world) return CalcClosestTownFromTile(tile, threshold);
assert(Town::GetNumItems() == 0);
return NULL;
}
assert(Town::IsValidID(tid));
Town *town = Town::Get(tid);
if (DistanceManhattan(tile, town->xy) >= threshold) town = NULL;
return town;
}
FALLTHROUGH;
case MP_HOUSE:
return Town::GetByTile(tile);
default:
return CMCalcClosestTownFromTile(tile, threshold);
}
}
/**
* Draw the zoning sprites.
* @param SpriteID image
@@ -76,7 +164,7 @@ bool IsTileWithinAcceptanceZoneOfStation(TileIndex tile) {
//Check the opinion of the local authority in the tile.
SpriteID TileZoneCheckOpinionEvaluation(TileIndex tile, Owner owner) {
Town *town = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
Town *town = CMClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
if (town == NULL) return INVALID_SPRITE_ID; // no town
else if (HasBit(town->have_ratings, owner)) { // good : bad
@@ -214,7 +302,7 @@ SpriteID TileZoneCheckNewCBBorders(TileIndex tile) {
//Check CB town acceptance area
SpriteID TileZoneCheckCBBorders(TileIndex tile) {
Town *town = CalcClosestTownFromTile(tile);
Town *town = CMCalcClosestTownFromTile(tile);
if (town != NULL) {
if (DistanceManhattan(town->xy, tile) <= _settings_client.gui.cb_distance_check) {
@@ -238,7 +326,7 @@ SpriteID TileZoneCheckCBTownBorders(TileIndex tile) {
//Check which advertisement zone(small, medium, large) tile belongs to
SpriteID TileZoneCheckTownAdvertisementZones(TileIndex tile) {
Town *town = CalcClosestTownFromTile(tile, 21U);
Town *town = CMCalcClosestTownFromTile(tile, 21U);
if (town == NULL) return INVALID_SPRITE_ID; //nothing
uint dist = DistanceManhattan(town->xy, tile);