More and probably final memory performance modifications - we're down from ~400MB on peak of initial update() to about 200MB!

Definitely sped things up along the way as well, not sure by how much though
This commit is contained in:
Yair Morgenstern 2019-07-24 00:37:12 +03:00
parent d33a553d58
commit 858ae5be7c
21 changed files with 104 additions and 73 deletions

View File

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.app" applicationId "com.unciv.app"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 28 targetSdkVersion 28
versionCode 275 versionCode 276
versionName "2.18.4" versionName "2.18.5"
} }
// Had to add this crap for Travis to build, it wanted to sign the app // Had to add this crap for Travis to build, it wanted to sign the app

View File

@ -14,5 +14,6 @@ class Constants{
const val peaceTreaty = "Peace Treaty" const val peaceTreaty = "Peace Treaty"
const val barbarianEncampment = "Barbarian encampment" const val barbarianEncampment = "Barbarian encampment"
const val ancientRuins = "Ancient ruins" const val ancientRuins = "Ancient ruins"
val greatImprovements = listOf("Academy", "Landmark", "Manufactory", "Customs house")
} }
} }

View File

@ -216,7 +216,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
} }
private fun addProductionBuildingChoice() { private fun addProductionBuildingChoice() {
val hasWaterResource = cityInfo.getTilesInRange().any { it.isWater && it.resource!=null } val hasWaterResource = cityInfo.tilesInRange
.any { it.isWater && it.resource!=null && it.position in cityInfo.tiles }
val productionBuilding = buildableNotWonders val productionBuilding = buildableNotWonders
.filter { it.isStatRelated(Stat.Production) .filter { it.isStatRelated(Stat.Production)
|| (hasWaterResource && (it.uniques.contains("+1 production and gold from all sea resources worked by the city") || (hasWaterResource && (it.uniques.contains("+1 production and gold from all sea resources worked by the city")

View File

@ -18,7 +18,7 @@ class SpecificUnitAutomation{
} }
fun automateWorkBoats(unit: MapUnit) { fun automateWorkBoats(unit: MapUnit) {
val seaResourcesInCities = unit.civInfo.cities.flatMap { it.getTilesInRange() }.asSequence() val seaResourcesInCities = unit.civInfo.cities.flatMap { city -> city.getWorkableTiles() }
.filter { hasWorkableSeaResource(it, unit.civInfo) && (unit.movement.canMoveTo(it) || unit.currentTile == it) } .filter { hasWorkableSeaResource(it, unit.civInfo) && (unit.movement.canMoveTo(it) || unit.currentTile == it) }
val closestReachableResource = seaResourcesInCities.sortedBy { it.arialDistanceTo(unit.currentTile) } val closestReachableResource = seaResourcesInCities.sortedBy { it.arialDistanceTo(unit.currentTile) }
.firstOrNull { unit.movement.canReach(it) } .firstOrNull { unit.movement.canReach(it) }

View File

@ -20,6 +20,7 @@ class CityInfo {
@Transient lateinit var ccenterTile:TileInfo // cached for better performance @Transient lateinit var ccenterTile:TileInfo // cached for better performance
@Transient val range = 2 @Transient val range = 2
@Transient lateinit var tileMap: TileMap @Transient lateinit var tileMap: TileMap
@Transient lateinit var tilesInRange:HashSet<TileInfo>
var location: Vector2 = Vector2.Zero var location: Vector2 = Vector2.Zero
var name: String = "" var name: String = ""
@ -103,7 +104,7 @@ class CityInfo {
fun getCenterTile(): TileInfo = ccenterTile fun getCenterTile(): TileInfo = ccenterTile
fun getTiles(): List<TileInfo> = tiles.map { tileMap[it] } fun getTiles(): List<TileInfo> = tiles.map { tileMap[it] }
fun getTilesInRange(): List<TileInfo> = getCenterTile().getTilesInDistance( 3) fun getWorkableTiles() = getTiles().filter { it in tilesInRange }
fun getCityResources(): ResourceSupplyList { fun getCityResources(): ResourceSupplyList {
val cityResources = ResourceSupplyList() val cityResources = ResourceSupplyList()
@ -190,6 +191,7 @@ class CityInfo {
fun setTransients() { fun setTransients() {
tileMap = civInfo.gameInfo.tileMap tileMap = civInfo.gameInfo.tileMap
ccenterTile = tileMap[location] ccenterTile = tileMap[location]
tilesInRange = getCenterTile().getTilesInDistance( 3).toHashSet()
population.cityInfo = this population.cityInfo = this
expansion.cityInfo = this expansion.cityInfo = this
expansion.setTransients() expansion.setTransients()

View File

@ -27,7 +27,8 @@ class CityStats {
//region pure fuctions //region pure fuctions
private fun getStatsFromTiles(): Stats { private fun getStatsFromTiles(): Stats {
val stats = Stats() val stats = Stats()
for (cell in cityInfo.getTilesInRange().filter { cityInfo.workedTiles.contains(it.position) || cityInfo.location == it.position }) for (cell in cityInfo.tilesInRange
.filter { cityInfo.location == it.position || cityInfo.workedTiles.contains(it.position) })
stats.add(cell.getTileStats(cityInfo, cityInfo.civInfo)) stats.add(cell.getTileStats(cityInfo, cityInfo.civInfo))
return stats return stats
} }

View File

@ -1,7 +1,6 @@
package com.unciv.logic.civilization package com.unciv.logic.civilization
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.BFS import com.unciv.logic.map.BFS
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
@ -10,21 +9,8 @@ import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.ResourceSupplyList import com.unciv.models.gamebasics.tile.ResourceSupplyList
import com.unciv.models.gamebasics.tr import com.unciv.models.gamebasics.tr
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.collections.addAll
import kotlin.collections.arrayListOf
import kotlin.collections.asSequence
import kotlin.collections.filter
import kotlin.collections.filterNot
import kotlin.collections.flatMap
import kotlin.collections.isNotEmpty
import kotlin.collections.map
import kotlin.collections.mapNotNull
import kotlin.collections.mutableListOf
import kotlin.collections.plusAssign
import kotlin.collections.set import kotlin.collections.set
import kotlin.collections.toList
/** CivInfo class was getting too crowded */ /** CivInfo class was getting too crowded */
class CivInfoTransientUpdater(val civInfo: CivilizationInfo){ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
@ -43,7 +29,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles
// updating the viewable tiles also affects the explored tiles, obvs // updating the viewable tiles also affects the explored tiles, obvs
val newExploredTiles = HashSet<Vector2>(civInfo.exploredTiles) val newExploredTiles = HashSet(civInfo.exploredTiles)
newExploredTiles.addAll(newViewableTiles.asSequence().map { it.position } newExploredTiles.addAll(newViewableTiles.asSequence().map { it.position }
.filterNot { civInfo.exploredTiles.contains(it) }) .filterNot { civInfo.exploredTiles.contains(it) })
civInfo.exploredTiles = newExploredTiles // ditto civInfo.exploredTiles = newExploredTiles // ditto

View File

@ -27,10 +27,12 @@ class BFS(val startingPoint: TileInfo, val predicate : (TileInfo) -> Boolean){
fun nextStep(){ fun nextStep(){
val newTilesToCheck = ArrayList<TileInfo>() val newTilesToCheck = ArrayList<TileInfo>()
for(tileInfo in tilesToCheck){ for(tileInfo in tilesToCheck){
val fitNeighbors = tileInfo.neighbors.asSequence() for(neighbor in tileInfo.neighbors){
.filter(predicate) if(predicate(neighbor) && !tilesReached.containsKey(neighbor)){
.filter{!tilesReached.containsKey(it)} tilesReached[neighbor] = tileInfo;
fitNeighbors.forEach { tilesReached[it] = tileInfo; newTilesToCheck.add(it) } newTilesToCheck.add(neighbor)
}
}
} }
tilesToCheck = newTilesToCheck tilesToCheck = newTilesToCheck
} }

View File

@ -53,12 +53,12 @@ open class TileInfo {
} }
fun containsGreatImprovement(): Boolean { fun containsGreatImprovement(): Boolean {
if (improvement in listOf("Academy", "Landmark", "Manufactory", "Customs house")) return true if (improvement in Constants.greatImprovements) return true
return false return false
} }
fun containsUnfinishedGreatImprovement(): Boolean { fun containsUnfinishedGreatImprovement(): Boolean {
if (improvementInProgress in listOf("Academy", "Landmark", "Manufactory", "Customs house")) return true if (improvementInProgress in Constants.greatImprovements) return true
return false return false
} }
@ -66,6 +66,8 @@ open class TileInfo {
/** Returns military, civilian and air units in tile */ /** Returns military, civilian and air units in tile */
fun getUnits(): List<MapUnit> { fun getUnits(): List<MapUnit> {
if(militaryUnit==null && civilianUnit==null && airUnits.isEmpty())
return emptyList() // for performance reasons - costs much less to initialize than an empty ArrayList or list()
val list = ArrayList<MapUnit>(2) val list = ArrayList<MapUnit>(2)
if(militaryUnit!=null) list.add(militaryUnit!!) if(militaryUnit!=null) list.add(militaryUnit!!)
if(civilianUnit!=null) list.add(civilianUnit!!) if(civilianUnit!=null) list.add(civilianUnit!!)

View File

@ -282,7 +282,7 @@ class Building : NamedStats(), IConstruction{
return "Requires [$requiredResource]" return "Requires [$requiredResource]"
if (requiredNearbyImprovedResources != null) { if (requiredNearbyImprovedResources != null) {
val containsResourceWithImprovement = construction.cityInfo.getTilesInRange() val containsResourceWithImprovement = construction.cityInfo.getWorkableTiles()
.any { .any {
it.resource != null it.resource != null
&& requiredNearbyImprovedResources!!.contains(it.resource!!) && requiredNearbyImprovedResources!!.contains(it.resource!!)

View File

@ -52,7 +52,7 @@ class Translations : HashMap<String, HashMap<String, String>>(){
} }
} }
val squareBraceRegex = Regex("\\[(.*?)\\]") // we don't need to allocate different memory for this every time we .tr()
fun String.tr(): String { fun String.tr(): String {
if(contains("[")){ // Placeholders! if(contains("[")){ // Placeholders!
/** /**
@ -68,7 +68,6 @@ fun String.tr(): String {
* We will find the german placeholder text, and replace the placeholders with what was filled in the text we got! * We will find the german placeholder text, and replace the placeholders with what was filled in the text we got!
*/ */
val squareBraceRegex = Regex("\\[(.*?)\\]")
val translationStringWithSquareBracketsOnly = replace(squareBraceRegex,"[]") val translationStringWithSquareBracketsOnly = replace(squareBraceRegex,"[]")
val translationStringUntilFirstSquareBracket = substringBefore('[') val translationStringUntilFirstSquareBracket = substringBefore('[')
val englishTranslationPlaceholder = GameBasics.Translations.keys val englishTranslationPlaceholder = GameBasics.Translations.keys

View File

@ -100,6 +100,6 @@ open class Stats() {
class StatMap:LinkedHashMap<String,Stats>(){ class StatMap:LinkedHashMap<String,Stats>(){
fun add(source:String,stats:Stats){ fun add(source:String,stats:Stats){
if(!containsKey(source)) put(source,stats) if(!containsKey(source)) put(source,stats)
else put(source, get(source)!!+stats) else get(source)!!.add(stats)
} }
} }

View File

@ -12,6 +12,7 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.tr import com.unciv.models.gamebasics.tr
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.TileGroupMap import com.unciv.ui.worldscreen.TileGroupMap
import java.util.* import java.util.*
@ -181,11 +182,11 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
private fun addTiles() { private fun addTiles() {
val cityInfo = city val cityInfo = city
val tileSetStrings = TileSetStrings()
val cityTileGroups = cityInfo.getCenterTile().getTilesInDistance(5) val cityTileGroups = cityInfo.getCenterTile().getTilesInDistance(5)
.filter { city.civInfo.exploredTiles.contains(it.position) } .filter { city.civInfo.exploredTiles.contains(it.position) }
.map { CityTileGroup(cityInfo, it) } .map { CityTileGroup(cityInfo, it, tileSetStrings) }
val tilesInRange = city.getTilesInRange()
for (tileGroup in cityTileGroups) { for (tileGroup in cityTileGroups) {
val tileInfo = tileGroup.tileInfo val tileInfo = tileGroup.tileInfo

View File

@ -6,12 +6,14 @@ import com.unciv.UnCivGame
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.centerX import com.unciv.ui.utils.centerX
class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo) : TileGroup(tileInfo) { class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo, tileSetStrings: TileSetStrings) : TileGroup(tileInfo,tileSetStrings) {
var isWorkable = false var isWorkable = false
var yieldGroup = YieldGroup()
init { init {
isTransform=false // performance helper - nothing here is rotated or scaled isTransform=false // performance helper - nothing here is rotated or scaled
@ -40,7 +42,7 @@ class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo) : TileGroup(
addAcquirableIcon() addAcquirableIcon()
} }
tileInfo !in city.getTilesInRange() -> { // within city but not close enough to be workable tileInfo !in city.tilesInRange -> { // within city but not close enough to be workable
yieldGroup.isVisible = false yieldGroup.isVisible = false
baseLayerGroup.color.a = 0.5f baseLayerGroup.color.a = 0.5f
} }

View File

@ -7,6 +7,7 @@ import com.unciv.logic.GameSaver
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
import com.unciv.models.gamebasics.tr import com.unciv.models.gamebasics.tr
import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.onClick import com.unciv.ui.utils.onClick
import com.unciv.ui.worldscreen.TileGroupMap import com.unciv.ui.worldscreen.TileGroupMap
@ -54,7 +55,8 @@ class MapEditorScreen(): CameraStageBaseScreen(){
} }
private fun getMapHolder(tileMap: TileMap): ScrollPane { private fun getMapHolder(tileMap: TileMap): ScrollPane {
val tileGroups = tileMap.values.map { TileGroup(it) } val tileSetStrings = TileSetStrings()
val tileGroups = tileMap.values.map { TileGroup(it, tileSetStrings) }
for (tileGroup in tileGroups) { for (tileGroup in tileGroups) {
tileGroup.showEntireMap = true tileGroup.showEntireMap = true
tileGroup.update(true, true, true) tileGroup.update(true, true, true)

View File

@ -15,6 +15,7 @@ import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.models.gamebasics.tile.TileImprovement import com.unciv.models.gamebasics.tile.TileImprovement
import com.unciv.models.gamebasics.tile.TileResource import com.unciv.models.gamebasics.tile.TileResource
import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.center import com.unciv.ui.utils.center
@ -118,7 +119,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
else tileInfo.baseTerrain=terrain.name else tileInfo.baseTerrain=terrain.name
tileInfo.setTransients() tileInfo.setTransients()
val group = TileGroup(tileInfo) val group = TileGroup(tileInfo, TileSetStrings())
group.showEntireMap=true group.showEntireMap=true
group.forMapEditorIcon=true group.forMapEditorIcon=true
group.update(true,true,true) group.update(true,true,true)
@ -244,7 +245,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
fun setCurrentHex(tileInfo: TileInfo){ fun setCurrentHex(tileInfo: TileInfo){
val tileGroup = TileGroup(tileInfo) val tileGroup = TileGroup(tileInfo,TileSetStrings())
.apply { .apply {
showEntireMap=true showEntireMap=true
forMapEditorIcon=true forMapEditorIcon=true

View File

@ -12,7 +12,6 @@ import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.ui.cityscreen.YieldGroup
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.UnitGroup import com.unciv.ui.utils.UnitGroup
import com.unciv.ui.utils.center import com.unciv.ui.utils.center
@ -20,9 +19,8 @@ import com.unciv.ui.utils.centerX
open class TileGroup(var tileInfo: TileInfo) : Group() { open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings) : Group() {
val groupSize = 54f val groupSize = 54f
val tileSetLocation = "TileSets/"+UnCivGame.Current.settings.tileSet +"/"
/* /*
Layers: Layers:
@ -33,7 +31,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
City name City name
*/ */
val baseLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) } val baseLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) }
protected var tileBaseImage :Image= ImageGetter.getImage(tileSetLocation+"Hexagon") protected var tileBaseImage :Image= ImageGetter.getImage(tileSetStrings.hexagon)
var currentTileBaseImageLocation = "" var currentTileBaseImageLocation = ""
protected var baseTerrainOverlayImage: Image? = null protected var baseTerrainOverlayImage: Image? = null
protected var baseTerrain:String="" protected var baseTerrain:String=""
@ -60,9 +58,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
val circleCrosshairFogLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) } val circleCrosshairFogLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) }
private val circleImage = ImageGetter.getCircle() // for blue and red circles on the tile private val circleImage = ImageGetter.getCircle() // for blue and red circles on the tile
private val crosshairImage = ImageGetter.getImage("OtherIcons/Crosshair.png") // for when a unit is targete private val crosshairImage = ImageGetter.getImage("OtherIcons/Crosshair.png") // for when a unit is targete
protected val fogImage = ImageGetter.getImage(tileSetLocation+"CrosshatchHexagon") protected val fogImage = ImageGetter.getImage(tileSetStrings.crosshatchHexagon)
var yieldGroup = YieldGroup()
var showEntireMap = UnCivGame.Current.viewEntireMapForDebug var showEntireMap = UnCivGame.Current.viewEntireMapForDebug
var forMapEditorIcon = false var forMapEditorIcon = false
@ -121,16 +118,15 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
} }
fun getTileBaseImageLocation(isRevealed: Boolean): String { fun getTileBaseImageLocation(isRevealed: Boolean): String {
if(!isRevealed) return tileSetLocation+"Hexagon" if(!isRevealed) return tileSetStrings.hexagon
if(tileInfo.isCityCenter()){ if(tileInfo.isCityCenter()){
val terrainAndCity = "$tileSetLocation${tileInfo.baseTerrain}+City" val terrainAndCity = tileSetStrings.getCityTile(baseTerrain)
if(ImageGetter.imageExists(terrainAndCity)) if(ImageGetter.imageExists(terrainAndCity))
return terrainAndCity return terrainAndCity
if(ImageGetter.imageExists(tileSetLocation+"City")) if(ImageGetter.imageExists(tileSetStrings.cityTile))
return tileSetLocation+"City" return tileSetStrings.cityTile
} }
// these are templates because apparently chain appending is faster or something? val baseTerrainTileLocation = tileSetStrings.getBaseTerrainTile(tileInfo.baseTerrain)
val baseTerrainTileLocation = "$tileSetLocation${tileInfo.baseTerrain}"
if(tileInfo.terrainFeature!=null){ if(tileInfo.terrainFeature!=null){
val baseTerrainAndFeatureTileLocation = "$baseTerrainTileLocation+${tileInfo.terrainFeature}" val baseTerrainAndFeatureTileLocation = "$baseTerrainTileLocation+${tileInfo.terrainFeature}"
if(ImageGetter.imageExists(baseTerrainAndFeatureTileLocation)) if(ImageGetter.imageExists(baseTerrainAndFeatureTileLocation))
@ -138,7 +134,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
} }
if(ImageGetter.imageExists(baseTerrainTileLocation)) return baseTerrainTileLocation if(ImageGetter.imageExists(baseTerrainTileLocation)) return baseTerrainTileLocation
return tileSetLocation+"Hexagon" return tileSetStrings.hexagon
} }
private fun updateTileImage(isRevealed: Boolean) { private fun updateTileImage(isRevealed: Boolean) {
@ -227,7 +223,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
baseTerrainOverlayImage=null baseTerrainOverlayImage=null
} }
val imagePath = "$tileSetLocation${tileInfo.baseTerrain}Overlay" val imagePath = tileSetStrings.getBaseTerrainOverlay(baseTerrain)
if (!ImageGetter.imageExists(imagePath)) return if (!ImageGetter.imageExists(imagePath)) return
baseTerrainOverlayImage = ImageGetter.getImage(imagePath) baseTerrainOverlayImage = ImageGetter.getImage(imagePath)
baseTerrainOverlayImage!!.run { baseTerrainOverlayImage!!.run {
@ -240,7 +236,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
private fun updateCityImage() { private fun updateCityImage() {
if (cityImage == null && tileInfo.isCityCenter()) { if (cityImage == null && tileInfo.isCityCenter()) {
val cityOverlayLocation = tileSetLocation+"CityOverlay" val cityOverlayLocation = tileSetStrings.cityOverlay
if(!ImageGetter.imageExists(cityOverlayLocation)) // have a city tile, don't need an overlay if(!ImageGetter.imageExists(cityOverlayLocation)) // have a city tile, don't need an overlay
return return
@ -336,7 +332,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
if (roadStatus == RoadStatus.None) continue // no road image if (roadStatus == RoadStatus.None) continue // no road image
val image = if (roadStatus == RoadStatus.Road) ImageGetter.getDot(Color.BROWN) val image = if (roadStatus == RoadStatus.Road) ImageGetter.getDot(Color.BROWN)
else ImageGetter.getImage(tileSetLocation+"Railroad.png") else ImageGetter.getImage(tileSetStrings.railroad)
roadImage.image = image roadImage.image = image
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position) val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
@ -355,12 +351,12 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
featureLayerGroup.addActor(image) featureLayerGroup.addActor(image)
} }
} }
private fun updateTileColor(isViewable: Boolean) { private fun updateTileColor(isViewable: Boolean) {
tileBaseImage.color = tileBaseImage.color =
if (ImageGetter.imageExists(tileSetLocation + tileInfo.baseTerrain)) Color.WHITE // no need to color it, it's already colored if (ImageGetter.imageExists(tileSetStrings.getBaseTerrainTile(tileInfo.baseTerrain)))
Color.WHITE // no need to color it, it's already colored
else tileInfo.getBaseTerrain().getColor() else tileInfo.getBaseTerrain().getColor()
if (!isViewable) tileBaseImage.color = tileBaseImage.color.lerp(Color.BLACK, 0.6f) if (!isViewable) tileBaseImage.color = tileBaseImage.color.lerp(Color.BLACK, 0.6f)
@ -373,7 +369,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
terrainFeatureOverlayImage = null terrainFeatureOverlayImage = null
if(terrainFeature!=null) { if(terrainFeature!=null) {
val terrainFeatureOverlayLocation = tileSetLocation +"$terrainFeature"+"Overlay" val terrainFeatureOverlayLocation = tileSetStrings.getTerrainFeatureOverlay(terrainFeature!!)
if(!ImageGetter.imageExists(terrainFeatureOverlayLocation)) return if(!ImageGetter.imageExists(terrainFeatureOverlayLocation)) return
terrainFeatureOverlayImage = ImageGetter.getImage(terrainFeatureOverlayLocation) terrainFeatureOverlayImage = ImageGetter.getImage(terrainFeatureOverlayLocation)
featureLayerGroup.addActor(terrainFeatureOverlayImage) featureLayerGroup.addActor(terrainFeatureOverlayImage)
@ -460,5 +456,4 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
fun hideCircle() { fun hideCircle() {
circleImage.isVisible = false circleImage.isVisible = false
} }
} }

View File

@ -0,0 +1,45 @@
package com.unciv.ui.tilegroups
import com.unciv.UnCivGame
class TileSetStrings {
// 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)
val tileSetLocation = "TileSets/"+ UnCivGame.Current.settings.tileSet +"/"
val hexagon = tileSetLocation+"Hexagon"
val crosshatchHexagon = tileSetLocation+"CrosshatchHexagon"
val cityTile = tileSetLocation+"City"
val cityOverlay = tileSetLocation+"CityOverlay"
val railroad = tileSetLocation+"Railroad"
private val baseTerrainToTile = HashMap<String,String>()
fun getBaseTerrainTile(baseTerrain:String): String {
if(!baseTerrainToTile.containsKey(baseTerrain))
baseTerrainToTile[baseTerrain] = "$tileSetLocation$baseTerrain"
return baseTerrainToTile[baseTerrain]!!
}
private val baseTerrainToOverlay = HashMap<String,String>()
fun getBaseTerrainOverlay(baseTerrain:String): String {
if(!baseTerrainToOverlay.containsKey(baseTerrain))
baseTerrainToOverlay[baseTerrain] = "$tileSetLocation$baseTerrain"+"Overlay"
return baseTerrainToOverlay[baseTerrain]!!
}
private val baseTerrainToCityTile = HashMap<String,String>()
fun getCityTile(baseTerrain:String): String {
if(!baseTerrainToCityTile.containsKey(baseTerrain))
baseTerrainToCityTile[baseTerrain] = "$tileSetLocation$baseTerrain+City"
return baseTerrainToCityTile[baseTerrain]!!
}
private val terrainFeatureToOverlay = HashMap<String,String>()
fun getTerrainFeatureOverlay(terrainFeature:String): String {
if(!terrainFeatureToOverlay.containsKey(terrainFeature))
terrainFeatureToOverlay[terrainFeature] = tileSetLocation + terrainFeature +"Overlay"
return terrainFeatureToOverlay[terrainFeature]!!
}
}

View File

@ -5,11 +5,11 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.center
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo) : TileGroup(tileInfo) { class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo, tileSetStrings: TileSetStrings)
: TileGroup(tileInfo,tileSetStrings) {
var cityButton: CityButton? = null var cityButton: CityButton? = null
@ -20,12 +20,6 @@ class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo)
unitImage?.selectUnit() unitImage?.selectUnit()
} }
init {
yieldGroup.center(this)
yieldGroup.moveBy(-22f, 0f)
}
fun update(isViewable: Boolean, showSubmarine: Boolean) { fun update(isViewable: Boolean, showSubmarine: Boolean) {
val city = tileInfo.getCity() val city = tileInfo.getCity()
@ -42,14 +36,10 @@ class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo)
super.update(isViewable || UnCivGame.Current.viewEntireMapForDebug, super.update(isViewable || UnCivGame.Current.viewEntireMapForDebug,
UnCivGame.Current.settings.showResourcesAndImprovements, showSubmarine) UnCivGame.Current.settings.showResourcesAndImprovements, showSubmarine)
yieldGroup.isVisible = !UnCivGame.Current.settings.showResourcesAndImprovements
if (yieldGroup.isVisible)
yieldGroup.setStats(tileInfo.getTileStats(currentPlayerCiv))
// order by z index! // order by z index!
cityImage?.toFront() cityImage?.toFront()
terrainFeatureOverlayImage?.toFront() terrainFeatureOverlayImage?.toFront()
yieldGroup.toFront()
improvementImage?.toFront() improvementImage?.toFront()
resourceImage?.toFront() resourceImage?.toFront()
cityButton?.toFront() cityButton?.toFront()

View File

@ -21,6 +21,7 @@ import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
import com.unciv.models.gamebasics.unit.UnitType import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.tilegroups.WorldTileGroup import com.unciv.ui.tilegroups.WorldTileGroup
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.unit.UnitContextMenu import com.unciv.ui.worldscreen.unit.UnitContextMenu
@ -37,8 +38,8 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
class MoveHereButtonDto(val unit: MapUnit, val tileInfo: TileInfo, val turnsToGetThere: Int) class MoveHereButtonDto(val unit: MapUnit, val tileInfo: TileInfo, val turnsToGetThere: Int)
internal fun addTiles() { internal fun addTiles() {
val tileSetStrings = TileSetStrings()
val daTileGroups = tileMap.values.map { WorldTileGroup(worldScreen, it) } val daTileGroups = tileMap.values.map { WorldTileGroup(worldScreen, it, tileSetStrings) }
for(tileGroup in daTileGroups) tileGroups[tileGroup.tileInfo]=tileGroup for(tileGroup in daTileGroups) tileGroups[tileGroup.tileInfo]=tileGroup

View File

@ -334,6 +334,7 @@ class WorldScreen : CameraStageBaseScreen() {
override fun render(delta: Float) { override fun render(delta: Float) {
if (shouldUpdate) { // This is so that updates happen in the MAIN THREAD, where there is a GL Context, if (shouldUpdate) { // This is so that updates happen in the MAIN THREAD, where there is a GL Context,
shouldUpdate = false
if (currentPlayerCiv != gameInfo.getCurrentPlayerCivilization()) { if (currentPlayerCiv != gameInfo.getCurrentPlayerCivilization()) {
UnCivGame.Current.screen = PlayerReadyScreen(gameInfo.getCurrentPlayerCivilization()) UnCivGame.Current.screen = PlayerReadyScreen(gameInfo.getCurrentPlayerCivilization())
@ -343,7 +344,6 @@ class WorldScreen : CameraStageBaseScreen() {
// otherwise images will not load properly! // otherwise images will not load properly!
update() update()
showTutorialsOnNextTurn() showTutorialsOnNextTurn()
shouldUpdate = false
} }
super.render(delta) super.render(delta)