From 3db03a78d2a3c7cd732dfff6eda63158f8f73378 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 3 Apr 2023 09:26:59 +0300 Subject: [PATCH] Performance: Use unique cache for tile percentage stats and auto-assigning population to tiles --- .../src/com/unciv/logic/automation/Automation.kt | 4 ++-- .../logic/city/managers/CityPopulationManager.kt | 7 +++++-- .../unciv/logic/map/tile/TileStatFunctions.kt | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index e1222f87fd..6c1e31216d 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -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) } diff --git a/core/src/com/unciv/logic/city/managers/CityPopulationManager.kt b/core/src/com/unciv/logic/city/managers/CityPopulationManager.kt index 5acf88c2ba..3e83cc4aa6 100644 --- a/core/src/com/unciv/logic/city/managers/CityPopulationManager.kt +++ b/core/src/com/unciv/logic/city/managers/CityPopulationManager.kt @@ -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 { 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) diff --git a/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt b/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt index 7222619d5e..e3c2432b64 100644 --- a/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt +++ b/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt @@ -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()