Removed "in other cities" conditional and cityfilter, allowing civ.getMatchingUniques to NOT be city-based, thus cacheable - makes future performance optimization possible :D

This commit is contained in:
Yair Morgenstern 2023-08-30 23:53:42 +03:00
parent a6142ec482
commit cb7bb51e18
9 changed files with 20 additions and 27 deletions

View File

@ -127,7 +127,7 @@ object ReligionAutomation {
if (validCitiesToBuy.isEmpty()) return if (validCitiesToBuy.isEmpty()) return
val citiesWithBonusCharges = validCitiesToBuy.filter { city -> val citiesWithBonusCharges = validCitiesToBuy.filter { city ->
city.getLocalMatchingUniques(UniqueType.UnitStartingActions).filter { it.params[2] == Constants.spreadReligion }.any() city.getMatchingUniques(UniqueType.UnitStartingActions).filter { it.params[2] == Constants.spreadReligion }.any()
} }
val holyCity = validCitiesToBuy.firstOrNull { it.isHolyCityOf(civInfo.religionManager.religion!!.name) } val holyCity = validCitiesToBuy.firstOrNull { it.isHolyCityOf(civInfo.religionManager.religion!!.name) }

View File

@ -232,10 +232,10 @@ object Battle {
val cityWithReligion = val cityWithReligion =
civUnit.getTile().getTilesInDistance(4).firstOrNull { civUnit.getTile().getTilesInDistance(4).firstOrNull {
it.isCityCenter() && it.getCity()!!.getLocalMatchingUniques(UniqueType.KillUnitPlunderNearCity, stateForConditionals).any() it.isCityCenter() && it.getCity()!!.getMatchingUniques(UniqueType.KillUnitPlunderNearCity, stateForConditionals).any()
}?.getCity() }?.getCity()
if (cityWithReligion != null) { if (cityWithReligion != null) {
bonusUniques.addAll(cityWithReligion.getLocalMatchingUniques(UniqueType.KillUnitPlunderNearCity, stateForConditionals)) bonusUniques.addAll(cityWithReligion.getMatchingUniques(UniqueType.KillUnitPlunderNearCity, stateForConditionals))
} }
for (unique in bonusUniques) { for (unique in bonusUniques) {

View File

@ -264,7 +264,7 @@ class City : IsPartOfGameInfoSerialization {
} }
private fun getCityResourcesFromUniqueBuildings(cityResources: ResourceSupplyList, resourceModifer: HashMap<String, Float>) { private fun getCityResourcesFromUniqueBuildings(cityResources: ResourceSupplyList, resourceModifer: HashMap<String, Float>) {
for (unique in getLocalMatchingUniques(UniqueType.ProvidesResources, StateForConditionals(civ, this))) { // E.G "Provides [1] [Iron]" for (unique in getMatchingUniques(UniqueType.ProvidesResources, StateForConditionals(civ, this))) { // E.G "Provides [1] [Iron]"
val resource = getRuleset().tileResources[unique.params[1]] val resource = getRuleset().tileResources[unique.params[1]]
?: continue ?: continue
cityResources.add( cityResources.add(
@ -575,7 +575,6 @@ class City : IsPartOfGameInfoSerialization {
return when (filter) { return when (filter) {
"in this city" -> true // Filtered by the way uniques are found "in this city" -> true // Filtered by the way uniques are found
"in all cities" -> true "in all cities" -> true
"in other cities" -> true // Filtered by the way uniques are found
"in all coastal cities" -> isCoastal() "in all coastal cities" -> isCoastal()
"in capital" -> isCapital() "in capital" -> isCapital()
"in all non-occupied cities" -> !cityStats.hasExtraAnnexUnhappiness() || isPuppet "in all non-occupied cities" -> !cityStats.hasExtraAnnexUnhappiness() || isPuppet
@ -618,13 +617,14 @@ class City : IsPartOfGameInfoSerialization {
uniqueType: UniqueType, uniqueType: UniqueType,
stateForConditionals: StateForConditionals = StateForConditionals(civ, this) stateForConditionals: StateForConditionals = StateForConditionals(civ, this)
): Sequence<Unique> { ): Sequence<Unique> {
return civ.getMatchingUniques(uniqueType, stateForConditionals, this) + return civ.getMatchingUniques(uniqueType, stateForConditionals) +
getLocalMatchingUniques(uniqueType, stateForConditionals) getLocalMatchingUniques(uniqueType, stateForConditionals)
} }
fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(civ, this)): Sequence<Unique> { // Uniques special to this city
private fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(civ, this)): Sequence<Unique> {
return ( return (
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { !it.isAntiLocalEffect } cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect }
+ religion.getUniques().filter { it.isOfType(uniqueType) } + religion.getUniques().filter { it.isOfType(uniqueType) }
).filter { ).filter {
it.conditionalsApply(stateForConditionals) it.conditionalsApply(stateForConditionals)
@ -632,6 +632,7 @@ class City : IsPartOfGameInfoSerialization {
} }
// Uniques coming from this city, but that should be provided globally
fun getMatchingUniquesWithNonLocalEffects(uniqueType: UniqueType, stateForConditionals: StateForConditionals): Sequence<Unique> { fun getMatchingUniquesWithNonLocalEffects(uniqueType: UniqueType, stateForConditionals: StateForConditionals): Sequence<Unique> {
val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType) val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType)
// Memory performance showed that this function was very memory intensive, thus we only create the filter if needed // Memory performance showed that this function was very memory intensive, thus we only create the filter if needed

View File

@ -506,7 +506,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
} }
builtBuildingObjects = builtBuildingObjects.withItem(building) builtBuildingObjects = builtBuildingObjects.withItem(building)
builtBuildings.add(buildingName) builtBuildings.add(buildingName)
updateUniques() updateUniques()
/** Support for [UniqueType.CreatesOneImprovement] */ /** Support for [UniqueType.CreatesOneImprovement] */
@ -578,15 +578,13 @@ class CityConstructions : IsPartOfGameInfoSerialization {
fun addFreeBuildings() { fun addFreeBuildings() {
// "Gain a free [buildingName] [cityFilter]" // "Gain a free [buildingName] [cityFilter]"
val freeBuildingUniques = city.getLocalMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals(city.civ, city)) val freeBuildingUniques = city.getMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals(city.civ, city))
for (unique in freeBuildingUniques) { for (unique in freeBuildingUniques) {
val freeBuilding = city.civ.getEquivalentBuilding(unique.params[0]) val freeBuilding = city.civ.getEquivalentBuilding(unique.params[0])
val citiesThatApply = when (unique.params[1]) { val citiesThatApply =
"in this city" -> listOf(city) if (unique.isLocalEffect) listOf(city)
"in other cities" -> city.civ.cities.filter { it !== city } else city.civ.cities.filter { it.matchesFilter(unique.params[1]) }
else -> city.civ.cities.filter { it.matchesFilter(unique.params[1]) }
}
for (city in citiesThatApply) { for (city in citiesThatApply) {
if (city.cityConstructions.containsBuildingOrEquivalent(freeBuilding.name)) continue if (city.cityConstructions.containsBuildingOrEquivalent(freeBuilding.name)) continue

View File

@ -258,7 +258,7 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
private fun getSpreadRange(): Int { private fun getSpreadRange(): Int {
var spreadRange = 10 var spreadRange = 10
for (unique in city.getLocalMatchingUniques(UniqueType.ReligionSpreadDistance)) { for (unique in city.getMatchingUniques(UniqueType.ReligionSpreadDistance)) {
spreadRange += unique.params[0].toInt() spreadRange += unique.params[0].toInt()
} }
@ -308,7 +308,7 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
var pressure = pressureFromAdjacentCities.toFloat() var pressure = pressureFromAdjacentCities.toFloat()
// Follower beliefs of this religion // Follower beliefs of this religion
for (unique in city.getLocalMatchingUniques(UniqueType.NaturalReligionSpreadStrength)) { for (unique in city.getMatchingUniques(UniqueType.NaturalReligionSpreadStrength)) {
if (pressuredCity.matchesFilter(unique.params[1])) if (pressuredCity.matchesFilter(unique.params[1]))
pressure *= unique.params[0].toPercent() pressure *= unique.params[0].toPercent()
} }

View File

@ -453,12 +453,10 @@ class Civilization : IsPartOfGameInfoSerialization {
/** Destined to replace getMatchingUniques, gradually, as we fill the enum */ /** Destined to replace getMatchingUniques, gradually, as we fill the enum */
fun getMatchingUniques( fun getMatchingUniques(
uniqueType: UniqueType, uniqueType: UniqueType,
stateForConditionals: StateForConditionals = StateForConditionals(this), stateForConditionals: StateForConditionals = StateForConditionals(this)
cityToIgnore: City? = null
): Sequence<Unique> = sequence { ): Sequence<Unique> = sequence {
yieldAll(nation.getMatchingUniques(uniqueType, stateForConditionals)) yieldAll(nation.getMatchingUniques(uniqueType, stateForConditionals))
yieldAll(cities.asSequence() yieldAll(cities.asSequence()
.filter { it != cityToIgnore }
.flatMap { city -> city.getMatchingUniquesWithNonLocalEffects(uniqueType, stateForConditionals) } .flatMap { city -> city.getMatchingUniquesWithNonLocalEffects(uniqueType, stateForConditionals) }
) )
yieldAll(policies.policyUniques.getMatchingUniques(uniqueType, stateForConditionals)) yieldAll(policies.policyUniques.getMatchingUniques(uniqueType, stateForConditionals))

View File

@ -38,7 +38,6 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
val allParams = params + conditionals.flatMap { it.params } val allParams = params + conditionals.flatMap { it.params }
val isLocalEffect = params.contains("in this city") || conditionals.any { it.type == UniqueType.ConditionalInThisCity } val isLocalEffect = params.contains("in this city") || conditionals.any { it.type == UniqueType.ConditionalInThisCity }
val isAntiLocalEffect = params.contains("in other cities") || conditionals.any { it.type == UniqueType.ConditionalInOtherCities }
fun hasFlag(flag: UniqueFlag) = type != null && type.flags.contains(flag) fun hasFlag(flag: UniqueFlag) = type != null && type.flags.contains(flag)

View File

@ -238,11 +238,9 @@ object UniqueTriggerActivation {
} }
UniqueType.OneTimeGainPopulation -> { UniqueType.OneTimeGainPopulation -> {
val applicableCities = when (unique.params[1]) { val applicableCities =
"in this city" -> sequenceOf(city!!) if (unique.params[1] == "in this city") sequenceOf(city!!)
"in other cities" -> civInfo.cities.asSequence().filter { it != city } else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
else -> civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
}
for (applicableCity in applicableCities) { for (applicableCity in applicableCities) {
applicableCity.population.addPopulation(unique.params[0].toInt()) applicableCity.population.addPopulation(unique.params[0].toInt())
} }

View File

@ -634,7 +634,6 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
/////// city conditionals /////// city conditionals
ConditionalInThisCity("in this city", UniqueTarget.Conditional), ConditionalInThisCity("in this city", UniqueTarget.Conditional),
ConditionalInOtherCities("in other cities", UniqueTarget.Conditional),
ConditionalCityWithBuilding("in cities with a [buildingFilter]", UniqueTarget.Conditional), ConditionalCityWithBuilding("in cities with a [buildingFilter]", UniqueTarget.Conditional),
ConditionalCityWithoutBuilding("in cities without a [buildingFilter]", UniqueTarget.Conditional), ConditionalCityWithoutBuilding("in cities without a [buildingFilter]", UniqueTarget.Conditional),
ConditionalPopulationFilter("in cities with at least [amount] [populationFilter]", UniqueTarget.Conditional), ConditionalPopulationFilter("in cities with at least [amount] [populationFilter]", UniqueTarget.Conditional),