From c70d315fae63ffa7f6a78d3b274c8522e1a2f4c8 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Fri, 8 Oct 2021 15:40:19 +0300 Subject: [PATCH] Resolved #5435 - optimized units seeing invisible tiles. @SomeTroglodyte @xlenstra - the problem was with MapUnit.matchesFilter calling hasUnique, which called civInfo.getUniques, which is patently ridiculous. I checked ALL usages of getUniques, and only found ONE unique which conceivably could be applied both globally and individually, and separated the check there. Current analysis shows that updating viewable tiles still takes much longer than I'd like it to, but not, like, 70% of "next turn" runtime. Next target - tileInfo.getHeight, which clocks in at around 10% (!!!) of next turn! Apparently the annual "we added too many new features and need to optimize" time has come again... --- .../civilization/CivInfoTransientUpdater.kt | 33 +++++++++++-------- core/src/com/unciv/logic/map/MapUnit.kt | 11 +++---- .../unciv/models/ruleset/unique/UniqueType.kt | 1 + .../unciv/ui/worldscreen/unit/UnitActions.kt | 2 +- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt index b54b60efc2..79130016ce 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt @@ -2,6 +2,7 @@ package com.unciv.logic.civilization import com.unciv.logic.map.TileInfo import com.unciv.models.ruleset.tile.ResourceSupplyList +import com.unciv.models.ruleset.unique.UniqueType /** CivInfo class was getting too crowded */ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) { @@ -10,20 +11,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) { fun updateViewableTiles() { setNewViewableTiles() - val newViewableInvisibleTiles = HashSet() - newViewableInvisibleTiles.addAll(civInfo.getCivUnits() - .filter { attacker -> attacker.hasUnique("Can see invisible [] units") } - .flatMap { attacker -> - attacker.viewableTiles - .asSequence() - .filter { tile -> - tile.militaryUnit != null - && attacker.getMatchingUniques("Can see invisible [] units") - .any { unique -> tile.militaryUnit!!.matchesFilter(unique.params[0]) } - } - } - ) - civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles + updateViewableInvisibleTiles() // updating the viewable tiles also affects the explored tiles, obviously. @@ -56,6 +44,23 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) { } } + private fun updateViewableInvisibleTiles() { + val newViewableInvisibleTiles = HashSet() + for (unit in civInfo.getCivUnits()) { + val invisibleUnitUniques = unit.getMatchingUniques(UniqueType.CanSeeInvisibleUnits) + if (invisibleUnitUniques.none()) continue + val visibleUnitTypes = invisibleUnitUniques.map { it.params[0] } + .toList() // save this, it'll be seeing a lot of use + for (tile in unit.viewableTiles) { + if (tile.militaryUnit == null) continue + if (visibleUnitTypes.any { tile.militaryUnit!!.matchesFilter(it) }) + newViewableInvisibleTiles.add(tile) + } + } + + civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles + } + private fun setNewViewableTiles() { val newViewableTiles = HashSet() diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 9aaee55661..b436521064 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -201,23 +201,20 @@ class MapUnit { fun getUniques(): ArrayList = tempUniques fun getMatchingUniques(placeholderText: String): Sequence = - tempUniques.asSequence().filter { it.placeholderText == placeholderText } + - civInfo.getMatchingUniques(placeholderText) + tempUniques.asSequence().filter { it.placeholderText == placeholderText } fun getMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null) = sequence { yieldAll(tempUniques.asSequence() - .filter { it.type == uniqueType && it.conditionalsApply(stateForConditionals)} + .filter { it.type == uniqueType && it.conditionalsApply(stateForConditionals) } ) - yieldAll(civInfo.getMatchingUniques(uniqueType, stateForConditionals)) } fun hasUnique(unique: String): Boolean { - return tempUniques.any { it.placeholderText == unique } || civInfo.hasUnique(unique) + return tempUniques.any { it.placeholderText == unique } } fun hasUnique(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null): Boolean { - return tempUniques.any { it.type == uniqueType && it.conditionalsApply(stateForConditionals) } - || civInfo.hasUnique(uniqueType, stateForConditionals) + return tempUniques.any { it.type == uniqueType && it.conditionalsApply(stateForConditionals) } } fun updateUniques(ruleset: Ruleset) { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 18ff35a32a..b5b81520d3 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -127,6 +127,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { FoundCity("Founds a new city", UniqueTarget.Unit), BuildImprovements("Can build [improvementFilter/terrainFilter] improvements on tiles", UniqueTarget.Unit), CreateWaterImprovements("May create improvements on water resources", UniqueTarget.Unit), + CanSeeInvisibleUnits("Can see invisible [mapUnitFilter] units", UniqueTarget.Unit), Strength("[amount]% Strength", UniqueTarget.Unit, UniqueTarget.Global), StrengthNearCapital("[amount]% Strength decreasing with distance from the capital", UniqueTarget.Unit), diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 091dcdf680..ad05859949 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -282,7 +282,7 @@ object UnitActions { tile.improvement = null if (tile.resource != null) tile.getOwner()?.updateDetailedCivResources() // this might take away a resource - val freePillage = unit.hasUnique("No movement cost to pillage") || + val freePillage = unit.hasUnique("No movement cost to pillage") || unit.civInfo.hasUnique("No movement cost to pillage") (unit.baseUnit.isMelee() && unit.civInfo.hasUnique("Melee units pay no movement cost to pillage")) if (!freePillage) unit.useMovementPoints(1f)