Performance: Use unique cache for tile percentage stats and auto-assigning population to tiles

This commit is contained in:
Yair Morgenstern 2023-04-03 09:26:59 +03:00
parent d3ac7c24bd
commit 3db03a78d2
3 changed files with 19 additions and 8 deletions

View File

@ -21,8 +21,8 @@ import com.unciv.ui.screens.victoryscreen.RankingType
object Automation {
fun rankTileForCityWork(tile: Tile, city: City, cityStats: Stats): Float {
val stats = tile.stats.getTileStats(city, city.civ)
fun rankTileForCityWork(tile: Tile, city: City, cityStats: Stats, localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)): Float {
val stats = tile.stats.getTileStats(city, city.civ, localUniqueCache)
return rankStatsForCityWork(stats, city, cityStats)
}

View File

@ -8,6 +8,7 @@ import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.map.tile.Tile
import com.unciv.models.Counter
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.ui.components.extensions.toPercent
@ -151,11 +152,13 @@ class CityPopulationManager : IsPartOfGameInfoSerialization {
val tilesToEvaluate = city.getCenterTile().getTilesInDistance(3)
.filter { it.getOwner() == currentCiv && !it.isBlockaded() }.toList().asSequence()
val localUniqueCache = LocalUniqueCache()
for (i in 1..getFreePopulation()) {
//evaluate tiles
val (bestTile, valueBestTile) = tilesToEvaluate
.filterNot { it.providesYield() }
.associateWith { Automation.rankTileForCityWork(it, city, cityStats) }
.associateWith { Automation.rankTileForCityWork(it, city, cityStats, localUniqueCache) }
.maxByOrNull { it.value }
?: object : Map.Entry<Tile?, Float> {
override val key: Tile? = null
@ -176,7 +179,7 @@ class CityPopulationManager : IsPartOfGameInfoSerialization {
if (valueBestTile > valueBestSpecialist) {
if (bestTile != null) {
city.workedTiles = city.workedTiles.withItem(bestTile.position)
cityStats[Stat.Food] += bestTile.stats.getTileStats(city, city.civ)[Stat.Food]
cityStats[Stat.Food] += bestTile.stats.getTileStats(city, city.civ, localUniqueCache)[Stat.Food]
}
} else if (bestJob != null) {
specialistAllocations.add(bestJob, 1)

View File

@ -70,7 +70,7 @@ class TileStatFunctions(val tile: Tile) {
stats.coerceAtLeast(minimumStats) // Minimum 0 or as defined by City center
for ((stat, value) in getTilePercentageStats(observingCiv, city)) {
for ((stat, value) in getTilePercentageStats(observingCiv, city, localUniqueCache)) {
stats[stat] *= value.toPercent()
}
@ -103,18 +103,26 @@ class TileStatFunctions(val tile: Tile) {
// Only gets the tile percentage bonus, not the improvement percentage bonus
@Suppress("MemberVisibilityCanBePrivate")
fun getTilePercentageStats(observingCiv: Civilization?, city: City?): Stats {
fun getTilePercentageStats(observingCiv: Civilization?, city: City?, uniqueCache: LocalUniqueCache): Stats {
val stats = Stats()
val stateForConditionals = StateForConditionals(civInfo = observingCiv, city = city, tile = tile)
if (city != null) {
for (unique in city.getMatchingUniques(UniqueType.StatPercentFromObject, stateForConditionals)) {
// Since the tile changes every time, we cache all uniques, and filter by conditional state only when iterating
val cachedStatPercentFromObjectUniques = uniqueCache.get(UniqueType.StatPercentFromObject.name,
city.getMatchingUniques(UniqueType.StatPercentFromObject, StateForConditionals.IgnoreConditionals))
for (unique in cachedStatPercentFromObjectUniques) {
if (!unique.conditionalsApply(stateForConditionals)) continue
val tileFilter = unique.params[2]
if (tile.matchesTerrainFilter(tileFilter, observingCiv))
stats[Stat.valueOf(unique.params[1])] += unique.params[0].toFloat()
}
for (unique in city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, stateForConditionals)) {
val cachedAllStatPercentFromObjectUniques = uniqueCache.get(UniqueType.AllStatsPercentFromObject.name,
city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, StateForConditionals.IgnoreConditionals))
for (unique in cachedAllStatPercentFromObjectUniques) {
if (!unique.conditionalsApply(stateForConditionals)) continue
val tileFilter = unique.params[1]
if (!tile.matchesTerrainFilter(tileFilter, observingCiv)) continue
val statPercentage = unique.params[0].toFloat()