From 8268c0c5618bcd91e40265dbe7f9497ea344a8b7 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Thu, 26 Apr 2018 23:43:36 +0300 Subject: [PATCH] Fixed settler automation performance problem - now actually viable for phone use All kinds of other small performance-boosting bits and bobs --- core/src/com/unciv/logic/Automation.kt | 20 ++++++++++--------- core/src/com/unciv/logic/WorkerAutomation.kt | 2 +- .../unciv/logic/city/CityExpansionManager.kt | 2 +- core/src/com/unciv/logic/city/CityInfo.kt | 6 +++--- .../logic/civilization/CivilizationInfo.kt | 2 +- .../unciv/logic/civilization/TechManager.kt | 2 +- core/src/com/unciv/logic/map/MapUnit.kt | 2 +- core/src/com/unciv/logic/map/TileInfo.kt | 11 +++++----- .../unciv/logic/map/UnitMovementAlgorithms.kt | 2 +- .../src/com/unciv/ui/cityscreen/CityScreen.kt | 2 +- .../com/unciv/ui/tilegroups/WorldTileGroup.kt | 2 +- .../com/unciv/ui/worldscreen/BattleTable.kt | 2 +- .../unciv/ui/worldscreen/unit/UnitActions.kt | 6 +++--- 13 files changed, 31 insertions(+), 30 deletions(-) diff --git a/core/src/com/unciv/logic/Automation.kt b/core/src/com/unciv/logic/Automation.kt index 891501c2f1..b6110818b4 100644 --- a/core/src/com/unciv/logic/Automation.kt +++ b/core/src/com/unciv/logic/Automation.kt @@ -22,22 +22,22 @@ class Automation { var rank = 0.0f if (stats.food <= 2) rank += stats.food else rank += (2 + (stats.food - 2) / 2f) // 1 point for each food up to 2, from there on half a point - rank += (stats.gold / 2) + rank += stats.gold / 2 rank += stats.production rank += stats.science rank += stats.culture if (tile.improvement == null) rank += 0.5f // improvement potential! - if (tile.resource != null) rank += 1.0f + if (tile.hasViewableResource(civInfo)) rank += 1.0f return rank } - fun rankTileAsCityCenter(tileInfo: TileInfo, civInfo: CivilizationInfo): Float { + fun rankTileAsCityCenter(tileInfo: TileInfo, civInfo: CivilizationInfo, nearbyTileRankings: Map): Float { val bestTilesFromOuterLayer = tileInfo.tileMap.getTilesAtDistance(tileInfo.position,2) - .sortedByDescending { rankTile(it,civInfo) }.take(2) + .sortedByDescending { nearbyTileRankings[it] }.take(2) val top5Tiles = tileInfo.neighbors.union(bestTilesFromOuterLayer) - .sortedByDescending { rankTile(it,civInfo) } + .sortedByDescending { nearbyTileRankings[it] } .take(5) - return top5Tiles.map { rankTile(it,civInfo) }.sum() + return top5Tiles.map { nearbyTileRankings[it]!! }.sum() } fun automateCivMoves(civInfo: CivilizationInfo) { @@ -113,7 +113,7 @@ class Automation { // if there is an attackable unit in the vicinity, attack! val attackableTiles = unit.civInfo.getViewableTiles() - .filter { it.unit != null && it.unit!!.owner != unit.civInfo.civName && !it.isCityCenter }.toHashSet() + .filter { it.unit != null && it.unit!!.owner != unit.civInfo.civName && !it.isCityCenter() }.toHashSet() val distanceToTiles = unit.getDistanceToTiles() val unitTileToAttack = distanceToTiles.keys.firstOrNull { attackableTiles.contains(it) } @@ -170,10 +170,12 @@ class Automation { // find best city location within 5 tiles val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities } .flatMap { it.getCenterTile().getTilesInDistance(2) } + + // This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once. + val nearbyTileRankings = unit.getTile().getTilesInDistance(7).associateBy ( {it},{rankTile(it,unit.civInfo) }) val bestCityLocation = unit.getTile().getTilesInDistance(5) .minus(tilesNearCities) - .sortedByDescending { rankTileAsCityCenter(it, unit.civInfo) } - .first() + .maxBy { rankTileAsCityCenter(it, unit.civInfo, nearbyTileRankings) }!! if (unit.getTile() == bestCityLocation) UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).first { it.name == "Found city" }.action() diff --git a/core/src/com/unciv/logic/WorkerAutomation.kt b/core/src/com/unciv/logic/WorkerAutomation.kt index e54d90eead..85d5985669 100644 --- a/core/src/com/unciv/logic/WorkerAutomation.kt +++ b/core/src/com/unciv/logic/WorkerAutomation.kt @@ -30,8 +30,8 @@ public class WorkerAutomation(){ .filter { (it.unit == null || it == currentTile) && it.improvement == null - && (it.getCity()==null || it.getCity()!!.civInfo == civInfo) // don't work tiles belonging to another civ && it.canBuildImprovement(chooseImprovement(it), civInfo) + && {val city=it.getCity(); city==null || it.getCity()?.civInfo == civInfo}() // don't work tiles belonging to another civ && UnitMovementAlgorithms(currentTile.tileMap) // the tile is actually reachable - more difficult than it seems! .getShortestPath(currentTile.position, it.position, 2f, 2, civInfo).isNotEmpty() } diff --git a/core/src/com/unciv/logic/city/CityExpansionManager.kt b/core/src/com/unciv/logic/city/CityExpansionManager.kt index df6c562adb..2cb24d130c 100644 --- a/core/src/com/unciv/logic/city/CityExpansionManager.kt +++ b/core/src/com/unciv/logic/city/CityExpansionManager.kt @@ -9,7 +9,7 @@ class CityExpansionManager { var cultureStored: Int = 0 fun reset() { - cityInfo.tiles = ArrayList(cityInfo.getCenterTile().getTilesInDistance(1).map { it.position }) + cityInfo.tiles = cityInfo.getCenterTile().getTilesInDistance(1).map { it.position }.toHashSet() } // This one has conflicting sources - diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 890de5d3a9..554eb9735b 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -23,8 +23,8 @@ class CityInfo { var expansion = CityExpansionManager() var cityStats = CityStats() - var tiles = ArrayList() - var workedTiles = ArrayList() + var tiles = HashSet() + var workedTiles = HashSet() internal val tileMap: TileMap @@ -42,7 +42,7 @@ class CityInfo { for (tileInfo in getTilesInRange().filter { it.resource != null }) { val resource = tileInfo.tileResource - if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter) + if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter()) cityResources.add(resource, 1) } diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index d6b1b59152..2c24e575fd 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -74,7 +74,7 @@ class CivilizationInfo { private fun getTransportationUpkeep(): Int { var transportationUpkeep = 0 - for (it in gameInfo.tileMap.values.filterNot { it.isCityCenter }) { + for (it in gameInfo.tileMap.values.filterNot { it.isCityCenter() }) { when(it.roadStatus) { RoadStatus.Road -> transportationUpkeep += 1 RoadStatus.Railroad -> transportationUpkeep += 2 diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 0451265081..f565b018a5 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -62,7 +62,7 @@ class TechManager { .filter { it.resource == revealedResource.name && civInfo == it.getOwner() }) { val closestCityTile = tileInfo.getTilesInDistance(4) - .firstOrNull { it.isCityCenter } + .firstOrNull { it.isCityCenter() } if (closestCityTile != null) { civInfo.addNotification( revealedResource.name + " revealed near " + closestCityTile.getCity()!!.name, tileInfo.position) diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index b1ccbac4dd..5231793a70 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -113,7 +113,7 @@ class MapUnit { private fun heal(){ val tile = getTile() health += when{ - tile.isCityCenter -> 20 + tile.isCityCenter() -> 20 tile.getOwner()?.civName == owner -> 15 // home territory tile.getOwner() == null -> 10 // no man's land (neutral) else -> 5 // enemy territory diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index c5c498526b..5da1a45caa 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -32,8 +32,7 @@ class TileInfo { val tileResource: TileResource get() = if (resource == null) throw Exception("No resource exists for this tile!") else GameBasics.TileResources[resource!!]!! - val isCityCenter: Boolean - get() = getCity() != null && position == getCity()!!.location + fun isCityCenter(): Boolean = getCity()?.location == position val tileImprovement: TileImprovement? get() = if (improvement == null) null else GameBasics.TileImprovements[improvement!!] @@ -101,7 +100,7 @@ class TileInfo { stats.add(improvement) // again, for the double effect } - if (isCityCenter) { + if (isCityCenter()) { if (stats.food < 2) stats.food = 2f if (stats.production < 1) stats.production = 1f } @@ -118,7 +117,7 @@ class TileInfo { } fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean { - if (isCityCenter || improvement.name == this.improvement) return false + if (isCityCenter() || improvement.name == this.improvement) return false val topTerrain = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature() if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!)) return false if (improvement.terrainsCanBeBuiltOn.contains(topTerrain!!.name)) return true @@ -141,14 +140,14 @@ class TileInfo { override fun toString(): String { val SB = StringBuilder() - if (isCityCenter) { + if (isCityCenter()) { val city = getCity()!! SB.appendln(city.name+ ",\r\n" + city.cityConstructions.getProductionForTileInfo()) } SB.appendln(this.baseTerrain) if (terrainFeature != null) SB.appendln(terrainFeature!!) if (hasViewableResource(tileMap.gameInfo.getPlayerCivilization())) SB.appendln(resource!!) - if (roadStatus !== RoadStatus.None && !isCityCenter) SB.appendln(roadStatus) + if (roadStatus !== RoadStatus.None && !isCityCenter()) SB.appendln(roadStatus) if (improvement != null) SB.appendln(improvement!!) if (improvementInProgress != null) SB.appendln("$improvementInProgress in ${this.turnsToImprovement} turns") if (unit != null && UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this)){ diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 3036ebb214..386c29aee8 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -16,7 +16,7 @@ class UnitMovementAlgorithms(val tileMap: TileMap){ val updatedTiles = ArrayList() for (tileToCheck in tilesToCheck) for (maybeUpdatedTile in tileToCheck.neighbors) { - if(maybeUpdatedTile.getOwner() != null && maybeUpdatedTile.getOwner() != civInfo && maybeUpdatedTile.isCityCenter) + if(maybeUpdatedTile.getOwner() != null && maybeUpdatedTile.getOwner() != civInfo && maybeUpdatedTile.isCityCenter()) continue // Enemy city, can't move through it! var distanceBetweenTiles = maybeUpdatedTile.lastTerrain.movementCost.toFloat() // no road diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index d5ace9a99a..f908483d50 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -163,7 +163,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() { if (tileInfo.getCity()!=city) { group.setColor(0f, 0f, 0f, 0.3f) group.yieldGroup.isVisible = false - } else if (!tileInfo.isCityCenter) { + } else if (!tileInfo.isCityCenter()) { group.addPopulationIcon() group.populationImage!!.addClickListener { if (!tileInfo.isWorked() && cityInfo.population.getFreePopulation() > 0) diff --git a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt index 1f2c385442..c6ecb51277 100644 --- a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt @@ -55,7 +55,7 @@ class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) { if (tileInfo.isWorked() && city!!.civInfo.isPlayerCivilization() && populationImage == null) addPopulationIcon() - if (city != null && tileInfo.isCityCenter) { + if (city != null && tileInfo.isCityCenter()) { if (cityButton == null) { cityButton = Table() cityButton!!.background = ImageGetter.getDrawable("skin/civTableBackground.png") diff --git a/core/src/com/unciv/ui/worldscreen/BattleTable.kt b/core/src/com/unciv/ui/worldscreen/BattleTable.kt index 5782897095..5acb12d024 100644 --- a/core/src/com/unciv/ui/worldscreen/BattleTable.kt +++ b/core/src/com/unciv/ui/worldscreen/BattleTable.kt @@ -31,7 +31,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() { val selectedTile = worldScreen.tileMapHolder.selectedTile!! val defender: ICombatant if (attacker.getCivilization().exploredTiles.contains(selectedTile.position) - && selectedTile.isCityCenter && selectedTile.getOwner() != worldScreen.civInfo) + && selectedTile.isCityCenter() && selectedTile.getOwner() != worldScreen.civInfo) defender = CityCombatant(selectedTile.getCity()!!) else if (selectedTile.unit != null && selectedTile.unit!!.owner != worldScreen.civInfo.civName // enemy unit on selected tile, diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 3dab58d43f..3ad26290b9 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -66,7 +66,7 @@ class UnitActions { worldScreen.update() }, unit.currentMovement != 0f && - !tile.getTilesInDistance(2).any { it.isCityCenter }) + !tile.getTilesInDistance(2).any { it.isCityCenter() }) } if (unit.name == "Worker") { @@ -76,7 +76,7 @@ class UnitActions { actionList += UnitAction(improvementButtonText, { worldScreen.game.screen = ImprovementPickerScreen(tile) }, unit.currentMovement != 0f && - !tile.isCityCenter || GameBasics.TileImprovements.values.any { tile.canBuildImprovement(it, unit.civInfo) }) + !tile.isCityCenter() || GameBasics.TileImprovements.values.any { tile.canBuildImprovement(it, unit.civInfo) }) if("automation" == unit.action){ actionList += UnitAction("Stop automation", @@ -123,7 +123,7 @@ class UnitActions { tile.unit = null // destroy! }, unit.currentMovement != 0f && - tile.isCityCenter && + tile.isCityCenter() && tile.getCity()!!.cityConstructions.getCurrentConstruction() is Building && (tile.getCity()!!.cityConstructions.getCurrentConstruction() as Building).isWonder)