mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-23 03:23:17 -04:00
chore(purity): Converted internal state classes to use annotations
This commit is contained in:
parent
064ba90990
commit
714fc6cfa6
@ -38,7 +38,7 @@ plugins {
|
||||
// This is *with* gradle 8.2 downloaded according the project specs, no idea what that's about
|
||||
kotlin("multiplatform") version "1.9.24"
|
||||
kotlin("plugin.serialization") version "1.9.24"
|
||||
id("io.github.yairm210.purity-plugin") version "0.0.49" apply(false)
|
||||
id("io.github.yairm210.purity-plugin") version "0.0.51" apply(false)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@ -59,12 +59,6 @@ allprojects {
|
||||
)
|
||||
wellKnownInternalStateClasses = setOf(
|
||||
"com.badlogic.gdx.math.Vector2",
|
||||
"com.unciv.models.stats.Stats",
|
||||
"com.unciv.models.Counter",
|
||||
"com.unciv.models.ruleset.tile.ResourceSupplyList",
|
||||
"com.unciv.models.ruleset.validation.RulesetErrorList",
|
||||
"com.unciv.logic.map.BFS",
|
||||
"com.unciv.logic.trade.TradeOffersList",
|
||||
)
|
||||
warnOnPossibleAnnotations = true
|
||||
}
|
||||
@ -176,7 +170,7 @@ project(":core") {
|
||||
"implementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||
"implementation"("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
||||
|
||||
"implementation"("io.github.yairm210:purity-annotations:0.0.40")
|
||||
"implementation"("io.github.yairm210:purity-annotations:0.0.51")
|
||||
|
||||
"implementation"("io.ktor:ktor-client-core:$ktorVersion")
|
||||
"implementation"("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.map
|
||||
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import yairm210.purity.annotations.InternalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.collections.ArrayDeque
|
||||
|
||||
@ -10,6 +11,7 @@ import kotlin.collections.ArrayDeque
|
||||
* @param startingPoint Starting [Tile] from which to start the search
|
||||
* @param predicate A condition for subsequent neighboring tiles to be considered in search
|
||||
*/
|
||||
@InternalState
|
||||
class BFS(
|
||||
val startingPoint: Tile,
|
||||
private val predicate : (Tile) -> Boolean
|
||||
|
@ -1,7 +1,9 @@
|
||||
package com.unciv.logic.trade
|
||||
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import yairm210.purity.annotations.InternalState
|
||||
|
||||
@InternalState
|
||||
class TradeOffersList: ArrayList<TradeOffer>(), IsPartOfGameInfoSerialization {
|
||||
override fun add(element: TradeOffer): Boolean {
|
||||
val equivalentOffer = firstOrNull { it.name == element.name && it.type == element.type }
|
||||
|
@ -3,6 +3,7 @@ package com.unciv.models
|
||||
import com.badlogic.gdx.utils.Json
|
||||
import com.badlogic.gdx.utils.JsonValue
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import yairm210.purity.annotations.InternalState
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
@ -14,6 +15,7 @@ import yairm210.purity.annotations.Readonly
|
||||
* - Therefore, Deserialization works properly ***only*** with [K] === String.
|
||||
* (ignoring this will return a deserialized map, but the keys will violate the compile-time type and BE strings)
|
||||
*/
|
||||
@InternalState
|
||||
open class Counter<K>(
|
||||
fromMap: Map<K, Int>? = null
|
||||
) : LinkedHashMap<K, Int>(fromMap?.size ?: 10), IsPartOfGameInfoSerialization, Json.Serializable {
|
||||
|
@ -3,12 +3,14 @@ package com.unciv.models.ruleset.tile
|
||||
import com.unciv.Constants
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.IConstruction // Kdoc only
|
||||
import yairm210.purity.annotations.InternalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
/** Container helps aggregating supply and demand of [resources][ResourceSupply.resource], categorized by [origin][ResourceSupply.origin].
|
||||
*
|
||||
* @param keepZeroAmounts If `false`, entries with [amount][ResourceSupply.amount] 0 are eliminated
|
||||
*/
|
||||
@InternalState
|
||||
class ResourceSupplyList(
|
||||
private val keepZeroAmounts: Boolean = false
|
||||
) : ArrayList<ResourceSupplyList.ResourceSupply>(24) {
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.validation.ModCompatibility.meetsAllRequirements
|
||||
import com.unciv.models.ruleset.validation.ModCompatibility.meetsBaseRequirements
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
/**
|
||||
* Helper collection dealing with declarative Mod compatibility
|
||||
@ -28,8 +29,9 @@ object ModCompatibility {
|
||||
*
|
||||
* Note: The guessing part may potentially be deprecated and removed if we get our Modders to complete declarative coverage.
|
||||
*/
|
||||
fun isAudioVisualMod(mod: Ruleset) = isAudioVisualDeclared(mod) ?: isAudioVisualGuessed(mod)
|
||||
@Readonly fun isAudioVisualMod(mod: Ruleset) = isAudioVisualDeclared(mod) ?: isAudioVisualGuessed(mod)
|
||||
|
||||
@Readonly
|
||||
private fun isAudioVisualDeclared(mod: Ruleset): Boolean? {
|
||||
if (mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)) return true
|
||||
if (mod.modOptions.hasUnique(UniqueType.ModIsAudioVisual)) return true
|
||||
@ -38,6 +40,7 @@ object ModCompatibility {
|
||||
}
|
||||
|
||||
// If there's media (audio folders or any atlas), show the PAV choice...
|
||||
@Readonly @Suppress("purity") // requies marking file functions
|
||||
private fun isAudioVisualGuessed(mod: Ruleset): Boolean {
|
||||
val folder = mod.folderLocation ?: return false // Also catches isBuiltin
|
||||
fun isSubFolderNotEmpty(modFolder: FileHandle, name: String): Boolean {
|
||||
@ -52,11 +55,14 @@ object ModCompatibility {
|
||||
return folder.list("atlas").isNotEmpty()
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun isExtensionMod(mod: Ruleset) =
|
||||
!mod.modOptions.isBaseRuleset
|
||||
&& mod.name.isNotBlank()
|
||||
&& !mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)
|
||||
|
||||
@Readonly
|
||||
@Suppress("purity") // requies marking file functions
|
||||
fun isConstantsOnly(mod: Ruleset): Boolean {
|
||||
val folder = mod.folderLocation ?: return false
|
||||
if (folder.list("atlas").isNotEmpty()) return false
|
||||
@ -73,10 +79,12 @@ object ModCompatibility {
|
||||
return partialName in modName.lowercase()
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun isIncompatibleWith(mod: Ruleset, otherMod: Ruleset) =
|
||||
mod.modOptions.getMatchingUniques(UniqueType.ModIncompatibleWith)
|
||||
.any { modNameFilter(otherMod.name, it.params[0]) }
|
||||
|
||||
@Readonly
|
||||
private fun isIncompatible(mod: Ruleset, otherMod: Ruleset) =
|
||||
isIncompatibleWith(mod, otherMod) || isIncompatibleWith(otherMod, mod)
|
||||
|
||||
@ -88,6 +96,7 @@ object ModCompatibility {
|
||||
* - For each ModRequires: Not ([baseRuleset] meets filter OR any other cached _extension_ mod meets filter) -> Nope
|
||||
* - All ModRequires tested -> OK
|
||||
*/
|
||||
@Readonly
|
||||
fun meetsBaseRequirements(mod: Ruleset, baseRuleset: Ruleset): Boolean {
|
||||
if (isIncompatible(mod, baseRuleset)) return false
|
||||
|
||||
@ -115,6 +124,7 @@ object ModCompatibility {
|
||||
* - For each ModRequires: Not([baseRuleset] meets filter OR any other **selected** extension mod meets filter) -> Nope
|
||||
* - All ModRequires tested -> OK
|
||||
*/
|
||||
@Readonly
|
||||
fun meetsAllRequirements(mod: Ruleset, baseRuleset: Ruleset, selectedExtensionMods: Iterable<Ruleset>): Boolean {
|
||||
val otherSelectedExtensionMods = selectedExtensionMods.filterNot { it == mod }.toList()
|
||||
if (otherSelectedExtensionMods.any { isIncompatible(mod, it) }) return false
|
||||
|
@ -6,7 +6,8 @@ import com.unciv.models.ruleset.unique.IHasUniques
|
||||
import com.unciv.models.ruleset.unique.GameContext
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.InternalState
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
class RulesetError(val text: String, val errorSeverityToReport: RulesetErrorSeverity)
|
||||
@ -31,6 +32,7 @@ enum class RulesetErrorSeverity(val color: Color, val iconName: String) {
|
||||
*
|
||||
* @param ruleset The ruleset being validated (needed to check modOptions for suppression uniques). Leave `null` only for validation results that need no suppression checks.
|
||||
*/
|
||||
@InternalState
|
||||
class RulesetErrorList(
|
||||
ruleset: Ruleset? = null
|
||||
) : ArrayList<RulesetError>() {
|
||||
@ -87,20 +89,23 @@ class RulesetErrorList(
|
||||
return true
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getFinalSeverity(): RulesetErrorSeverity {
|
||||
if (isEmpty()) return RulesetErrorSeverity.OK
|
||||
return this.maxOf { it.errorSeverityToReport }
|
||||
}
|
||||
|
||||
/** @return `true` means severe errors make the mod unplayable */
|
||||
fun isError() = getFinalSeverity() == RulesetErrorSeverity.Error
|
||||
@Readonly fun isError() = getFinalSeverity() == RulesetErrorSeverity.Error
|
||||
/** @return `true` means problems exist, Options screen mod checker or unit tests for vanilla ruleset should complain */
|
||||
fun isNotOK() = getFinalSeverity() != RulesetErrorSeverity.OK
|
||||
@Readonly fun isNotOK() = getFinalSeverity() != RulesetErrorSeverity.OK
|
||||
/** @return `true` means at least errors impacting gameplay exist, new game screen should warn or block */
|
||||
fun isWarnUser() = getFinalSeverity() >= RulesetErrorSeverity.Warning
|
||||
@Readonly fun isWarnUser() = getFinalSeverity() >= RulesetErrorSeverity.Warning
|
||||
|
||||
fun getErrorText(unfiltered: Boolean = false) =
|
||||
@Readonly fun getErrorText(unfiltered: Boolean = false) =
|
||||
getErrorText { unfiltered || it.errorSeverityToReport > RulesetErrorSeverity.WarningOptionsOnly }
|
||||
|
||||
@Readonly
|
||||
fun getErrorText(filter: (RulesetError)->Boolean) =
|
||||
filter(filter)
|
||||
.sortedByDescending { it.errorSeverityToReport }
|
||||
@ -114,7 +119,7 @@ class RulesetErrorList(
|
||||
companion object {
|
||||
/** Helper factory for a single entry list (which can result in an empty list due to suppression)
|
||||
* Note: Valid source for [addAll] since suppression is already taken care of. */
|
||||
@Readonly
|
||||
@Pure
|
||||
fun of(
|
||||
text: String,
|
||||
severity: RulesetErrorSeverity = RulesetErrorSeverity.Error,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.models.stats
|
||||
|
||||
import com.unciv.models.translations.tr
|
||||
import yairm210.purity.annotations.InternalState
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
@ -12,6 +13,7 @@ import yairm210.purity.annotations.Readonly
|
||||
*
|
||||
* Also possible: `<Stats>`.[values].sum() and similar aggregates over a Sequence<Float>.
|
||||
*/
|
||||
@InternalState
|
||||
open class Stats(
|
||||
var production: Float = 0f,
|
||||
var food: Float = 0f,
|
||||
|
Loading…
x
Reference in New Issue
Block a user