Huge performance boost for time of "next turn"

This commit is contained in:
Yair Morgenstern 2018-09-25 22:03:53 +03:00
parent d22da73636
commit 833760ab32
10 changed files with 48 additions and 22 deletions

View File

@ -23,7 +23,6 @@ class GameInfo {
toReturn.civilizations.addAll(civilizations.map { it.clone() }) toReturn.civilizations.addAll(civilizations.map { it.clone() })
toReturn.notifications.addAll(notifications) toReturn.notifications.addAll(notifications)
toReturn.turns=turns toReturn.turns=turns
toReturn.setTransients()
return toReturn return toReturn
} }

View File

@ -177,6 +177,7 @@ class UnitAutomation{
private fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean { private fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean {
if(unit.civInfo.cities.isEmpty()) return false if(unit.civInfo.cities.isEmpty()) return false
var enemyCities = unit.civInfo.gameInfo.civilizations.filter { unit.civInfo.isAtWarWith(it) } var enemyCities = unit.civInfo.gameInfo.civilizations.filter { unit.civInfo.isAtWarWith(it) }
.flatMap { it.cities }.filter { it.location in unit.civInfo.exploredTiles }.map { it.getCenterTile() } .flatMap { it.cities }.filter { it.location in unit.civInfo.exploredTiles }.map { it.getCenterTile() }
if(unit.baseUnit().unitType.isRanged()) if(unit.baseUnit().unitType.isRanged())
@ -234,8 +235,9 @@ class UnitAutomation{
if(unit.baseUnit().unitType.isMelee()) return false // don't garrison melee units, they're not that good at it if(unit.baseUnit().unitType.isMelee()) return false // don't garrison melee units, they're not that good at it
val reachableCitiesWithoutUnits = unit.civInfo.cities.filter { val reachableCitiesWithoutUnits = unit.civInfo.cities.filter {
val centerTile = it.getCenterTile() val centerTile = it.getCenterTile()
unit.canMoveTo(centerTile) centerTile.militaryUnit==null
&& unit.movementAlgs().canReach(centerTile) && unit.canMoveTo(centerTile)
&& unit.movementAlgs().canReach(centerTile)
} }
fun cityThatNeedsDefendingInWartime(city: CityInfo): Boolean { fun cityThatNeedsDefendingInWartime(city: CityInfo): Boolean {
@ -249,6 +251,9 @@ class UnitAutomation{
if (!unit.civInfo.isAtWar()) { if (!unit.civInfo.isAtWar()) {
if (unit.getTile().isCityCenter()) return true // It's always good to have a unit in the city center, so if you haven't found anyone around to attack, forget it. if (unit.getTile().isCityCenter()) return true // It's always good to have a unit in the city center, so if you haven't found anyone around to attack, forget it.
if (reachableCitiesWithoutUnits.isNotEmpty()) { if (reachableCitiesWithoutUnits.isNotEmpty()) {
val closestCity = reachableCitiesWithoutUnits.minBy { it.getCenterTile().arialDistanceTo(unit.currentTile) }!!
unit.movementAlgs().headTowards(closestCity.getCenterTile())
return true
} }
} else { } else {
if (unit.getTile().isCityCenter() && if (unit.getTile().isCityCenter() &&
@ -280,9 +285,6 @@ class UnitAutomation{
} }
else distanceToTiles = unitDistanceToTiles else distanceToTiles = unitDistanceToTiles
val reachableTiles= distanceToTiles
.filter { unit.canMoveTo(it.key) }
for(tile in unit.currentTile.getTilesInDistance(5)) for(tile in unit.currentTile.getTilesInDistance(5))
if(unit.canMoveTo(tile) && tile.position !in unit.civInfo.exploredTiles if(unit.canMoveTo(tile) && tile.position !in unit.civInfo.exploredTiles
&& unit.movementAlgs().canReach(tile)){ && unit.movementAlgs().canReach(tile)){
@ -290,6 +292,10 @@ class UnitAutomation{
return return
} }
val reachableTiles= distanceToTiles
.filter { unit.canMoveTo(it.key) && unit.movementAlgs().canReach(it.key) }
val reachableTilesMaxWalkingDistance = reachableTiles.filter { it.value == unit.currentMovement } val reachableTilesMaxWalkingDistance = reachableTiles.filter { it.value == unit.currentMovement }
if (reachableTilesMaxWalkingDistance.any()) unit.moveToTile(reachableTilesMaxWalkingDistance.toList().getRandom().first) if (reachableTilesMaxWalkingDistance.any()) unit.moveToTile(reachableTilesMaxWalkingDistance.toList().getRandom().first)
else if (reachableTiles.any()) unit.moveToTile(reachableTiles.toList().getRandom().first) else if (reachableTiles.any()) unit.moveToTile(reachableTiles.toList().getRandom().first)
@ -305,7 +311,7 @@ class UnitAutomation{
} }
private fun automateSettlerActions(unit: MapUnit) { private fun automateSettlerActions(unit: MapUnit) {
if(unit.getTile().militaryUnit==null) return // Don;t move until you're accompanied by a military unit if(unit.getTile().militaryUnit==null) return // Don't move until you're accompanied by a military unit
// find best city location within 5 tiles // find best city location within 5 tiles
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities } val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }

View File

@ -54,12 +54,18 @@ class MapUnit {
return movementAlgs().getDistanceToTilesWithinTurn(tile.position,currentMovement) return movementAlgs().getDistanceToTilesWithinTurn(tile.position,currentMovement)
} }
fun getUniques(): MutableList<String> { @Transient var tempUniques: List<String> = ArrayList()
val abilities = mutableListOf<String>()
fun getUniques(): List<String> {
return tempUniques
}
fun updateUniques(){
val uniques = ArrayList<String>()
val baseUnit = baseUnit() val baseUnit = baseUnit()
if(baseUnit.uniques!=null) abilities.addAll(baseUnit.uniques!!) if(baseUnit.uniques!=null) uniques.addAll(baseUnit.uniques!!)
abilities.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect }) uniques.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect })
return abilities tempUniques = uniques
} }
fun hasUnique(unique:String): Boolean { fun hasUnique(unique:String): Boolean {
@ -134,6 +140,7 @@ class MapUnit {
fun setTransients(){ fun setTransients(){
promotions.unit=this promotions.unit=this
baseUnit=GameBasics.Units[name]!! baseUnit=GameBasics.Units[name]!!
updateUniques()
} }
fun doPreTurnAction() { fun doPreTurnAction() {
val currentTile = getTile() val currentTile = getTile()

View File

@ -47,12 +47,16 @@ open class TileInfo {
} }
fun getUnits()= listOf(militaryUnit,civilianUnit).filterNotNull() fun getUnits(): List<MapUnit> {
val list = ArrayList<MapUnit>(2)
if(militaryUnit!=null) list.add(militaryUnit!!)
if(civilianUnit!=null) list.add(civilianUnit!!)
return list
// this used to be "return listOf(militaryUnit,civilianUnit).filterNotNull()" but profiling revealed that that took considerably longer
}
fun getCity(): CityInfo? { fun getCity(): CityInfo? {
return owningCity return owningCity
// return tileMap.gameInfo.tilesToCities.get(this)
//return tileMap.gameInfo.civilizations.flatMap { it.cities }.firstOrNull{it.tiles.contains(position)}
} }
val lastTerrain: Terrain val lastTerrain: Terrain

View File

@ -60,7 +60,6 @@ class TileMap {
fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo): MapUnit { fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo): MapUnit {
val unit = GameBasics.Units[unitName]!!.getMapUnit() val unit = GameBasics.Units[unitName]!!.getMapUnit()
val tilesInDistance = getTilesInDistance(position, 2) val tilesInDistance = getTilesInDistance(position, 2)
unit.assignOwner(civInfo) // both the civ name and actual civ need to be in here in order to calculate the canMoveTo...Darn unit.assignOwner(civInfo) // both the civ name and actual civ need to be in here in order to calculate the canMoveTo...Darn

View File

@ -19,6 +19,7 @@ class UnitPromotions{
XP -= xpForNextPromotion() XP -= xpForNextPromotion()
promotions.add(promotionName) promotions.add(promotionName)
numberOfPromotions++ numberOfPromotions++
unit.updateUniques()
} }
fun getAvailablePromotions(): List<Promotion> { fun getAvailablePromotions(): List<Promotion> {

View File

@ -154,15 +154,16 @@ class Building : NamedStats(), IConstruction{
override fun isBuildable(construction: CityConstructions): Boolean { override fun isBuildable(construction: CityConstructions): Boolean {
if (construction.isBuilt(name)) return false if (construction.isBuilt(name)) return false
val civInfo = construction.cityInfo.civInfo val civInfo = construction.cityInfo.civInfo
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return false
if (GameBasics.Buildings.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return false
if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!)) return false if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!)) return false
if (isWonder && requiredBuildingInAllCities==null if (isWonder && requiredBuildingInAllCities==null
&& civInfo.gameInfo.civilizations.flatMap { it.cities }.any { && civInfo.gameInfo.civilizations.flatMap { it.cities }.any {
it.cityConstructions.isBuilding(name) || it.cityConstructions.isBuilt(name) it.cityConstructions.isBuilding(name) || it.cityConstructions.isBuilt(name)
}) })
return false return false
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return false
if (GameBasics.Buildings.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return false
if (requiredBuilding != null && !construction.isBuilt(requiredBuilding!!) if (requiredBuilding != null && !construction.isBuilt(requiredBuilding!!)
&& construction.getBuiltBuildings().none{it.replaces==requiredBuilding}) return false && construction.getBuiltBuildings().none{it.replaces==requiredBuilding}) return false
if (requiredBuildingInAllCities != null && civInfo.cities.any { !it.cityConstructions.isBuilt(requiredBuildingInAllCities!!) }) if (requiredBuildingInAllCities != null && civInfo.cities.any { !it.cityConstructions.isBuilt(requiredBuildingInAllCities!!) })

View File

@ -76,7 +76,7 @@ class BaseUnit : INamed, IConstruction, ICivilopedia {
fun getMapUnit(): MapUnit { fun getMapUnit(): MapUnit {
val unit = MapUnit() val unit = MapUnit()
unit.name = name unit.name = name
unit.setTransients() // must be after setting name because it sets the bseUnit according to the name unit.setTransients() // must be after setting name because it sets the baseUnit according to the name
unit.currentMovement = unit.getMaxMovement().toFloat() // must be after setTransients because it relies on having the baseUnit set unit.currentMovement = unit.getMaxMovement().toFloat() // must be after setTransients because it relies on having the baseUnit set
return unit return unit
} }

View File

@ -10,13 +10,21 @@ enum class UnitType{
Siege; Siege;
fun isMelee(): Boolean { fun isMelee(): Boolean {
return this in listOf(Melee, Mounted, Scout) return this == Melee
|| this == Mounted
|| this == Scout
} }
fun isRanged(): Boolean { fun isRanged(): Boolean {
return this in listOf(Ranged, Siege) return this == Ranged
|| this == Siege
} }
fun isLandUnit(): Boolean { fun isLandUnit(): Boolean {
return this in listOf(Civilian, Melee, Mounted, Scout, Ranged, Siege) return this == Civilian
|| this == Melee
|| this == Mounted
|| this == Scout
|| this == Ranged
|| this == Siege
} }
} }

View File

@ -88,6 +88,7 @@ class WorldScreen : CameraStageBaseScreen() {
// because that's guaranteed to stay the exact same and so we won't get any concurrent modification exceptions // because that's guaranteed to stay the exact same and so we won't get any concurrent modification exceptions
val gameClone = gameInfo.clone() val gameClone = gameInfo.clone()
gameClone.setTransients()
val cloneCivilization = gameClone.getPlayerCivilization() val cloneCivilization = gameClone.getPlayerCivilization()
kotlin.concurrent.thread { kotlin.concurrent.thread {
civInfo.happiness = gameClone.getPlayerCivilization().getHappinessForNextTurn().values.sum().toInt() civInfo.happiness = gameClone.getPlayerCivilization().getHappinessForNextTurn().values.sum().toInt()