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!
This commit is contained in:
Yair Morgenstern 2019-05-02 23:15:22 +03:00
parent 827d24c778
commit 7400f6e874
13 changed files with 32 additions and 29 deletions

View File

@ -84,11 +84,11 @@ class GameStarter{
fun getStartingLocations(numberOfPlayers:Int,tileMap: TileMap): Stack<TileInfo> {
var landTiles = tileMap.values
.filter { it.isLand() && !it.getBaseTerrain().impassable }
.filter { it.isLand && !it.getBaseTerrain().impassable }
val landTilesInBigEnoughGroup = ArrayList<TileInfo>()
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 }

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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){

View File

@ -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

View File

@ -126,7 +126,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
override fun setWaterTiles(map: HashMap<String, TileInfo>) {
//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<Vector2>()
val tilesToCheck = ArrayList<Vector2>()
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)

View File

@ -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

View File

@ -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) }

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}