mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-18 03:38:55 +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) {
|
if (surplusFood > 0 && city.avoidGrowth) {
|
||||||
yieldStats.food = 0f // don't need more food!
|
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
|
// Focus on non-food/growth
|
||||||
if (surplusFood < 0)
|
if (surplusFood < 0)
|
||||||
yieldStats.food *= 8 // Starving, need Food, get to 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.
|
* 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()
|
val currentTile = unit.getTile()
|
||||||
// Must be called before any getPriority checks to guarantee the local road cache is processed
|
// Must be called before any getPriority checks to guarantee the local road cache is processed
|
||||||
val citiesToConnect = roadBetweenCitiesAutomation.getNearbyCitiesToConnect(unit)
|
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
|
// 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) {
|
&& currentTile.improvementInProgress != null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val tileToWork = findTileToWork(unit, dangerousTiles)
|
val tileToWork = findTileToWork(unit, dangerousTiles, localUniqueCache)
|
||||||
|
|
||||||
if (tileToWork != currentTile) {
|
if (tileToWork != currentTile) {
|
||||||
debug("WorkerAutomation: %s -> head towards %s", unit.toString(), tileToWork)
|
debug("WorkerAutomation: %s -> head towards %s", unit.toString(), tileToWork)
|
||||||
@ -106,7 +106,7 @@ class WorkerAutomation(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (reachedTile.improvementInProgress == null && reachedTile.isLand
|
if (reachedTile.improvementInProgress == null && reachedTile.isLand
|
||||||
&& tileHasWorkToDo(reachedTile, unit)
|
&& tileHasWorkToDo(reachedTile, unit, localUniqueCache)
|
||||||
) {
|
) {
|
||||||
debug("WorkerAutomation: $unit -> start improving $reachedTile")
|
debug("WorkerAutomation: $unit -> start improving $reachedTile")
|
||||||
return reachedTile.startWorkingOnImprovement(tileRankings[reachedTile]!!.bestImprovement!!, civInfo, unit)
|
return reachedTile.startWorkingOnImprovement(tileRankings[reachedTile]!!.bestImprovement!!, civInfo, unit)
|
||||||
@ -117,7 +117,7 @@ class WorkerAutomation(
|
|||||||
|
|
||||||
if (currentTile.improvementInProgress != null) return // we're working!
|
if (currentTile.improvementInProgress != null) return // we're working!
|
||||||
|
|
||||||
if (tileHasWorkToDo(currentTile, unit)) {
|
if (tileHasWorkToDo(currentTile, unit, localUniqueCache)) {
|
||||||
val tileRankings = tileRankings[currentTile]!!
|
val tileRankings = tileRankings[currentTile]!!
|
||||||
if (tileRankings.repairImprovment!!) {
|
if (tileRankings.repairImprovment!!) {
|
||||||
debug("WorkerAutomation: $unit -> repairs $currentTile")
|
debug("WorkerAutomation: $unit -> repairs $currentTile")
|
||||||
@ -140,7 +140,9 @@ class WorkerAutomation(
|
|||||||
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
|
val citiesToNumberOfUnimprovedTiles = HashMap<String, Int>()
|
||||||
for (city in unit.civ.cities) {
|
for (city in unit.civ.cities) {
|
||||||
citiesToNumberOfUnimprovedTiles[city.id] = city.getTiles()
|
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()
|
val closestUndevelopedCity = unit.civ.cities.asSequence()
|
||||||
@ -171,10 +173,10 @@ class WorkerAutomation(
|
|||||||
* Looks for a worthwhile tile to improve
|
* Looks for a worthwhile tile to improve
|
||||||
* @return The current tile if no tile to work was found
|
* @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()
|
val currentTile = unit.getTile()
|
||||||
if (currentTile !in tilesToAvoid && getBasePriority(currentTile, unit) >= 5
|
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
|
return currentTile
|
||||||
}
|
}
|
||||||
val workableTilesCenterFirst = currentTile.getTilesInDistance(4)
|
val workableTilesCenterFirst = currentTile.getTilesInDistance(4)
|
||||||
@ -197,10 +199,10 @@ class WorkerAutomation(
|
|||||||
var bestTile: Tile? = null
|
var bestTile: Tile? = null
|
||||||
for (tileInGroup in tilePriorityGroup.value.sortedBy { unit.getTile().aerialDistanceTo(it) }) {
|
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.
|
// 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.getTile() == tileInGroup) return unit.getTile()
|
||||||
if (!unit.movement.canReach(tileInGroup)) continue
|
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
|
bestTile = tileInGroup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,23 +254,23 @@ class WorkerAutomation(
|
|||||||
/**
|
/**
|
||||||
* Calculates the priority building the improvement on the tile
|
* 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)
|
getBasePriority(tile, unit)
|
||||||
val rank = tileRankings[tile]
|
val rank = tileRankings[tile]
|
||||||
if(rank!!.improvementPriority == null) {
|
if (rank!!.improvementPriority == null) {
|
||||||
// All values of rank have to be initialized
|
// All values of rank have to be initialized
|
||||||
rank.improvementPriority = -100f
|
rank.improvementPriority = -100f
|
||||||
rank.bestImprovement = null
|
rank.bestImprovement = null
|
||||||
rank.repairImprovment = false
|
rank.repairImprovment = false
|
||||||
|
|
||||||
val bestImprovement = chooseImprovement(unit, tile)
|
val bestImprovement = chooseImprovement(unit, tile, localUniqueCache)
|
||||||
if (bestImprovement != null) {
|
if (bestImprovement != null) {
|
||||||
rank.bestImprovement = bestImprovement
|
rank.bestImprovement = bestImprovement
|
||||||
// Increased priority if the improvement has been worked on longer
|
// Increased priority if the improvement has been worked on longer
|
||||||
val timeSpentPriority = if (tile.improvementInProgress == bestImprovement.name)
|
val timeSpentPriority = if (tile.improvementInProgress == bestImprovement.name)
|
||||||
bestImprovement.getTurnsToBuild(unit.civ,unit) - tile.turnsToImprovement else 0
|
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) {
|
if (tile.improvement != null && tile.isPillaged() && tile.owningCity != null) {
|
||||||
@ -293,15 +295,15 @@ class WorkerAutomation(
|
|||||||
/**
|
/**
|
||||||
* Calculates the full priority of the tile
|
* Calculates the full priority of the tile
|
||||||
*/
|
*/
|
||||||
private fun getFullPriority(tile: Tile, unit: MapUnit): Float {
|
private fun getFullPriority(tile: Tile, unit: MapUnit, localUniqueCache: LocalUniqueCache): Float {
|
||||||
return getBasePriority(tile, unit) + getImprovementPriority(tile, unit)
|
return getBasePriority(tile, unit) + getImprovementPriority(tile, unit, localUniqueCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the best improvement
|
* Returns the best improvement
|
||||||
*/
|
*/
|
||||||
private fun tileHasWorkToDo(tile: Tile, unit: MapUnit): Boolean {
|
private fun tileHasWorkToDo(tile: Tile, unit: MapUnit, localUniqueCache: LocalUniqueCache): Boolean {
|
||||||
if (getImprovementPriority(tile, unit) <= 0) return false
|
if (getImprovementPriority(tile, unit, localUniqueCache) <= 0) return false
|
||||||
if (!(tileRankings[tile]!!.bestImprovement != null || tileRankings[tile]!!.repairImprovment!!))
|
if (!(tileRankings[tile]!!.bestImprovement != null || tileRankings[tile]!!.repairImprovment!!))
|
||||||
throw IllegalStateException("There was an improvementPriority > 0 and nothing to do")
|
throw IllegalStateException("There was an improvementPriority > 0 and nothing to do")
|
||||||
return true
|
return true
|
||||||
@ -311,7 +313,7 @@ class WorkerAutomation(
|
|||||||
* Determine the improvement appropriate to a given tile and worker
|
* Determine the improvement appropriate to a given tile and worker
|
||||||
* Returns null if
|
* 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
|
// 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!!]
|
if (tile.improvementInProgress != null) return ruleSet.tileImprovements[tile.improvementInProgress!!]
|
||||||
|
|
||||||
@ -322,8 +324,6 @@ class WorkerAutomation(
|
|||||||
}
|
}
|
||||||
if (potentialTileImprovements.isEmpty()) return null
|
if (potentialTileImprovements.isEmpty()) return null
|
||||||
|
|
||||||
val localUniqueCache = LocalUniqueCache()
|
|
||||||
|
|
||||||
var bestBuildableImprovement = potentialTileImprovements.values.asSequence()
|
var bestBuildableImprovement = potentialTileImprovements.values.asSequence()
|
||||||
.map { Pair(it, getImprovementRanking(tile, unit, it.name, localUniqueCache)) }
|
.map { Pair(it, getImprovementRanking(tile, unit, it.name, localUniqueCache)) }
|
||||||
.filter { it.second > 0f }
|
.filter { it.second > 0f }
|
||||||
@ -410,7 +410,7 @@ class WorkerAutomation(
|
|||||||
newTile.removeTerrainFeature(removedFeature)
|
newTile.removeTerrainFeature(removedFeature)
|
||||||
if (removedImprovement != null)
|
if (removedImprovement != null)
|
||||||
newTile.removeImprovement()
|
newTile.removeImprovement()
|
||||||
val wantedFinalImprovement = chooseImprovement(unit, newTile)
|
val wantedFinalImprovement = chooseImprovement(unit, newTile, localUniqueCache)
|
||||||
if (wantedFinalImprovement != null)
|
if (wantedFinalImprovement != null)
|
||||||
stats.add(newTile.stats.getStatDiffForImprovement(wantedFinalImprovement, civInfo, newTile.getCity(), localUniqueCache))
|
stats.add(newTile.stats.getStatDiffForImprovement(wantedFinalImprovement, civInfo, newTile.getCity(), localUniqueCache))
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,8 @@ enum class CityFocus(
|
|||||||
|
|
||||||
fun applyWeightTo(stats: Stats) {
|
fun applyWeightTo(stats: Stats) {
|
||||||
for (stat in Stat.values()) {
|
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
|
// set used in Automation. All non-Food Focuses, so targets 0 Surplus Food
|
||||||
fun zeroFoodFocuses(): Set<CityFocus> {
|
val zeroFoodFocuses = setOf(
|
||||||
return setOf(
|
CultureFocus, FaithFocus, GoldFocus,
|
||||||
CultureFocus, FaithFocus, GoldFocus,
|
HappinessFocus, ProductionFocus, ScienceFocus
|
||||||
HappinessFocus, ProductionFocus, ScienceFocus
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user