From 7400f6e8744d2b72faf83930729d2efa5d012157 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Thu, 2 May 2019 23:15:22 +0300 Subject: [PATCH] Performance boost - moved TileInfo.isLand and .isWater to transient bools instead of functions, since the base terrain doesn't change isBarbarianCivilization performance boost - called A LOT! --- core/src/com/unciv/GameStarter.kt | 4 ++-- core/src/com/unciv/logic/automation/Automation.kt | 2 +- .../logic/automation/SpecificUnitAutomation.kt | 6 +++--- .../com/unciv/logic/automation/UnitAutomation.kt | 6 +++--- .../com/unciv/logic/automation/WorkerAutomation.kt | 6 +++--- .../unciv/logic/civilization/CivilizationInfo.kt | 4 ++-- core/src/com/unciv/logic/map/MapUnit.kt | 4 ++-- core/src/com/unciv/logic/map/RandomMapGenerator.kt | 4 ++-- core/src/com/unciv/logic/map/TileInfo.kt | 13 ++++++++----- core/src/com/unciv/logic/map/TileMap.kt | 2 +- .../com/unciv/logic/map/UnitMovementAlgorithms.kt | 4 ++-- core/src/com/unciv/ui/worldscreen/Minimap.kt | 4 ++-- .../com/unciv/ui/worldscreen/unit/UnitActions.kt | 2 +- 13 files changed, 32 insertions(+), 29 deletions(-) diff --git a/core/src/com/unciv/GameStarter.kt b/core/src/com/unciv/GameStarter.kt index e8e2d6fdcd..d0ff73964a 100644 --- a/core/src/com/unciv/GameStarter.kt +++ b/core/src/com/unciv/GameStarter.kt @@ -84,11 +84,11 @@ class GameStarter{ fun getStartingLocations(numberOfPlayers:Int,tileMap: TileMap): Stack { var landTiles = tileMap.values - .filter { it.isLand() && !it.getBaseTerrain().impassable } + .filter { it.isLand && !it.getBaseTerrain().impassable } val landTilesInBigEnoughGroup = ArrayList() while(landTiles.any()){ - val bfs = BFS(landTiles.random()){it.isLand() && !it.getBaseTerrain().impassable} + val bfs = BFS(landTiles.random()){it.isLand && !it.getBaseTerrain().impassable} bfs.stepToEnd() val tilesInGroup = bfs.tilesReached.keys landTiles = landTiles.filter { it !in tilesInGroup } diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 5d0d12ce1e..ada8c055d4 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -81,7 +81,7 @@ class Automation { val canBuildWorkboat = cityInfo.cityConstructions.getConstructableUnits().map { it.name }.contains("Work Boats") && !cityInfo.getTiles().any { it.civilianUnit?.name == "Work Boats" } val needWorkboat = canBuildWorkboat - && cityInfo.getTiles().any { it.isWater() && it.hasViewableResource(cityInfo.civInfo) && it.improvement == null } + && cityInfo.getTiles().any { it.isWater && it.hasViewableResource(cityInfo.civInfo) && it.improvement == null } val isAtWar = cityInfo.civInfo.isAtWar() diff --git a/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt b/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt index 29e7579165..c1bd4295f3 100644 --- a/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/SpecificUnitAutomation.kt @@ -11,7 +11,7 @@ import com.unciv.ui.worldscreen.unit.UnitActions class SpecificUnitAutomation{ private fun hasWorkableSeaResource(tileInfo: TileInfo, civInfo: CivilizationInfo): Boolean { - return tileInfo.hasViewableResource(civInfo) && tileInfo.isWater() && tileInfo.improvement==null + return tileInfo.hasViewableResource(civInfo) && tileInfo.isWater && tileInfo.improvement==null } fun automateWorkBoats(unit: MapUnit) { @@ -88,7 +88,7 @@ class SpecificUnitAutomation{ .associateBy ( {it},{ Automation().rankTile(it,unit.civInfo) }) val possibleCityLocations = unit.getTile().getTilesInDistance(5) - .filter { (unit.canMoveTo(it) || unit.currentTile==it) && it !in tilesNearCities && it.isLand() } + .filter { (unit.canMoveTo(it) || unit.currentTile==it) && it !in tilesNearCities && it.isLand } val bestCityLocation: TileInfo? = possibleCityLocations .asSequence() @@ -131,7 +131,7 @@ class SpecificUnitAutomation{ // if we got here, we're pretty close, start looking! val tiles = city.getTiles().asSequence() .filter { (unit.canMoveTo(it) || unit.currentTile==it) - && it.isLand() + && it.isLand && !it.isCityCenter() && it.resource==null } .sortedByDescending { Automation().rankTile(it,unit.civInfo) }.toList() diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index bd75751c25..571657ac74 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -121,9 +121,9 @@ class UnitAutomation{ if(combatant is MapUnitCombatant){ if (combatant.unit.isEmbarked()) { if (combatant.isRanged()) return false - if (tile.isWater()) return false // can't attack water units while embarked, only land + if (tile.isWater) return false // can't attack water units while embarked, only land } - if (combatant.unit.hasUnique("Can only attack water") && tile.isLand()) return false + if (combatant.unit.hasUnique("Can only attack water") && tile.isLand) return false } val tileCombatant = Battle(combatant.getCivInfo().gameInfo).getMapCombatantOfTile(tile) @@ -286,7 +286,7 @@ class UnitAutomation{ BattleDamage().calculateDamageToAttacker(MapUnitCombatant(unit), Battle(unit.civInfo.gameInfo).getMapCombatantOfTile(it.tileToAttack)!!) < unit.health } - .filter {it.tileToAttackFrom.isLand()} + .filter {it.tileToAttackFrom.isLand} val enemyTileToAttackNextTurn = chooseAttackTarget(unit, attackableEnemiesNextTurn) diff --git a/core/src/com/unciv/logic/automation/WorkerAutomation.kt b/core/src/com/unciv/logic/automation/WorkerAutomation.kt index 950c78a92f..9b5362be18 100644 --- a/core/src/com/unciv/logic/automation/WorkerAutomation.kt +++ b/core/src/com/unciv/logic/automation/WorkerAutomation.kt @@ -29,7 +29,7 @@ class WorkerAutomation(val unit: MapUnit) { if(reachedTile!=tile) unit.doPreTurnAction() // otherwise, we get a situation where the worker is automated, so it tries to move but doesn't, then tries to automate, then move, etc, forever. Stack overflow exception! return } - if (tile.improvementInProgress == null && tile.isLand()) { + if (tile.improvementInProgress == null && tile.isLand) { val improvement = chooseImprovement(tile, unit.civInfo) if (improvement != null && tile.canBuildImprovement(improvement, unit.civInfo)) { // What if we're stuck on this tile but can't build there? @@ -56,7 +56,7 @@ class WorkerAutomation(val unit: MapUnit) { if(citiesThatNeedConnecting.isEmpty()) return false // do nothing. val citiesThatNeedConnectingBfs = citiesThatNeedConnecting - .map { city -> BFS(city.getCenterTile()){it.isLand() && unit.canPassThrough(it)} } + .map { city -> BFS(city.getCenterTile()){it.isLand && unit.canPassThrough(it)} } .toMutableList() val connectedCities = unit.civInfo.cities.filter { it.isCapital() || it.cityStats.isConnectedToCapital(targetStatus) } @@ -100,7 +100,7 @@ class WorkerAutomation(val unit: MapUnit) { .filter { (it.civilianUnit== null || it == currentTile) && (it.improvement == null || (it.hasViewableResource(unit.civInfo) && !it.containsGreatImprovement() && it.getTileResource().improvement != it.improvement)) - && it.isLand() + && it.isLand && !it.getBaseTerrain().impassable && (it.containsUnfinishedGreatImprovement() || it.canBuildImprovement(chooseImprovement(it, unit.civInfo), unit.civInfo)) && {val city=it.getCity(); city==null || it.getCity()?.civInfo == unit.civInfo}() // don't work tiles belonging to another civ diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 06db40e528..660f005930 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -130,7 +130,7 @@ class CivilizationInfo { fun getCapital()=cities.first { it.isCapital() } fun isPlayerCivilization() = playerType==PlayerType.Human fun isCurrentPlayer() = gameInfo.getCurrentPlayerCivilization()==this - fun isBarbarianCivilization() = gameInfo.getBarbarianCivilization()==this + fun isBarbarianCivilization() = civName=="Barbarians" fun isCityState(): Boolean = getNation().isCityState() fun isMajorCiv() = !isBarbarianCivilization() && !isCityState() fun getStatsForNextTurn():Stats = getStatMapForNextTurn().values.toList().reduce{a,b->a+b} @@ -507,7 +507,7 @@ class CivilizationInfo { if(!reachedMediums.contains("Harbor") && cityToConnectFrom.cityConstructions.containsBuildingOrEquivalent("Harbor")){ - val seaBfs = BFS(cityToConnectFrom.getCenterTile()){it.isWater() || it.isCityCenter()} + val seaBfs = BFS(cityToConnectFrom.getCenterTile()){it.isWater || it.isCityCenter()} seaBfs.stepToEnd() val reachedCities = cities.filter { seaBfs.tilesReached.containsKey(it.getCenterTile())} for(reachedCity in reachedCities){ diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index aba649ab0d..f95b33055d 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -133,11 +133,11 @@ class MapUnit { fun canPassThrough(tile: TileInfo):Boolean{ if(tile.getBaseTerrain().impassable) return false - if(tile.isLand() && type.isWaterUnit() && !tile.isCityCenter()) + if(tile.isLand && type.isWaterUnit() && !tile.isCityCenter()) return false val isOcean = tile.baseTerrain == "Ocean" - if(tile.isWater() && type.isLandUnit()){ + if(tile.isWater && type.isLandUnit()){ if(!civInfo.tech.unitsCanEmbark) return false if(isOcean && !civInfo.tech.embarkedUnitsCanEnterOcean) return false diff --git a/core/src/com/unciv/logic/map/RandomMapGenerator.kt b/core/src/com/unciv/logic/map/RandomMapGenerator.kt index 1a148415ae..aeeeb05c96 100644 --- a/core/src/com/unciv/logic/map/RandomMapGenerator.kt +++ b/core/src/com/unciv/logic/map/RandomMapGenerator.kt @@ -126,7 +126,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() { override fun setWaterTiles(map: HashMap) { //define lakes - var waterTiles = map.values.filter { it.isWater() }.map { it.position } + var waterTiles = map.values.filter { it.isWater }.map { it.position } val tilesInArea = ArrayList() val tilesToCheck = ArrayList() while (waterTiles.isNotEmpty()) { @@ -530,7 +530,7 @@ open class RandomMapGenerator { val suitableTiles = mapToReturn.values .filter { it.resource==null && resource.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } - val numberOfResources = mapToReturn.values.count{it.isLand() && !it.getBaseTerrain().impassable} / 50 + val numberOfResources = mapToReturn.values.count{it.isLand && !it.getBaseTerrain().impassable} / 50 val locations = chooseSpreadOutLocations(numberOfResources,suitableTiles, distance) diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index d5931cdada..d030930406 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -15,6 +15,10 @@ open class TileInfo { @Transient var owningCity:CityInfo?=null @Transient private lateinit var baseTerrainObject:Terrain + // These are for performance - checked with every tile movement and "canEnter" check, which makes them performance-critical + @Transient var isLand = false + @Transient var isWater = false + var militaryUnit:MapUnit?=null var civilianUnit:MapUnit?=null @@ -110,9 +114,6 @@ open class TileInfo { return city!=null && city.workedTiles.contains(position) } - fun isLand() = getBaseTerrain().type==TerrainType.Land - fun isWater() = getBaseTerrain().type==TerrainType.Water - fun getTileStats(observingCiv: CivilizationInfo): Stats { return getTileStats(getCity(), observingCiv) } @@ -151,7 +152,7 @@ open class TileInfo { if(resource.name=="Oil" && city!=null && city.getBuildingUniques().contains("+2 Gold for each source of Oil and oasis")) stats.gold += 2 - if(city!=null && isWater()){ + if(city!=null && isWater){ if(city.getBuildingUniques().contains("+1 production from all sea resources worked by the city")) stats.production+=1 if(city.getBuildingUniques().contains("+1 production and gold from all sea resources worked by the city")){ @@ -175,7 +176,7 @@ open class TileInfo { stats.add(improvement) // again, for the double effect } - if(city!=null && isWater() && city.getBuildingUniques().contains("+1 gold from worked water tiles in city")) + if(city!=null && isWater && city.getBuildingUniques().contains("+1 gold from worked water tiles in city")) stats.gold += 1 if (isCityCenter()) { @@ -279,6 +280,8 @@ open class TileInfo { //region state-changing functions fun setTransients(){ baseTerrainObject = GameBasics.Terrains[baseTerrain]!! + isWater = getBaseTerrain().type==TerrainType.Water + isLand = getBaseTerrain().type==TerrainType.Land if(militaryUnit!=null) militaryUnit!!.currentTile = this if(civilianUnit!=null) civilianUnit!!.currentTile = this diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 9d787673fb..4201994223 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -77,7 +77,7 @@ class TileMap { val unit = GameBasics.Units[unitName]!!.getMapUnit() 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 - var unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) && (unit.type.isWaterUnit() || it.isLand()) } + var unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) && (unit.type.isWaterUnit() || it.isLand) } if (unitToPlaceTile==null) unitToPlaceTile = tilesInDistance.firstOrNull { unit.canMoveTo(it) } diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 7edc2a4b85..b4b72cc8b3 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -10,14 +10,14 @@ class UnitMovementAlgorithms(val unit:MapUnit) { var cost = getMovementCostBetweenAdjacentTiles(from,to) val toOwner = to.getOwner() - if(toOwner!=null && to.isLand() && civInfo.isAtWarWith(toOwner) && toOwner.hasActiveGreatWall) + if(toOwner!=null && to.isLand && civInfo.isAtWarWith(toOwner) && toOwner.hasActiveGreatWall) cost += 1 return cost } private fun getMovementCostBetweenAdjacentTiles(from: TileInfo, to: TileInfo): Float { - if(unit.type.isLandUnit() && (from.isLand() != to.isLand())) + if(unit.type.isLandUnit() && (from.isLand != to.isLand)) return 100f // this is embarkment or disembarkment, and will take the entire turn if (from.roadStatus === RoadStatus.Railroad && to.roadStatus === RoadStatus.Railroad) diff --git a/core/src/com/unciv/ui/worldscreen/Minimap.kt b/core/src/com/unciv/ui/worldscreen/Minimap.kt index e6d19d28d5..472cef5151 100644 --- a/core/src/com/unciv/ui/worldscreen/Minimap.kt +++ b/core/src/com/unciv/ui/worldscreen/Minimap.kt @@ -78,9 +78,9 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){ val hex = tileImages[tileInfo]!! if (!(UnCivGame.Current.viewEntireMapForDebug || exploredTiles.contains(tileInfo.position))) hex.color = Color.BLACK - else if (tileInfo.isCityCenter() && !tileInfo.isWater()) + else if (tileInfo.isCityCenter() && !tileInfo.isWater) hex.color = tileInfo.getOwner()!!.getNation().getSecondaryColor() - else if (tileInfo.getCity() != null && !tileInfo.isWater()) + else if (tileInfo.getCity() != null && !tileInfo.isWater) hex.color = tileInfo.getOwner()!!.getNation().getColor() else hex.color = tileInfo.getBaseTerrain().getColor().lerp(Color.GRAY, 0.5f) } diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index f5d27327f7..7b52ebb60d 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -94,7 +94,7 @@ class UnitActions { { // http://well-of-souls.com/civ/civ5_improvements.html says that naval improvements are destroyed upon pilllage // and I can't find any other sources so I'll go with that - if(tile.isLand()) { + if(tile.isLand) { tile.improvementInProgress = tile.improvement tile.turnsToImprovement = 2 }