mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-04 23:40:01 +07:00
Cache city-wide uniques in CityConstructions.getStats() for reuse between buildings - see #6695
This commit is contained in:
@ -6,6 +6,7 @@ import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueMap
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -87,8 +88,9 @@ class CityConstructions {
|
||||
*/
|
||||
fun getStats(): StatTreeNode {
|
||||
val stats = StatTreeNode()
|
||||
val localUniqueCache = LocalUniqueCache()
|
||||
for (building in getBuiltBuildings())
|
||||
stats.addStats(building.getStats(cityInfo), building.name)
|
||||
stats.addStats(building.getStats(cityInfo, localUniqueCache), building.name)
|
||||
return stats
|
||||
}
|
||||
|
||||
@ -98,13 +100,11 @@ class CityConstructions {
|
||||
fun getMaintenanceCosts(): Int {
|
||||
var maintenanceCost = 0
|
||||
val freeBuildings = cityInfo.civInfo.civConstructions.getFreeBuildings(cityInfo.id)
|
||||
|
||||
for (building in getBuiltBuildings()) {
|
||||
if (building.name !in freeBuildings) {
|
||||
|
||||
for (building in getBuiltBuildings())
|
||||
if (building.name !in freeBuildings)
|
||||
maintenanceCost += building.maintenance
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return maintenanceCost
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
|
||||
// We IGNORE the conditionals when we get them civ-wide, so we won't need to do the same thing for EVERY unit in the civ.
|
||||
// This leads to massive memory and CPU time savings when calculating the maintenance!
|
||||
val civwideDiscountUniques = civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscount, StateForConditionals.IgnoreConditionals).toList()
|
||||
val civwideDiscountUniques = civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscount, StateForConditionals.IgnoreConditionals)
|
||||
.toList().asSequence()
|
||||
|
||||
for (unit in unitsToPayFor) {
|
||||
val stateForConditionals = StateForConditionals(civInfo = civInfo, unit = unit)
|
||||
@ -47,8 +48,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
val uniquesThatApply = unit.getMatchingUniques(
|
||||
UniqueType.UnitMaintenanceDiscount,
|
||||
stateForConditionals
|
||||
) + civwideDiscountUniques.asSequence()
|
||||
.filter { it.conditionalsApply(stateForConditionals) }
|
||||
) + civwideDiscountUniques.filter { it.conditionalsApply(stateForConditionals) }
|
||||
for (unique in uniquesThatApply) {
|
||||
unitMaintenance *= unique.params[0].toPercent()
|
||||
}
|
||||
|
@ -163,12 +163,15 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
return lines.joinToString("\n") { it.tr() }.trim()
|
||||
}
|
||||
|
||||
fun getStats(city: CityInfo): Stats {
|
||||
fun getStats(city: CityInfo,
|
||||
/* By default, do not cache - if we're getting stats for only one building this isn't efficient.
|
||||
* Only use a cache if it was sent to us from outside, which means we can use the results for other buildings. */
|
||||
localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)): Stats {
|
||||
// Calls the clone function of the NamedStats this class is derived from, not a clone function of this class
|
||||
val stats = cloneStats()
|
||||
val civInfo = city.civInfo
|
||||
|
||||
for (unique in city.getMatchingUniques(UniqueType.StatsFromObject)) {
|
||||
for (unique in localUniqueCache.get("StatsFromObject", city.getMatchingUniques(UniqueType.StatsFromObject))) {
|
||||
if (!matchesFilter(unique.params[1])) continue
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
@ -179,7 +182,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
stats.add(unique.stats)
|
||||
|
||||
if (!isWonder)
|
||||
for (unique in city.getMatchingUniques(UniqueType.StatsFromBuildings)) {
|
||||
for (unique in localUniqueCache.get("StatsFromBuildings", city.getMatchingUniques(UniqueType.StatsFromBuildings))) {
|
||||
if (matchesFilter(unique.params[1]))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
@ -262,6 +262,22 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
||||
override fun toString() = if (type == null) "\"$text\"" else "$type (\"$text\")"
|
||||
}
|
||||
|
||||
/** Used to cache results of getMatchingUniques
|
||||
* Must only be used when we're sure the matching uniques will not change in the meantime */
|
||||
class LocalUniqueCache(val cache:Boolean = true) {
|
||||
// This stores sequences *that iterate directly on a list* - that is, pre-resolved
|
||||
private val keyToUniques = HashMap<String, Sequence<Unique>>()
|
||||
|
||||
/** Get cached results as a sequence */
|
||||
fun get(key: String, sequence: Sequence<Unique>): Sequence<Unique> {
|
||||
if (!cache) return sequence
|
||||
if (keyToUniques.containsKey(key)) return keyToUniques[key]!!
|
||||
// Iterate the sequence, save actual results as a list, as return a sequence to that
|
||||
val results = sequence.toList().asSequence()
|
||||
keyToUniques[key] = results
|
||||
return results
|
||||
}
|
||||
}
|
||||
|
||||
class UniqueMap: HashMap<String, ArrayList<Unique>>() {
|
||||
//todo Once all untyped Uniques are converted, this should be HashMap<UniqueType, *>
|
||||
|
Reference in New Issue
Block a user