mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -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
|
// This is *with* gradle 8.2 downloaded according the project specs, no idea what that's about
|
||||||
kotlin("multiplatform") version "1.9.24"
|
kotlin("multiplatform") version "1.9.24"
|
||||||
kotlin("plugin.serialization") 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 {
|
allprojects {
|
||||||
@ -59,12 +59,6 @@ allprojects {
|
|||||||
)
|
)
|
||||||
wellKnownInternalStateClasses = setOf(
|
wellKnownInternalStateClasses = setOf(
|
||||||
"com.badlogic.gdx.math.Vector2",
|
"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
|
warnOnPossibleAnnotations = true
|
||||||
}
|
}
|
||||||
@ -176,7 +170,7 @@ project(":core") {
|
|||||||
"implementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
"implementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
|
||||||
"implementation"("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
|
"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-core:$ktorVersion")
|
||||||
"implementation"("io.ktor:ktor-client-cio:$ktorVersion")
|
"implementation"("io.ktor:ktor-client-cio:$ktorVersion")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.logic.map
|
package com.unciv.logic.map
|
||||||
|
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
|
import yairm210.purity.annotations.InternalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.collections.ArrayDeque
|
import kotlin.collections.ArrayDeque
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ import kotlin.collections.ArrayDeque
|
|||||||
* @param startingPoint Starting [Tile] from which to start the search
|
* @param startingPoint Starting [Tile] from which to start the search
|
||||||
* @param predicate A condition for subsequent neighboring tiles to be considered in search
|
* @param predicate A condition for subsequent neighboring tiles to be considered in search
|
||||||
*/
|
*/
|
||||||
|
@InternalState
|
||||||
class BFS(
|
class BFS(
|
||||||
val startingPoint: Tile,
|
val startingPoint: Tile,
|
||||||
private val predicate : (Tile) -> Boolean
|
private val predicate : (Tile) -> Boolean
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package com.unciv.logic.trade
|
package com.unciv.logic.trade
|
||||||
|
|
||||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||||
|
import yairm210.purity.annotations.InternalState
|
||||||
|
|
||||||
|
@InternalState
|
||||||
class TradeOffersList: ArrayList<TradeOffer>(), IsPartOfGameInfoSerialization {
|
class TradeOffersList: ArrayList<TradeOffer>(), IsPartOfGameInfoSerialization {
|
||||||
override fun add(element: TradeOffer): Boolean {
|
override fun add(element: TradeOffer): Boolean {
|
||||||
val equivalentOffer = firstOrNull { it.name == element.name && it.type == element.type }
|
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.Json
|
||||||
import com.badlogic.gdx.utils.JsonValue
|
import com.badlogic.gdx.utils.JsonValue
|
||||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||||
|
import yairm210.purity.annotations.InternalState
|
||||||
import yairm210.purity.annotations.LocalState
|
import yairm210.purity.annotations.LocalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import yairm210.purity.annotations.Readonly
|
|||||||
* - Therefore, Deserialization works properly ***only*** with [K] === String.
|
* - 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)
|
* (ignoring this will return a deserialized map, but the keys will violate the compile-time type and BE strings)
|
||||||
*/
|
*/
|
||||||
|
@InternalState
|
||||||
open class Counter<K>(
|
open class Counter<K>(
|
||||||
fromMap: Map<K, Int>? = null
|
fromMap: Map<K, Int>? = null
|
||||||
) : LinkedHashMap<K, Int>(fromMap?.size ?: 10), IsPartOfGameInfoSerialization, Json.Serializable {
|
) : 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.Constants
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.IConstruction // Kdoc only
|
import com.unciv.models.ruleset.IConstruction // Kdoc only
|
||||||
|
import yairm210.purity.annotations.InternalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
/** Container helps aggregating supply and demand of [resources][ResourceSupply.resource], categorized by [origin][ResourceSupply.origin].
|
/** 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
|
* @param keepZeroAmounts If `false`, entries with [amount][ResourceSupply.amount] 0 are eliminated
|
||||||
*/
|
*/
|
||||||
|
@InternalState
|
||||||
class ResourceSupplyList(
|
class ResourceSupplyList(
|
||||||
private val keepZeroAmounts: Boolean = false
|
private val keepZeroAmounts: Boolean = false
|
||||||
) : ArrayList<ResourceSupplyList.ResourceSupply>(24) {
|
) : 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.meetsAllRequirements
|
||||||
import com.unciv.models.ruleset.validation.ModCompatibility.meetsBaseRequirements
|
import com.unciv.models.ruleset.validation.ModCompatibility.meetsBaseRequirements
|
||||||
import yairm210.purity.annotations.Pure
|
import yairm210.purity.annotations.Pure
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper collection dealing with declarative Mod compatibility
|
* 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.
|
* 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? {
|
private fun isAudioVisualDeclared(mod: Ruleset): Boolean? {
|
||||||
if (mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)) return true
|
if (mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)) return true
|
||||||
if (mod.modOptions.hasUnique(UniqueType.ModIsAudioVisual)) 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...
|
// 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 {
|
private fun isAudioVisualGuessed(mod: Ruleset): Boolean {
|
||||||
val folder = mod.folderLocation ?: return false // Also catches isBuiltin
|
val folder = mod.folderLocation ?: return false // Also catches isBuiltin
|
||||||
fun isSubFolderNotEmpty(modFolder: FileHandle, name: String): Boolean {
|
fun isSubFolderNotEmpty(modFolder: FileHandle, name: String): Boolean {
|
||||||
@ -52,11 +55,14 @@ object ModCompatibility {
|
|||||||
return folder.list("atlas").isNotEmpty()
|
return folder.list("atlas").isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isExtensionMod(mod: Ruleset) =
|
fun isExtensionMod(mod: Ruleset) =
|
||||||
!mod.modOptions.isBaseRuleset
|
!mod.modOptions.isBaseRuleset
|
||||||
&& mod.name.isNotBlank()
|
&& mod.name.isNotBlank()
|
||||||
&& !mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)
|
&& !mod.modOptions.hasUnique(UniqueType.ModIsAudioVisualOnly)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
|
@Suppress("purity") // requies marking file functions
|
||||||
fun isConstantsOnly(mod: Ruleset): Boolean {
|
fun isConstantsOnly(mod: Ruleset): Boolean {
|
||||||
val folder = mod.folderLocation ?: return false
|
val folder = mod.folderLocation ?: return false
|
||||||
if (folder.list("atlas").isNotEmpty()) return false
|
if (folder.list("atlas").isNotEmpty()) return false
|
||||||
@ -73,10 +79,12 @@ object ModCompatibility {
|
|||||||
return partialName in modName.lowercase()
|
return partialName in modName.lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun isIncompatibleWith(mod: Ruleset, otherMod: Ruleset) =
|
private fun isIncompatibleWith(mod: Ruleset, otherMod: Ruleset) =
|
||||||
mod.modOptions.getMatchingUniques(UniqueType.ModIncompatibleWith)
|
mod.modOptions.getMatchingUniques(UniqueType.ModIncompatibleWith)
|
||||||
.any { modNameFilter(otherMod.name, it.params[0]) }
|
.any { modNameFilter(otherMod.name, it.params[0]) }
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun isIncompatible(mod: Ruleset, otherMod: Ruleset) =
|
private fun isIncompatible(mod: Ruleset, otherMod: Ruleset) =
|
||||||
isIncompatibleWith(mod, otherMod) || isIncompatibleWith(otherMod, mod)
|
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
|
* - For each ModRequires: Not ([baseRuleset] meets filter OR any other cached _extension_ mod meets filter) -> Nope
|
||||||
* - All ModRequires tested -> OK
|
* - All ModRequires tested -> OK
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun meetsBaseRequirements(mod: Ruleset, baseRuleset: Ruleset): Boolean {
|
fun meetsBaseRequirements(mod: Ruleset, baseRuleset: Ruleset): Boolean {
|
||||||
if (isIncompatible(mod, baseRuleset)) return false
|
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
|
* - For each ModRequires: Not([baseRuleset] meets filter OR any other **selected** extension mod meets filter) -> Nope
|
||||||
* - All ModRequires tested -> OK
|
* - All ModRequires tested -> OK
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun meetsAllRequirements(mod: Ruleset, baseRuleset: Ruleset, selectedExtensionMods: Iterable<Ruleset>): Boolean {
|
fun meetsAllRequirements(mod: Ruleset, baseRuleset: Ruleset, selectedExtensionMods: Iterable<Ruleset>): Boolean {
|
||||||
val otherSelectedExtensionMods = selectedExtensionMods.filterNot { it == mod }.toList()
|
val otherSelectedExtensionMods = selectedExtensionMods.filterNot { it == mod }.toList()
|
||||||
if (otherSelectedExtensionMods.any { isIncompatible(mod, it) }) return false
|
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.GameContext
|
||||||
import com.unciv.models.ruleset.unique.Unique
|
import com.unciv.models.ruleset.unique.Unique
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
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
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
class RulesetError(val text: String, val errorSeverityToReport: RulesetErrorSeverity)
|
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.
|
* @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(
|
class RulesetErrorList(
|
||||||
ruleset: Ruleset? = null
|
ruleset: Ruleset? = null
|
||||||
) : ArrayList<RulesetError>() {
|
) : ArrayList<RulesetError>() {
|
||||||
@ -87,20 +89,23 @@ class RulesetErrorList(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getFinalSeverity(): RulesetErrorSeverity {
|
fun getFinalSeverity(): RulesetErrorSeverity {
|
||||||
if (isEmpty()) return RulesetErrorSeverity.OK
|
if (isEmpty()) return RulesetErrorSeverity.OK
|
||||||
return this.maxOf { it.errorSeverityToReport }
|
return this.maxOf { it.errorSeverityToReport }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return `true` means severe errors make the mod unplayable */
|
/** @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 */
|
/** @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 */
|
/** @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 }
|
getErrorText { unfiltered || it.errorSeverityToReport > RulesetErrorSeverity.WarningOptionsOnly }
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getErrorText(filter: (RulesetError)->Boolean) =
|
fun getErrorText(filter: (RulesetError)->Boolean) =
|
||||||
filter(filter)
|
filter(filter)
|
||||||
.sortedByDescending { it.errorSeverityToReport }
|
.sortedByDescending { it.errorSeverityToReport }
|
||||||
@ -114,7 +119,7 @@ class RulesetErrorList(
|
|||||||
companion object {
|
companion object {
|
||||||
/** Helper factory for a single entry list (which can result in an empty list due to suppression)
|
/** 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. */
|
* Note: Valid source for [addAll] since suppression is already taken care of. */
|
||||||
@Readonly
|
@Pure
|
||||||
fun of(
|
fun of(
|
||||||
text: String,
|
text: String,
|
||||||
severity: RulesetErrorSeverity = RulesetErrorSeverity.Error,
|
severity: RulesetErrorSeverity = RulesetErrorSeverity.Error,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.models.stats
|
package com.unciv.models.stats
|
||||||
|
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import yairm210.purity.annotations.InternalState
|
||||||
import yairm210.purity.annotations.Pure
|
import yairm210.purity.annotations.Pure
|
||||||
import yairm210.purity.annotations.Readonly
|
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>.
|
* Also possible: `<Stats>`.[values].sum() and similar aggregates over a Sequence<Float>.
|
||||||
*/
|
*/
|
||||||
|
@InternalState
|
||||||
open class Stats(
|
open class Stats(
|
||||||
var production: Float = 0f,
|
var production: Float = 0f,
|
||||||
var food: Float = 0f,
|
var food: Float = 0f,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user