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
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) }

View File

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

View File

@ -264,7 +264,7 @@ class City : IsPartOfGameInfoSerialization {
}
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]]
?: continue
cityResources.add(
@ -575,7 +575,6 @@ class City : IsPartOfGameInfoSerialization {
return when (filter) {
"in this city" -> true // Filtered by the way uniques are found
"in all cities" -> true
"in other cities" -> true // Filtered by the way uniques are found
"in all coastal cities" -> isCoastal()
"in capital" -> isCapital()
"in all non-occupied cities" -> !cityStats.hasExtraAnnexUnhappiness() || isPuppet
@ -618,13 +617,14 @@ class City : IsPartOfGameInfoSerialization {
uniqueType: UniqueType,
stateForConditionals: StateForConditionals = StateForConditionals(civ, this)
): Sequence<Unique> {
return civ.getMatchingUniques(uniqueType, stateForConditionals, this) +
return civ.getMatchingUniques(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 (
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { !it.isAntiLocalEffect }
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect }
+ religion.getUniques().filter { it.isOfType(uniqueType) }
).filter {
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> {
val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType)
// 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)
builtBuildings.add(buildingName)
updateUniques()
/** Support for [UniqueType.CreatesOneImprovement] */
@ -578,15 +578,13 @@ class CityConstructions : IsPartOfGameInfoSerialization {
fun addFreeBuildings() {
// "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) {
val freeBuilding = city.civ.getEquivalentBuilding(unique.params[0])
val citiesThatApply = when (unique.params[1]) {
"in this city" -> listOf(city)
"in other cities" -> city.civ.cities.filter { it !== city }
else -> city.civ.cities.filter { it.matchesFilter(unique.params[1]) }
}
val citiesThatApply =
if (unique.isLocalEffect) listOf(city)
else city.civ.cities.filter { it.matchesFilter(unique.params[1]) }
for (city in citiesThatApply) {
if (city.cityConstructions.containsBuildingOrEquivalent(freeBuilding.name)) continue

View File

@ -258,7 +258,7 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
private fun getSpreadRange(): Int {
var spreadRange = 10
for (unique in city.getLocalMatchingUniques(UniqueType.ReligionSpreadDistance)) {
for (unique in city.getMatchingUniques(UniqueType.ReligionSpreadDistance)) {
spreadRange += unique.params[0].toInt()
}
@ -308,7 +308,7 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
var pressure = pressureFromAdjacentCities.toFloat()
// 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]))
pressure *= unique.params[0].toPercent()
}

View File

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

View File

@ -238,11 +238,9 @@ object UniqueTriggerActivation {
}
UniqueType.OneTimeGainPopulation -> {
val applicableCities = when (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]) }
}
val applicableCities =
if (unique.params[1] == "in this city") sequenceOf(city!!)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
for (applicableCity in applicableCities) {
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
ConditionalInThisCity("in this city", UniqueTarget.Conditional),
ConditionalInOtherCities("in other cities", UniqueTarget.Conditional),
ConditionalCityWithBuilding("in cities with a [buildingFilter]", UniqueTarget.Conditional),
ConditionalCityWithoutBuilding("in cities without a [buildingFilter]", UniqueTarget.Conditional),
ConditionalPopulationFilter("in cities with at least [amount] [populationFilter]", UniqueTarget.Conditional),