mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-09 20:29:50 +07:00
(CQ) Linting and comments on TileSetStrings and ImageAttempter (#10582)
* (CQ) Linting and comments on TileSetStrings and ImageAttempter * (CQ) Linting and comments on TileSetStrings and ImageAttempter - some more
This commit is contained in:
parent
50ce8b30b6
commit
20fa1d3f06
@ -9,11 +9,29 @@ import com.unciv.models.tilesets.TileSetConfig
|
||||
import com.unciv.ui.images.ImageAttempter
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate") // No advandage hiding them
|
||||
|
||||
/**
|
||||
* Resolver translating more abstract tile data to paint on a map into actual texture names.
|
||||
*
|
||||
* Deals with variants, e.g. there could be a "City center-asian-Ancient era.png" that would be chosen
|
||||
* for a "City center"-containing Tile when it is to be drawn for a Nation defining it's style as "asian"
|
||||
* and whose techs say it's still in the first vanilla Era.
|
||||
*
|
||||
* Instantiated once per [TileGroupMap] and per [TileSet][com.unciv.models.tilesets.TileSet] -
|
||||
* typically once for HexaRealm and once for FantasyHex (fallback) at the start of a player turn,
|
||||
* and the same two every time they enter a CityScreen.
|
||||
*
|
||||
* @param tileSet Name of the tileset. Defaults to active at time of instantiation.
|
||||
* @param fallbackDepth Maximum number of fallback tilesets to try. Used to prevent infinite recursion.
|
||||
* */
|
||||
class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitSet: String? = UncivGame.Current.settings.unitSet, fallbackDepth: Int = 1) {
|
||||
class TileSetStrings(
|
||||
tileSet: String = UncivGame.Current.settings.tileSet,
|
||||
unitSet: String? = UncivGame.Current.settings.unitSet,
|
||||
fallbackDepth: Int = 1
|
||||
) {
|
||||
/** Separator used to mark variants, e.g. nation style or era specific */
|
||||
val tag = "-"
|
||||
|
||||
// this is so that when we have 100s of TileGroups, they won't all individually come up with all these strings themselves,
|
||||
// it gets pretty memory-intensive (10s of MBs which is a lot for lower-end phones)
|
||||
@ -24,7 +42,7 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
val tileSetConfig = TileSetCache[tileSet]?.config ?: TileSetConfig()
|
||||
|
||||
// These need to be by lazy since the orFallback expects a tileset, which it may not get.
|
||||
val hexagon: String by lazy { orFallback {tileSetLocation + "Hexagon"} }
|
||||
val hexagon: String by lazy { orFallback { tileSetLocation + "Hexagon"} }
|
||||
val hexagonList by lazy { listOf(hexagon) }
|
||||
val crosshatchHexagon by lazy { orFallback { tileSetLocation + "CrosshatchHexagon" } }
|
||||
val unexploredTile by lazy { orFallback { tileSetLocation + "UnexploredTile" } }
|
||||
@ -68,7 +86,6 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
return currentString
|
||||
}
|
||||
|
||||
val tag = "-"
|
||||
fun getTile(baseTerrain: String) = getString(tilesLocation, baseTerrain)
|
||||
|
||||
fun getBorder(borderShapeString: String, innerOrOuter:String) = getString(bordersLocation, borderShapeString, innerOrOuter)
|
||||
@ -81,7 +98,6 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
TileSetStrings(tileSetConfig.fallbackTileSet!!, tileSetConfig.fallbackTileSet!!, fallbackDepth-1)
|
||||
}
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
/**
|
||||
* @param image An image path string, such as returned from an instance of [TileSetStrings].
|
||||
* @param fallbackImage A lambda function that will be run with the [fallback] as its receiver if the original image does not exist according to [ImageGetter.imageExists].
|
||||
@ -90,18 +106,18 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
fun orFallback(image: String, fallbackImage: TileSetStrings.() -> String): String {
|
||||
return if (fallback == null || ImageGetter.imageExists(image))
|
||||
image
|
||||
else fallback!!.run(fallbackImage)
|
||||
else fallbackImage.invoke(fallback!!)
|
||||
}
|
||||
|
||||
/** @see orFallback */
|
||||
fun orFallback(image: TileSetStrings.() -> String)
|
||||
= orFallback(this.run(image), image)
|
||||
= orFallback(image.invoke(this), image)
|
||||
|
||||
|
||||
|
||||
/** For caching image locations based on given parameters (era, style, etc)
|
||||
* Based on what the final image would look like if all parameters existed,
|
||||
* like "pikeman-Medieval era-France": "pikeman" */
|
||||
* like "pikeman-France-Medieval era": "pikeman" */
|
||||
val imageParamsToImageLocation = HashMap<String,String>()
|
||||
|
||||
|
||||
@ -110,6 +126,7 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
|
||||
val embarkedCivilianUnitLocation = getString(unitsLocation, "EmbarkedUnit-Civilian")
|
||||
val hasEmbarkedCivilianUnitImage = ImageGetter.imageExists(embarkedCivilianUnitLocation)
|
||||
|
||||
/**
|
||||
* Image fallbacks work by precedence.
|
||||
* So currently, if you're france, it's the modern era, and you have a pikeman:
|
||||
@ -119,7 +136,6 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
* This means that if there's a "pikeman-France" and a "pikeman-Medieval era",
|
||||
* The era-based image wins out, even though it's not the current era.
|
||||
*/
|
||||
|
||||
private fun tryGetUnitImageLocation(unit: MapUnit): String? {
|
||||
|
||||
var baseUnitIconLocation = getString(this.unitsLocation, unit.name)
|
||||
@ -139,13 +155,13 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
val style = civInfo.nation.getStyleOrCivName()
|
||||
|
||||
var imageAttempter = ImageAttempter(baseUnitIconLocation)
|
||||
// Era+style image: looks like "pikeman-Medieval era-France"
|
||||
// Era+style image: looks like "pikeman-France-Medieval era"
|
||||
// More advanced eras default to older eras
|
||||
.tryEraImage(civInfo, baseUnitIconLocation, style, this)
|
||||
// Era-only image: looks like "pikeman-Medieval era"
|
||||
.tryEraImage(civInfo, baseUnitIconLocation, null, this)
|
||||
// Style era: looks like "pikeman-France" or "pikeman-European"
|
||||
.tryImage { getString(baseUnitIconLocation, tag, civInfo.nation.getStyleOrCivName()) }
|
||||
.tryImage { getString(baseUnitIconLocation, tag, style) }
|
||||
.tryImage { baseUnitIconLocation }
|
||||
|
||||
if (unit.baseUnit.replaces != null)
|
||||
@ -154,7 +170,7 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
return imageAttempter.getPathOrNull()
|
||||
}
|
||||
|
||||
fun getUnitImageLocation(unit: MapUnit):String {
|
||||
fun getUnitImageLocation(unit: MapUnit): String {
|
||||
val imageKey = getString(
|
||||
unit.name, tag,
|
||||
unit.civ.getEra().name, tag,
|
||||
@ -163,7 +179,7 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
)
|
||||
// if in cache return that
|
||||
val currentImageMapping = imageParamsToImageLocation[imageKey]
|
||||
if (currentImageMapping!=null) return currentImageMapping
|
||||
if (currentImageMapping != null) return currentImageMapping
|
||||
|
||||
val imageLocation = tryGetUnitImageLocation(unit)
|
||||
?: fallback?.tryGetUnitImageLocation(unit)
|
||||
@ -172,7 +188,7 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
return imageLocation
|
||||
}
|
||||
|
||||
private fun tryGetOwnedTileImageLocation(baseLocation:String, owner:Civilization): String? {
|
||||
private fun tryGetOwnedTileImageLocation(baseLocation: String, owner: Civilization): String? {
|
||||
val ownersStyle = owner.nation.getStyleOrCivName()
|
||||
return ImageAttempter(baseLocation)
|
||||
.tryEraImage(owner, baseLocation, ownersStyle, this)
|
||||
@ -181,12 +197,12 @@ class TileSetStrings(tileSet: String = UncivGame.Current.settings.tileSet, unitS
|
||||
.getPathOrNull()
|
||||
}
|
||||
|
||||
fun getOwnedTileImageLocation(baseLocation:String, owner:Civilization): String {
|
||||
fun getOwnedTileImageLocation(baseLocation: String, owner: Civilization): String {
|
||||
val imageKey = getString(baseLocation, tag,
|
||||
owner.getEra().name, tag,
|
||||
owner.nation.getStyleOrCivName())
|
||||
val currentImageMapping = imageParamsToImageLocation[imageKey]
|
||||
if (currentImageMapping!=null) return currentImageMapping
|
||||
if (currentImageMapping != null) return currentImageMapping
|
||||
|
||||
val imageLocation = tryGetOwnedTileImageLocation(baseLocation, owner)
|
||||
?: baseLocation
|
||||
|
@ -3,16 +3,24 @@ package com.unciv.ui.images
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.ui.components.tilegroups.TileSetStrings
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate") // no problem for clients to see scope, imageFound, unused/internally used API
|
||||
|
||||
/**
|
||||
* Metaprogrammy class for short-circuitingly finding the first existing of multiple image options according to [ImageGetter.imageExists].
|
||||
*
|
||||
* Has a [tryImage] method that can be chain-called with functions which return candidate image paths. The first function to return a valid image path stops subsequently chained calls from having any effect, and its result is saved to be retrieved by the [getPath] and [getImage] methods at the end of the candidate chain.
|
||||
* Has a [tryImage] method that can be chain-called with functions which return candidate image paths.
|
||||
* The first function to return a valid image path stops subsequently chained calls from having any effect,
|
||||
* and its result is saved to be retrieved by the [getPath] and [getImage] methods at the end of the candidate chain.
|
||||
*
|
||||
* Binds candidate functions to a [scope] instance provided to primary constructor, for syntactic convenience. Bind to [Unit] when not needed.
|
||||
* (So it is similar to Sequence in that intermediate "transforms" are only evaluated when necessary,
|
||||
* but it is also different as resolution happens early, while chaining, not triggered by a terminating transform.)
|
||||
*
|
||||
* Binds candidate functions to a [scope] instance of type [T] provided to primary constructor, for syntactic convenience. Bind to [Unit] when not needed.
|
||||
*
|
||||
* Non-reusable.
|
||||
*
|
||||
* @property scope Instance to which to bind the candidate-returning functions. For syntactic terseness when making lots of calls to, E.G., [com.unciv.ui.tilegroups.TileSetStrings].
|
||||
* @param T type of [scope]
|
||||
* @property scope Instance to which to bind the candidate-returning functions. For syntactic terseness when making lots of calls to, e.g., [TileSetStrings][com.unciv.ui.components.tilegroups.TileSetStrings].
|
||||
*/
|
||||
class ImageAttempter<out T: Any>(val scope: T) {
|
||||
/** The first valid filename tried if any, or the last filename tried if none have succeeded. */
|
||||
@ -26,11 +34,11 @@ class ImageAttempter<out T: Any>(val scope: T) {
|
||||
*
|
||||
* @see ImageAttempter
|
||||
* @param fileName Function that returns the filename of the image to check. Bound to [scope]. Will not be run if a valid image has already been found. May return `null` to skip this candidate entirely.
|
||||
* @return This [ImageAttempter], for chaining.
|
||||
* @return Chainable `this` [ImageAttempter] extended by one check for [fileName]
|
||||
*/
|
||||
fun tryImage(fileName: T.() -> String?): ImageAttempter<T> {
|
||||
if (!imageFound) {
|
||||
val imagePath = scope.run(fileName)
|
||||
val imagePath = fileName.invoke(scope)
|
||||
lastTriedFileName = imagePath ?: lastTriedFileName
|
||||
if (imagePath != null && ImageGetter.imageExists(imagePath))
|
||||
imageFound = true
|
||||
@ -42,7 +50,7 @@ class ImageAttempter<out T: Any>(val scope: T) {
|
||||
*
|
||||
* @see tryImage
|
||||
* @param fileNames Any number of image candidate returning functions to pass to [tryImage].
|
||||
* @return This [ImageAttempter], for chaining.
|
||||
* @return Chainable `this` [ImageAttempter] extended by zero or more checks for [fileNames]
|
||||
*/
|
||||
fun tryImages(fileNames: Sequence<T.() -> String?>): ImageAttempter<T> {
|
||||
for (fileName in fileNames) {
|
||||
@ -52,9 +60,14 @@ class ImageAttempter<out T: Any>(val scope: T) {
|
||||
}
|
||||
|
||||
/** Try to load era-specific image variants
|
||||
* [civInfo]: the civ who owns the tile or unit
|
||||
* [locationToCheck]: the beginning of the filename to check
|
||||
* [style]: an optional string to load a civ- or style-specific sprite
|
||||
*
|
||||
* Tries eras from the civ's current one down to the first era defined, by json order of eras.
|
||||
* Result looks like "Plains-Rome-Ancient era": [style] goes before era if supplied.
|
||||
*
|
||||
* @param civInfo the civ who owns the tile or unit, used for getEraNumber and ruleset (but not for nation.getStyleOrCivName)
|
||||
* @param locationToCheck the beginning of the filename to check
|
||||
* @param style an optional string to load a civ- or style-specific sprite
|
||||
* @return Chainable `this` [ImageAttempter] extended by one or more checks for era-specific images
|
||||
* */
|
||||
fun tryEraImage(civInfo: Civilization, locationToCheck: String, style: String?, tileSetStrings: TileSetStrings): ImageAttempter<T> {
|
||||
return tryImages(
|
||||
|
Loading…
Reference in New Issue
Block a user