Optimize String to Stat and Translation mod list somewhat (#6669)

* Accelerate Stat.values().firstOrNull and tr.activeMods a bit

* Use Stat.safeValueOf and its Map in existing code
This commit is contained in:
SomeTroglodyte 2022-05-04 09:12:40 +02:00 committed by GitHub
parent deac3d6f67
commit 75239ca1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 25 deletions

View File

@ -722,7 +722,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
replaces -> true
else -> {
if (uniques.contains(filter)) return true
val stat = Stat.values().firstOrNull { it.name == filter }
val stat = Stat.safeValueOf(filter)
if (stat != null && isStatRelated(stat)) return true
return false
}

View File

@ -155,14 +155,14 @@ enum class UniqueParameterType(
StatName("stat", "Culture", "This is one of the 7 major stats in the game - `Gold`, `Science`, `Production`, `Food`, `Happiness`, `Culture` and `Faith`. Note that the stat names need to be capitalized!") {
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
UniqueType.UniqueComplianceErrorSeverity? {
if (Stat.values().any { it.name == parameterText }) return null
if (Stat.isStat(parameterText)) return null
return UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant
}
},
/** [UniqueType.DamageUnitsPlunder] and others near that one */
PlunderableStatName("plunderableStat", "Gold", "All the following stats can be plundered: `Gold`, `Science`, `Culture`, `Faith`") {
private val knownValues = setOf(Stat.Gold.name, Stat.Science.name, Stat.Culture.name, Stat.Faith.name)
private val knownValues = Stat.statsWithCivWideField.map { it.name }.toSet()
override fun getErrorSeverity(
parameterText: String,
ruleset: Ruleset
@ -216,7 +216,7 @@ enum class UniqueParameterType(
/** Implemented by [Building.matchesFilter][com.unciv.models.ruleset.Building.matchesFilter] */
BuildingFilter("buildingFilter", "Culture") {
private val knownValues = mutableSetOf("All","Building","Buildings","Wonder","Wonders","National Wonder","World Wonder")
.apply { addAll(Stat.values().map { it.name }) }
.apply { addAll(Stat.names()) }
override fun getErrorSeverity(
parameterText: String,
ruleset: Ruleset

View File

@ -319,10 +319,9 @@ object UniqueTriggerActivation {
// I could parametrize the [Allied], but eh.
OneTimeGainStat -> {
if (Stat.values().none { it.name == unique.params[1] }) return false
val stat = Stat.valueOf(unique.params[1])
val stat = Stat.safeValueOf(unique.params[1]) ?: return false
if (stat !in listOf(Stat.Gold, Stat.Faith, Stat.Science, Stat.Culture)
if (stat !in Stat.statsWithCivWideField
|| unique.params[0].toIntOrNull() == null
) return false
@ -332,10 +331,9 @@ object UniqueTriggerActivation {
return true
}
OneTimeGainStatRange -> {
if (Stat.values().none { it.name == unique.params[2] }) return false
val stat = Stat.valueOf(unique.params[2])
val stat = Stat.safeValueOf(unique.params[2]) ?: return false
if (stat !in listOf(Stat.Gold, Stat.Faith, Stat.Science, Stat.Culture)
if (stat !in Stat.statsWithCivWideField
|| unique.params[0].toIntOrNull() == null
|| unique.params[1].toIntOrNull() == null
) return false

View File

@ -18,7 +18,12 @@ enum class Stat(
Faith(NotificationIcon.Faith, UncivSound.Choir, Fonts.faith);
companion object {
val statsUsableToBuy = listOf(Gold, Food, Science, Culture, Faith)
val statsUsableToBuy = setOf(Gold, Food, Science, Culture, Faith)
private val valuesAsMap = values().associateBy { it.name }
fun safeValueOf(name: String) = valuesAsMap[name]
fun isStat(name: String) = name in valuesAsMap
fun names() = valuesAsMap.keys
val statsWithCivWideField = setOf(Gold, Science, Culture, Faith)
}
}

View File

@ -241,7 +241,39 @@ val curlyBraceRegex = Regex("""\{([^}]*)\}""")
val pointyBraceRegex = Regex("""\<([^>]*)\>""")
/**
object TranslationActiveModsCache {
private var cachedHash = Int.MIN_VALUE
var activeMods: HashSet<String> = hashSetOf()
get() {
val hash = getCurrentHash()
if (hash != cachedHash) {
cachedHash = hash
field = getCurrentSet()
}
return field
}
private set
private fun getCurrentHash() = UncivGame.Current.run {
if (isGameInfoInitialized())
gameInfo.gameParameters.mods.hashCode() + gameInfo.gameParameters.baseRuleset.hashCode() * 31
else translations.translationActiveMods.hashCode() * 31 * 31
}
private fun getCurrentSet() = UncivGame.Current.run {
if (isGameInfoInitialized()) {
val par = gameInfo.gameParameters
// This is equivalent to (par.mods + par.baseRuleset) without the cast down to `Set`
LinkedHashSet<String>(par.mods.size + 1).apply {
addAll(par.mods)
add(par.baseRuleset)
}
} else translations.translationActiveMods
}
}
/**
* This function does the actual translation work,
* using an instance of [Translations] stored in UncivGame.Current
*
@ -256,11 +288,6 @@ val pointyBraceRegex = Regex("""\<([^>]*)\>""")
* but with placeholder or sentence brackets removed.
*/
fun String.tr(): String {
val activeMods = with(UncivGame.Current) {
if (isGameInfoInitialized())
gameInfo.gameParameters.mods + gameInfo.gameParameters.baseRuleset
else translations.translationActiveMods
}.toHashSet()
val language = UncivGame.Current.settings.language
if (contains('<') && contains('>')) { // Conditionals!
@ -325,7 +352,7 @@ fun String.tr(): String {
if (contains('{')) { // Translating partial sentences
return curlyBraceRegex.replace(this) { it.groups[1]!!.value.tr() }
}
// There might still be optimization potential here!
if (contains('[')) { // Placeholders!
/**
@ -345,7 +372,7 @@ fun String.tr(): String {
val translationStringWithSquareBracketsOnly = this.getPlaceholderText()
// That is now the key into the translation HashMap!
val translationEntry = UncivGame.Current.translations
.get(translationStringWithSquareBracketsOnly, language, activeMods)
.get(translationStringWithSquareBracketsOnly, language, TranslationActiveModsCache.activeMods)
var languageSpecificPlaceholder: String
val originalEntry: String
@ -377,9 +404,9 @@ fun String.tr(): String {
if (Stats.isStats(this)) return Stats.parse(this).toString()
val translation = UncivGame.Current.translations.getText(this, language, activeMods)
val translation = UncivGame.Current.translations.getText(this, language, TranslationActiveModsCache.activeMods)
val stat = Stat.values().firstOrNull { it.name == this }
val stat = Stat.safeValueOf(this)
if (stat != null) return stat.character + translation
return translation

View File

@ -57,7 +57,7 @@ class CityOverviewTab(
.apply { addTooltip("Current construction", 18f, tipAlign = Align.center) }
// Readability helpers
private fun String.isStat() = Stat.values().any { it.name == this }
private fun String.isStat() = Stat.isStat(this)
private fun CityInfo.getStat(stat: Stat) =
if (stat == Stat.Happiness)
@ -115,7 +115,7 @@ class CityOverviewTab(
"Population" -> city2.population.population - city1.population.population
WLTK -> city2.isWeLoveTheKingDayActive().compareTo(city1.isWeLoveTheKingDayActive())
else -> {
val stat = Stat.valueOf(persistableData.sortedBy)
val stat = Stat.safeValueOf(persistableData.sortedBy)!!
city2.getStat(stat) - city1.getStat(stat)
}
}
@ -199,8 +199,8 @@ class CityOverviewTab(
cityInfoTableDetails.add(city.population.population.toCenteredLabel())
for (column in columnsNames) {
if (!column.isStat()) continue
cityInfoTableDetails.add(city.getStat(Stat.valueOf(column)).toCenteredLabel())
val stat = Stat.safeValueOf(column) ?: continue
cityInfoTableDetails.add(city.getStat(stat).toCenteredLabel())
}
when {