From 033957c73844890713aed147cf9ccbb757660558 Mon Sep 17 00:00:00 2001 From: WhoIsJohannes <126110113+WhoIsJohannes@users.noreply.github.com> Date: Mon, 24 Apr 2023 16:16:43 +0200 Subject: [PATCH] Performance improvements (#9265) * UnitMovement#getDistanceToTilesWithinTurn hotspots * Make fog busting less expensive * Speed up tryHeadTowardsEncampment * Reorder conditions in isGoodTileToExplore * Reorder conditions in isGoodTileToExplore * Revert "Speed up tryHeadTowardsEncampment" This reverts commit d3841a233b0212ea9fd3cf053f70abb090fbc241. * Don't lookup twice. --- .../unciv/logic/automation/unit/UnitAutomation.kt | 13 +++++++++---- .../src/com/unciv/logic/map/mapunit/UnitMovement.kt | 13 ++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt b/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt index 0a5ed3a5ec..a3ff38e7f2 100644 --- a/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt @@ -27,13 +27,12 @@ object UnitAutomation { private const val CLOSE_ENEMY_TURNS_AWAY_LIMIT = 3f private fun isGoodTileToExplore(unit: MapUnit, tile: Tile): Boolean { - return unit.movement.canMoveTo(tile) - && (tile.getOwner() == null || !tile.getOwner()!!.isCityState()) + return (tile.getOwner() == null || !tile.getOwner()!!.isCityState()) && tile.neighbors.any { !unit.civ.hasExplored(it) } && (!unit.civ.isCityState() || tile.neighbors.any { it.getOwner() == unit.civ }) // Don't want city-states exploring far outside their borders && unit.getDamageFromTerrain(tile) <= 0 // Don't take unnecessary damage - && tile.getTilesInDistance(3) // don't walk in range of enemy units - .none { tile_it -> containsEnemyMilitaryUnit(unit, tile_it)} + && tile.getTilesInDistance(3) .none { containsEnemyMilitaryUnit(unit, it) } // don't walk in range of enemy units + && unit.movement.canMoveTo(tile) // expensive, evaluate last && unit.movement.canReach(tile) // expensive, evaluate last } @@ -78,6 +77,12 @@ object UnitAutomation { private fun tryFogBust(unit: MapUnit): Boolean { if (!Automation.afraidOfBarbarians(unit.civ)) return false // Not if we're not afraid + // If everything around this unit is visible, we can stop. + // Calculations below are quite expensive especially in the late game. + if (unit.currentTile.getTilesInDistance(5).any { !it.isVisible(unit.civ) }) { + return false + } + val reachableTilesThisTurn = unit.movement.getDistanceToTiles().keys.filter { isGoodTileForFogBusting(unit, it) } if (reachableTilesThisTurn.any()) { diff --git a/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt b/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt index cbf03a552b..5bae6749dc 100644 --- a/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt +++ b/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt @@ -163,6 +163,9 @@ class UnitMovement(val unit: MapUnit) { distanceToTiles[unitTile] = ParentTileAndTotalDistance(unitTile, unitTile, 0f) var tilesToCheck = listOf(unitTile) + val passThroughCache = HashMap() // Cache for canPassThrough + val movementCostCache = HashMap, Float>() // Cache for getMovementCostBetweenAdjacentTiles + while (tilesToCheck.isNotEmpty()) { val updatedTiles = ArrayList() for (tileToCheck in tilesToCheck) @@ -171,13 +174,17 @@ class UnitMovement(val unit: MapUnit) { var totalDistanceToTile: Float = when { !unit.civ.hasExplored(neighbor) -> distanceToTiles[tileToCheck]!!.totalDistance + 1f // If we don't know then we just guess it to be 1. - !canPassThrough(neighbor) -> unitMovement // Can't go here. + !passThroughCache.getOrPut(neighbor) { canPassThrough(neighbor) } -> unitMovement // Can't go here. // The reason that we don't just "return" is so that when calculating how to reach an enemy, // You need to assume his tile is reachable, otherwise all movement algorithms on reaching enemy // cities and units goes kaput. else -> { - val distanceBetweenTiles = getMovementCostBetweenAdjacentTiles(tileToCheck, neighbor, unit.civ, considerZoneOfControl) - distanceToTiles[tileToCheck]!!.totalDistance + distanceBetweenTiles + val key = Pair(tileToCheck, neighbor) + val movementCost = + movementCostCache.getOrPut(key) { + getMovementCostBetweenAdjacentTiles(tileToCheck, neighbor, unit.civ, considerZoneOfControl) + } + distanceToTiles[tileToCheck]!!.totalDistance + movementCost } }