chore: Readonly 3

This commit is contained in:
yairm210 2025-07-14 12:48:17 +03:00
parent 87c096b085
commit 7e1cc64ca7
5 changed files with 39 additions and 4 deletions

View File

@ -47,9 +47,17 @@ allprojects {
apply(plugin = "io.github.yairm210.purity-plugin") apply(plugin = "io.github.yairm210.purity-plugin")
configure<yairm210.purity.PurityConfiguration>{ configure<yairm210.purity.PurityConfiguration>{
wellKnownPureFunctions = setOf() wellKnownPureFunctions = setOf(
"kotlin.let",
"kotlin.run",
"kotlin.also",
"kotlin.apply",
"kotlin.takeIf",
"kotlin.takeUnless",
)
wellKnownReadonlyFunctions = setOf( wellKnownReadonlyFunctions = setOf(
"kotlin.collections.any", "kotlin.collections.any",
"kotlin.collections.get",
"kotlin.collections.all", "kotlin.collections.all",
"kotlin.ranges.coerceAtLeast", "kotlin.ranges.coerceAtLeast",
// Looks like the Collection.contains is not considered overridden :thunk: // Looks like the Collection.contains is not considered overridden :thunk:

View File

@ -56,6 +56,7 @@ import com.unciv.models.translations.tr
import com.unciv.ui.components.extensions.toPercent import com.unciv.ui.components.extensions.toPercent
import com.unciv.ui.screens.victoryscreen.RankingType import com.unciv.ui.screens.victoryscreen.RankingType
import org.jetbrains.annotations.VisibleForTesting import org.jetbrains.annotations.VisibleForTesting
import yairm210.purity.annotations.Readonly
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -323,7 +324,9 @@ class Civilization : IsPartOfGameInfoSerialization {
if (!knows(civInfo)) diplomacyFunctions.makeCivilizationsMeet(civInfo) if (!knows(civInfo)) diplomacyFunctions.makeCivilizationsMeet(civInfo)
return getDiplomacyManager(civInfo.civName)!! return getDiplomacyManager(civInfo.civName)!!
} }
@Readonly
fun getDiplomacyManager(civInfo: Civilization): DiplomacyManager? = getDiplomacyManager(civInfo.civName) fun getDiplomacyManager(civInfo: Civilization): DiplomacyManager? = getDiplomacyManager(civInfo.civName)
@Readonly
fun getDiplomacyManager(civName: String): DiplomacyManager? = diplomacy[civName] fun getDiplomacyManager(civName: String): DiplomacyManager? = diplomacy[civName]
fun getProximity(civInfo: Civilization) = getProximity(civInfo.civName) fun getProximity(civInfo: Civilization) = getProximity(civInfo.civName)

View File

@ -283,12 +283,18 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
fun hasImprovementInProgress() = improvementQueue.isNotEmpty() fun hasImprovementInProgress() = improvementQueue.isNotEmpty()
@Readonly
fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!] fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!]
@Readonly
fun isPillaged(): Boolean = improvementIsPillaged || roadIsPillaged fun isPillaged(): Boolean = improvementIsPillaged || roadIsPillaged
@Readonly
fun getUnpillagedTileImprovement(): TileImprovement? = if (getUnpillagedImprovement() == null) null else ruleset.tileImprovements[improvement!!] fun getUnpillagedTileImprovement(): TileImprovement? = if (getUnpillagedImprovement() == null) null else ruleset.tileImprovements[improvement!!]
@Readonly
fun getTileImprovementInProgress(): TileImprovement? = improvementQueue.firstOrNull()?.let { ruleset.tileImprovements[it.improvement] } fun getTileImprovementInProgress(): TileImprovement? = improvementQueue.firstOrNull()?.let { ruleset.tileImprovements[it.improvement] }
@Readonly
fun containsGreatImprovement() = getTileImprovement()?.isGreatImprovement() == true fun containsGreatImprovement() = getTileImprovement()?.isGreatImprovement() == true
@Readonly
fun getImprovementToPillage(): TileImprovement? { fun getImprovementToPillage(): TileImprovement? {
if (canPillageTileImprovement()) if (canPillageTileImprovement())
return ruleset.tileImprovements[improvement]!! return ruleset.tileImprovements[improvement]!!
@ -297,6 +303,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
return null return null
} }
// same as above, but slightly quicker // same as above, but slightly quicker
@Readonly
fun getImprovementToPillageName(): String? { fun getImprovementToPillageName(): String? {
if (canPillageTileImprovement()) if (canPillageTileImprovement())
return improvement return improvement
@ -304,6 +311,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
return roadStatus.name return roadStatus.name
return null return null
} }
@Readonly
fun getImprovementToRepair(): TileImprovement? { fun getImprovementToRepair(): TileImprovement? {
if (improvement != null && improvementIsPillaged) if (improvement != null && improvementIsPillaged)
return ruleset.tileImprovements[improvement]!! return ruleset.tileImprovements[improvement]!!
@ -311,24 +319,30 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
return ruleset.tileImprovements[roadStatus.name]!! return ruleset.tileImprovements[roadStatus.name]!!
return null return null
} }
@Readonly
fun canPillageTile(): Boolean { fun canPillageTile(): Boolean {
return canPillageTileImprovement() || canPillageRoad() return canPillageTileImprovement() || canPillageRoad()
} }
@Readonly
fun canPillageTileImprovement(): Boolean { fun canPillageTileImprovement(): Boolean {
return improvement != null && !improvementIsPillaged return improvement != null && !improvementIsPillaged
&& !ruleset.tileImprovements[improvement]!!.hasUnique(UniqueType.Unpillagable) && !ruleset.tileImprovements[improvement]!!.hasUnique(UniqueType.Unpillagable)
&& !ruleset.tileImprovements[improvement]!!.hasUnique(UniqueType.Irremovable) && !ruleset.tileImprovements[improvement]!!.hasUnique(UniqueType.Irremovable)
} }
@Readonly
fun canPillageRoad(): Boolean { fun canPillageRoad(): Boolean {
return roadStatus != RoadStatus.None && !roadIsPillaged return roadStatus != RoadStatus.None && !roadIsPillaged
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Unpillagable) && !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Unpillagable)
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Irremovable) && !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Irremovable)
} }
@Readonly
fun getUnpillagedImprovement(): String? = if (improvementIsPillaged) null else improvement fun getUnpillagedImprovement(): String? = if (improvementIsPillaged) null else improvement
/** @return [RoadStatus] on this [Tile], pillaged road counts as [RoadStatus.None] */ /** @return [RoadStatus] on this [Tile], pillaged road counts as [RoadStatus.None] */
@Readonly
fun getUnpillagedRoad(): RoadStatus = if (roadIsPillaged) RoadStatus.None else roadStatus fun getUnpillagedRoad(): RoadStatus = if (roadIsPillaged) RoadStatus.None else roadStatus
@Readonly
fun getUnpillagedRoadImprovement(): TileImprovement? { fun getUnpillagedRoadImprovement(): TileImprovement? {
return if (getUnpillagedRoad() == RoadStatus.None) null return if (getUnpillagedRoad() == RoadStatus.None) null
else ruleset.tileImprovements[getUnpillagedRoad().name] else ruleset.tileImprovements[getUnpillagedRoad().name]
@ -491,7 +505,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
return MultiFilter.multiFilter(filter, { matchesSingleFilter(it, civInfo) }) return MultiFilter.multiFilter(filter, { matchesSingleFilter(it, civInfo) })
} }
@Readonly @Suppress("purity") @Readonly
private fun matchesSingleFilter(filter: String, civInfo: Civilization? = null): Boolean { private fun matchesSingleFilter(filter: String, civInfo: Civilization? = null): Boolean {
if (matchesSingleTerrainFilter(filter, civInfo)) return true if (matchesSingleTerrainFilter(filter, civInfo)) return true
if ((improvement == null || improvementIsPillaged) && filter == "unimproved") return true if ((improvement == null || improvementIsPillaged) && filter == "unimproved") return true
@ -508,7 +522,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
else matchesSingleTerrainFilter(filter, observingCiv) else matchesSingleTerrainFilter(filter, observingCiv)
} }
@Readonly @Suppress("purity")
private fun matchesSingleTerrainFilter(filter: String, observingCiv: Civilization?): Boolean { private fun matchesSingleTerrainFilter(filter: String, observingCiv: Civilization?): Boolean {
// Constant strings get their own 'when' for performance - // Constant strings get their own 'when' for performance -
// see https://yairm210.medium.com/kotlin-when-string-optimization-e15c6eea2734 // see https://yairm210.medium.com/kotlin-when-string-optimization-e15c6eea2734

View File

@ -14,6 +14,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.ui.components.extensions.toPercent import com.unciv.ui.components.extensions.toPercent
import com.unciv.ui.objectdescriptions.ImprovementDescriptions import com.unciv.ui.objectdescriptions.ImprovementDescriptions
import com.unciv.ui.screens.civilopediascreen.FormattedLine import com.unciv.ui.screens.civilopediascreen.FormattedLine
import yairm210.purity.annotations.Readonly
import kotlin.math.roundToInt import kotlin.math.roundToInt
class TileImprovement : RulesetStatsObject() { class TileImprovement : RulesetStatsObject() {
@ -50,8 +51,11 @@ class TileImprovement : RulesetStatsObject() {
fun getDescription(ruleset: Ruleset): String = ImprovementDescriptions.getDescription(this, ruleset) fun getDescription(ruleset: Ruleset): String = ImprovementDescriptions.getDescription(this, ruleset)
fun getShortDecription() = ImprovementDescriptions.getShortDescription(this) fun getShortDecription() = ImprovementDescriptions.getShortDescription(this)
@Readonly
fun isGreatImprovement() = hasUnique(UniqueType.GreatImprovement) fun isGreatImprovement() = hasUnique(UniqueType.GreatImprovement)
@Readonly
fun isRoad() = RoadStatus.entries.any { it != RoadStatus.None && it.name == this.name } fun isRoad() = RoadStatus.entries.any { it != RoadStatus.None && it.name == this.name }
@Readonly
fun isAncientRuinsEquivalent() = hasUnique(UniqueType.IsAncientRuinsEquivalent) fun isAncientRuinsEquivalent() = hasUnique(UniqueType.IsAncientRuinsEquivalent)
fun canBeBuiltOn(terrain: String): Boolean { fun canBeBuiltOn(terrain: String): Boolean {
@ -77,6 +81,7 @@ class TileImprovement : RulesetStatsObject() {
/** Implements [UniqueParameterType.ImprovementFilter][com.unciv.models.ruleset.unique.UniqueParameterType.ImprovementFilter] */ /** Implements [UniqueParameterType.ImprovementFilter][com.unciv.models.ruleset.unique.UniqueParameterType.ImprovementFilter] */
@Readonly
fun matchesFilter(filter: String, tileState: GameContext? = null, multiFilter: Boolean = true): Boolean { fun matchesFilter(filter: String, tileState: GameContext? = null, multiFilter: Boolean = true): Boolean {
return if (multiFilter) MultiFilter.multiFilter(filter, { return if (multiFilter) MultiFilter.multiFilter(filter, {
matchesSingleFilter(it) || matchesSingleFilter(it) ||
@ -88,6 +93,7 @@ class TileImprovement : RulesetStatsObject() {
tileState == null && hasTagUnique(filter) tileState == null && hasTagUnique(filter)
} }
@Readonly
private fun matchesSingleFilter(filter: String): Boolean { private fun matchesSingleFilter(filter: String): Boolean {
return when (filter) { return when (filter) {
"all", "All" -> true "all", "All" -> true

View File

@ -8,6 +8,7 @@ import com.unciv.models.ruleset.tech.TechColumn
import com.unciv.models.ruleset.tech.Technology import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.stats.INamed import com.unciv.models.stats.INamed
import com.unciv.ui.components.extensions.toPercent import com.unciv.ui.components.extensions.toPercent
import yairm210.purity.annotations.Readonly
/** /**
* Common interface for all 'ruleset objects' that have Uniques, like BaseUnit, Nation, etc. * Common interface for all 'ruleset objects' that have Uniques, like BaseUnit, Nation, etc.
@ -48,12 +49,15 @@ interface IHasUniques : INamed {
fun getMatchingUniques(uniqueTag: String, state: GameContext = GameContext.EmptyState) = fun getMatchingUniques(uniqueTag: String, state: GameContext = GameContext.EmptyState) =
uniqueMap.getMatchingUniques(uniqueTag, state) uniqueMap.getMatchingUniques(uniqueTag, state)
@Readonly
fun hasUnique(uniqueType: UniqueType, state: GameContext? = null) = fun hasUnique(uniqueType: UniqueType, state: GameContext? = null) =
uniqueMap.hasMatchingUnique(uniqueType, state ?: GameContext.EmptyState) uniqueMap.hasMatchingUnique(uniqueType, state ?: GameContext.EmptyState)
@Readonly
fun hasUnique(uniqueTag: String, state: GameContext? = null) = fun hasUnique(uniqueTag: String, state: GameContext? = null) =
uniqueMap.hasMatchingUnique(uniqueTag, state ?: GameContext.EmptyState) uniqueMap.hasMatchingUnique(uniqueTag, state ?: GameContext.EmptyState)
@Readonly
fun hasTagUnique(tagUnique: String) = fun hasTagUnique(tagUnique: String) =
uniqueMap.hasTagUnique(tagUnique) uniqueMap.hasTagUnique(tagUnique)