From b2c6cc59b7853100219338b7c9bb7c8cdfb6d444 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 26 Oct 2020 23:38:29 +0200 Subject: [PATCH] All stat-based uniques are parsed EXACTLY once, for performance reasons and to avoid ANRs --- core/src/com/unciv/logic/city/CityConstructions.kt | 4 ++-- core/src/com/unciv/logic/city/CityStats.kt | 12 ++++++------ core/src/com/unciv/logic/map/TileInfo.kt | 8 ++++---- core/src/com/unciv/models/ruleset/Building.kt | 8 ++++---- core/src/com/unciv/models/ruleset/Unique.kt | 4 ++++ 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 13eeacf504..c992a98286 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -73,8 +73,8 @@ class CityConstructions { stats.add(building.getStats(cityInfo.civInfo)) for (unique in builtBuildingUniqueMap.getAllUniques()) when (unique.placeholderText) { - "[] Per [] Population in this city" -> stats.add(Stats.parse(unique.params[0]).times(cityInfo.population.population / unique.params[1].toFloat())) - "[] once [] is discovered" -> if (cityInfo.civInfo.tech.isResearched(unique.params[1])) stats.add(Stats.parse(unique.params[0])) + "[] Per [] Population in this city" -> stats.add(unique.stats!!.times(cityInfo.population.population / unique.params[1].toFloat())) + "[] once [] is discovered" -> if (cityInfo.civInfo.tech.isResearched(unique.params[1])) stats.add(unique.stats!!) } // This is to be deprecated and converted to "[stats] Per [N] Population in this city" - keeping it here to that mods with this can still work for now diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index 8d0369db35..f09a1794c2 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -50,7 +50,7 @@ class CityStats { val civInfo = cityInfo.civInfo stats.gold = civInfo.getCapital().population.population * 0.15f + cityInfo.population.population * 1.1f - 1 // Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5) for (unique in civInfo.getMatchingUniques("[] from each Trade Route")) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) if (civInfo.hasUnique("Gold from all trade routes +25%")) stats.gold *= 1.25f // Machu Pichu speciality } return stats @@ -215,7 +215,7 @@ class CityStats { if (cityInfo.getCenterTile().militaryUnit != null) for (unique in civInfo.getMatchingUniques("[] in all cities with a garrison")) - happinessFromPolicies += Stats.parse(unique.params[0]).happiness + happinessFromPolicies += unique.stats!!.happiness newHappinessList["Policies"] = happinessFromPolicies @@ -247,7 +247,7 @@ class CityStats { else stats.add(stat, 2f) // science and gold specialists for(unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist")) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) return stats } @@ -257,7 +257,7 @@ class CityStats { if (specialist == null) return Stats() val stats = specialist.clone() for (unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist")) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) return stats } @@ -275,10 +275,10 @@ class CityStats { if ((unique.placeholderText == "[] in capital" && cityInfo.isCapital()) || unique.placeholderText == "[] in all cities" || (unique.placeholderText == "[] in all cities with a garrison" && cityInfo.getCenterTile().militaryUnit != null)) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) if (unique.placeholderText == "[] per [] population in all cities") { val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat() - stats.add(Stats.parse(unique.params[0]).times(amountOfEffects)) + stats.add(unique.stats!!.times(amountOfEffects)) } if (unique.text == "+1 gold and -1 unhappiness for every 2 citizens in capital" && cityInfo.isCapital()) { stats.gold += (cityInfo.population.population / 2).toFloat() diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 71b60a0267..c2e61836f5 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -194,7 +194,7 @@ open class TileInfo { || (resource == tileType && hasViewableResource(observingCiv)) || (tileType == "Strategic resource" && hasViewableResource(observingCiv) && getTileResource().resourceType == ResourceType.Strategic) || (tileType == "Water resource" && isWater && hasViewableResource(observingCiv)) - ) stats.add(Stats.parse(unique.params[0])) + ) stats.add(unique.stats!!) } } @@ -247,7 +247,7 @@ open class TileInfo { for (unique in improvement.uniqueObjects) if (unique.placeholderText == "[] once [] is discovered" && observingCiv.tech.isResearched(unique.params[1])) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) if (city != null) { val cityWideUniques = city.cityConstructions.builtBuildingUniqueMap.getUniques("[] from [] tiles in this city") @@ -262,7 +262,7 @@ open class TileInfo { || (unique.params[1] == "fresh water" && isAdjacentToFreshwater) || (unique.params[1] == "non-fresh water" && !isAdjacentToFreshwater) ) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) } } @@ -278,7 +278,7 @@ open class TileInfo { || it.matchesUniqueFilter(adjacent) || it.roadStatus.name == adjacent } - stats.add(Stats.parse(unique.params[0]).times(numberOfBonuses.toFloat())) + stats.add(unique.stats!!.times(numberOfBonuses.toFloat())) } return stats diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index c4fb3c70e8..6cb7203ca7 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -143,21 +143,21 @@ class Building : NamedStats(), IConstruction { for (unique in civInfo.getMatchingUniques("[] from every []")) { if (unique.params[1] != baseBuildingName) continue - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) } for (unique in uniqueObjects) if (unique.placeholderText == "[] with []" && civInfo.hasResource(unique.params[1]) && Stats.isStats(unique.params[0])) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) if (!isWonder) for (unique in civInfo.getMatchingUniques("[] from all [] buildings")) { if (isStatRelated(Stat.valueOf(unique.params[1]))) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) } else for (unique in civInfo.getMatchingUniques("[] from every Wonder")) - stats.add(Stats.parse(unique.params[0])) + stats.add(unique.stats!!) } return stats diff --git a/core/src/com/unciv/models/ruleset/Unique.kt b/core/src/com/unciv/models/ruleset/Unique.kt index 5a6378c99b..2e68f1deff 100644 --- a/core/src/com/unciv/models/ruleset/Unique.kt +++ b/core/src/com/unciv/models/ruleset/Unique.kt @@ -2,12 +2,16 @@ package com.unciv.models.ruleset import com.unciv.Constants import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.models.stats.Stats import com.unciv.models.translations.getPlaceholderParameters import com.unciv.models.translations.getPlaceholderText class Unique(val text:String){ val placeholderText = text.getPlaceholderText() val params = text.getPlaceholderParameters() + /** This is so the heavy regex-based parsing is only activated once per unique, instead of every time it's called + * - for instance, in the city screen, we call every tile unique for every tile, which can lead to ANRs */ + val stats = params.firstOrNull { Stats.isStats(it) }?.let { Stats.parse(it) } } class UniqueMap:HashMap>() {