mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-13 17:28:57 +07:00
perf: Performance improvements for worker automation by caching uniques
This commit is contained in:
@ -72,7 +72,7 @@ object Automation {
|
||||
|
||||
if (surplusFood > 0 && city.avoidGrowth) {
|
||||
yieldStats.food = 0f // don't need more food!
|
||||
} else if (cityAIFocus in CityFocus.zeroFoodFocuses()) {
|
||||
} else if (cityAIFocus in CityFocus.zeroFoodFocuses) {
|
||||
// Focus on non-food/growth
|
||||
if (surplusFood < 0)
|
||||
yieldStats.food *= 8 // Starving, need Food, get to 0
|
||||
|
@ -68,16 +68,16 @@ class WorkerAutomation(
|
||||
/**
|
||||
* Automate one Worker - decide what to do and where, move, start or continue work.
|
||||
*/
|
||||
fun automateWorkerAction(unit: MapUnit, dangerousTiles: HashSet<Tile>) {
|
||||
fun automateWorkerAction(unit: MapUnit, dangerousTiles: HashSet<Tile>, localUniqueCache: LocalUniqueCache = LocalUniqueCache()) {
|
||||
val currentTile = unit.getTile()
|
||||
// Must be called before any getPriority checks to guarantee the local road cache is processed
|
||||
val citiesToConnect = roadBetweenCitiesAutomation.getNearbyCitiesToConnect(unit)
|
||||
// Shortcut, we are working a good tile (like resource) and don't need to check for other tiles to work
|
||||
if (!dangerousTiles.contains(currentTile) && getFullPriority(unit.getTile(), unit) >= 10
|
||||
if (!dangerousTiles.contains(currentTile) && getFullPriority(unit.getTile(), unit, localUniqueCache) >= 10
|
||||
&& currentTile.improvementInProgress != null) {
|
||||
return
|
||||
}
|
||||
val tileToWork = findTileToWork(unit, dangerousTiles)
|
||||
val tileToWork = findTileToWork(unit, dangerousTiles, localUniqueCache)
|
||||
|
||||
if (tileToWork != currentTile) {
|
||||
debug("WorkerAutomation: %s -> head towards %s", unit.toString(), tileToWork)
|
||||
@ -106,7 +106,7 @@ class WorkerAutomation(
|
||||
return
|
||||
}
|
||||
if (reachedTile.improvementInProgress == null && reachedTile.isLand
|
||||
&& tileHasWorkToDo(reachedTile, unit)
|
||||
&& tileHasWorkToDo(reachedTile, unit, localUniqueCache)
|
||||
) {
|
||||
debug("WorkerAutomation: $unit -> start improving $reachedTile")
|
||||
return reachedTile.startWorkingOnImprovement(tileRankings[reachedTile]!!.bestImprovement!!, civInfo, unit)
|
||||
@ -117,7 +117,7 @@ class WorkerAutomation(
|
||||
|
||||
if (currentTile.improvementInProgress != null) return // we're working!
|
||||
|
||||
if (tileHasWorkToDo(currentTile, unit)) {
|
||||
if (tileHasWorkToDo(currentTile, unit, localUniqueCache)) {
|
||||
val tileRankings = tileRankings[currentTile]!!
|
||||
if (tileRankings.repairImprovment!!) {
|
||||
debug("WorkerAutomation: $unit -> repairs $currentTile")
|
||||
@ -140,7 +140,9 @@ class WorkerAutomation(
|
||||
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
|
||||
for (city in unit.civ.cities) {
|
||||
citiesToNumberOfUnimprovedTiles[city.id] = city.getTiles()
|
||||
.count { tile -> tile.isLand && tile.getUnits().any { unit -> unit.cache.hasUniqueToBuildImprovements } && (tile.isPillaged() || tileHasWorkToDo(tile, unit)) }
|
||||
.count { tile -> tile.isLand
|
||||
&& tile.getUnits().any { unit -> unit.cache.hasUniqueToBuildImprovements }
|
||||
&& (tile.isPillaged() || tileHasWorkToDo(tile, unit, localUniqueCache)) }
|
||||
}
|
||||
|
||||
val closestUndevelopedCity = unit.civ.cities.asSequence()
|
||||
@ -171,10 +173,10 @@ class WorkerAutomation(
|
||||
* Looks for a worthwhile tile to improve
|
||||
* @return The current tile if no tile to work was found
|
||||
*/
|
||||
private fun findTileToWork(unit: MapUnit, tilesToAvoid: Set<Tile>): Tile {
|
||||
private fun findTileToWork(unit: MapUnit, tilesToAvoid: Set<Tile>, localUniqueCache: LocalUniqueCache): Tile {
|
||||
val currentTile = unit.getTile()
|
||||
if (currentTile !in tilesToAvoid && getBasePriority(currentTile, unit) >= 5
|
||||
&& (tileHasWorkToDo(currentTile, unit) || currentTile.isPillaged() || currentTile.hasFalloutEquivalent())) {
|
||||
&& (tileHasWorkToDo(currentTile, unit, localUniqueCache) || currentTile.isPillaged() || currentTile.hasFalloutEquivalent())) {
|
||||
return currentTile
|
||||
}
|
||||
val workableTilesCenterFirst = currentTile.getTilesInDistance(4)
|
||||
@ -197,10 +199,10 @@ class WorkerAutomation(
|
||||
var bestTile: Tile? = null
|
||||
for (tileInGroup in tilePriorityGroup.value.sortedBy { unit.getTile().aerialDistanceTo(it) }) {
|
||||
// These are the expensive calculations (tileCanBeImproved, canReach), so we only apply these filters after everything else it done.
|
||||
if (!tileHasWorkToDo(tileInGroup, unit)) continue
|
||||
if (!tileHasWorkToDo(tileInGroup, unit, localUniqueCache)) continue
|
||||
if (unit.getTile() == tileInGroup) return unit.getTile()
|
||||
if (!unit.movement.canReach(tileInGroup)) continue
|
||||
if (bestTile == null || getFullPriority(tileInGroup, unit) > getFullPriority(bestTile, unit)) {
|
||||
if (bestTile == null || getFullPriority(tileInGroup, unit, localUniqueCache) > getFullPriority(bestTile, unit, localUniqueCache)) {
|
||||
bestTile = tileInGroup
|
||||
}
|
||||
}
|
||||
@ -252,23 +254,23 @@ class WorkerAutomation(
|
||||
/**
|
||||
* Calculates the priority building the improvement on the tile
|
||||
*/
|
||||
private fun getImprovementPriority(tile: Tile, unit: MapUnit): Float {
|
||||
private fun getImprovementPriority(tile: Tile, unit: MapUnit, localUniqueCache: LocalUniqueCache): Float {
|
||||
getBasePriority(tile, unit)
|
||||
val rank = tileRankings[tile]
|
||||
if(rank!!.improvementPriority == null) {
|
||||
if (rank!!.improvementPriority == null) {
|
||||
// All values of rank have to be initialized
|
||||
rank.improvementPriority = -100f
|
||||
rank.bestImprovement = null
|
||||
rank.repairImprovment = false
|
||||
|
||||
val bestImprovement = chooseImprovement(unit, tile)
|
||||
val bestImprovement = chooseImprovement(unit, tile, localUniqueCache)
|
||||
if (bestImprovement != null) {
|
||||
rank.bestImprovement = bestImprovement
|
||||
// Increased priority if the improvement has been worked on longer
|
||||
val timeSpentPriority = if (tile.improvementInProgress == bestImprovement.name)
|
||||
bestImprovement.getTurnsToBuild(unit.civ,unit) - tile.turnsToImprovement else 0
|
||||
|
||||
rank.improvementPriority = getImprovementRanking(tile, unit, rank.bestImprovement!!.name, LocalUniqueCache()) + timeSpentPriority
|
||||
rank.improvementPriority = getImprovementRanking(tile, unit, rank.bestImprovement!!.name, localUniqueCache) + timeSpentPriority
|
||||
}
|
||||
|
||||
if (tile.improvement != null && tile.isPillaged() && tile.owningCity != null) {
|
||||
@ -293,15 +295,15 @@ class WorkerAutomation(
|
||||
/**
|
||||
* Calculates the full priority of the tile
|
||||
*/
|
||||
private fun getFullPriority(tile: Tile, unit: MapUnit): Float {
|
||||
return getBasePriority(tile, unit) + getImprovementPriority(tile, unit)
|
||||
private fun getFullPriority(tile: Tile, unit: MapUnit, localUniqueCache: LocalUniqueCache): Float {
|
||||
return getBasePriority(tile, unit) + getImprovementPriority(tile, unit, localUniqueCache)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best improvement
|
||||
*/
|
||||
private fun tileHasWorkToDo(tile: Tile, unit: MapUnit): Boolean {
|
||||
if (getImprovementPriority(tile, unit) <= 0) return false
|
||||
private fun tileHasWorkToDo(tile: Tile, unit: MapUnit, localUniqueCache: LocalUniqueCache): Boolean {
|
||||
if (getImprovementPriority(tile, unit, localUniqueCache) <= 0) return false
|
||||
if (!(tileRankings[tile]!!.bestImprovement != null || tileRankings[tile]!!.repairImprovment!!))
|
||||
throw IllegalStateException("There was an improvementPriority > 0 and nothing to do")
|
||||
return true
|
||||
@ -311,7 +313,7 @@ class WorkerAutomation(
|
||||
* Determine the improvement appropriate to a given tile and worker
|
||||
* Returns null if
|
||||
* */
|
||||
private fun chooseImprovement(unit: MapUnit, tile: Tile): TileImprovement? {
|
||||
private fun chooseImprovement(unit: MapUnit, tile: Tile, localUniqueCache: LocalUniqueCache): TileImprovement? {
|
||||
// You can keep working on half-built improvements, even if they're unique to another civ
|
||||
if (tile.improvementInProgress != null) return ruleSet.tileImprovements[tile.improvementInProgress!!]
|
||||
|
||||
@ -322,8 +324,6 @@ class WorkerAutomation(
|
||||
}
|
||||
if (potentialTileImprovements.isEmpty()) return null
|
||||
|
||||
val localUniqueCache = LocalUniqueCache()
|
||||
|
||||
var bestBuildableImprovement = potentialTileImprovements.values.asSequence()
|
||||
.map { Pair(it, getImprovementRanking(tile, unit, it.name, localUniqueCache)) }
|
||||
.filter { it.second > 0f }
|
||||
@ -410,7 +410,7 @@ class WorkerAutomation(
|
||||
newTile.removeTerrainFeature(removedFeature)
|
||||
if (removedImprovement != null)
|
||||
newTile.removeImprovement()
|
||||
val wantedFinalImprovement = chooseImprovement(unit, newTile)
|
||||
val wantedFinalImprovement = chooseImprovement(unit, newTile, localUniqueCache)
|
||||
if (wantedFinalImprovement != null)
|
||||
stats.add(newTile.stats.getStatDiffForImprovement(wantedFinalImprovement, civInfo, newTile.getCity(), localUniqueCache))
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ enum class CityFocus(
|
||||
|
||||
fun applyWeightTo(stats: Stats) {
|
||||
for (stat in Stat.values()) {
|
||||
stats[stat] *= getStatMultiplier(stat)
|
||||
val currentStat = stats[stat]
|
||||
if (currentStat != 0f) stats[stat] *= getStatMultiplier(stat)
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,12 +79,10 @@ enum class CityFocus(
|
||||
}
|
||||
|
||||
// set used in Automation. All non-Food Focuses, so targets 0 Surplus Food
|
||||
fun zeroFoodFocuses(): Set<CityFocus> {
|
||||
return setOf(
|
||||
CultureFocus, FaithFocus, GoldFocus,
|
||||
HappinessFocus, ProductionFocus, ScienceFocus
|
||||
)
|
||||
}
|
||||
val zeroFoodFocuses = setOf(
|
||||
CultureFocus, FaithFocus, GoldFocus,
|
||||
HappinessFocus, ProductionFocus, ScienceFocus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user