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"
minSdkVersion 14
targetSdkVersion 28
versionCode 275
versionName "2.18.4"
versionCode 276
versionName "2.18.5"
}
// 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 barbarianEncampment = "Barbarian encampment"
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() {
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
.filter { it.isStatRelated(Stat.Production)
|| (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) {
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) }
val closestReachableResource = seaResourcesInCities.sortedBy { it.arialDistanceTo(unit.currentTile) }
.firstOrNull { unit.movement.canReach(it) }

View File

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

View File

@ -27,7 +27,8 @@ class CityStats {
//region pure fuctions
private fun getStatsFromTiles(): 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))
return stats
}

View File

@ -1,7 +1,6 @@
package com.unciv.logic.civilization
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.BFS
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.tr
import java.util.*
import kotlin.collections.ArrayList
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.toList
/** CivInfo class was getting too crowded */
class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
@ -43,7 +29,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles
// 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 }
.filterNot { civInfo.exploredTiles.contains(it) })
civInfo.exploredTiles = newExploredTiles // ditto

View File

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

View File

@ -53,12 +53,12 @@ open class TileInfo {
}
fun containsGreatImprovement(): Boolean {
if (improvement in listOf("Academy", "Landmark", "Manufactory", "Customs house")) return true
if (improvement in Constants.greatImprovements) return true
return false
}
fun containsUnfinishedGreatImprovement(): Boolean {
if (improvementInProgress in listOf("Academy", "Landmark", "Manufactory", "Customs house")) return true
if (improvementInProgress in Constants.greatImprovements) return true
return false
}
@ -66,6 +66,8 @@ open class TileInfo {
/** Returns military, civilian and air units in tile */
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)
if(militaryUnit!=null) list.add(militaryUnit!!)
if(civilianUnit!=null) list.add(civilianUnit!!)

View File

@ -282,7 +282,7 @@ class Building : NamedStats(), IConstruction{
return "Requires [$requiredResource]"
if (requiredNearbyImprovedResources != null) {
val containsResourceWithImprovement = construction.cityInfo.getTilesInRange()
val containsResourceWithImprovement = construction.cityInfo.getWorkableTiles()
.any {
it.resource != null
&& 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 {
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!
*/
val squareBraceRegex = Regex("\\[(.*?)\\]")
val translationStringWithSquareBracketsOnly = replace(squareBraceRegex,"[]")
val translationStringUntilFirstSquareBracket = substringBefore('[')
val englishTranslationPlaceholder = GameBasics.Translations.keys

View File

@ -100,6 +100,6 @@ open class Stats() {
class StatMap:LinkedHashMap<String,Stats>(){
fun add(source:String,stats: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.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.TileGroupMap
import java.util.*
@ -181,11 +182,11 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
private fun addTiles() {
val cityInfo = city
val tileSetStrings = TileSetStrings()
val cityTileGroups = cityInfo.getCenterTile().getTilesInDistance(5)
.filter { city.civInfo.exploredTiles.contains(it.position) }
.map { CityTileGroup(cityInfo, it) }
.map { CityTileGroup(cityInfo, it, tileSetStrings) }
val tilesInRange = city.getTilesInRange()
for (tileGroup in cityTileGroups) {
val tileInfo = tileGroup.tileInfo

View File

@ -6,12 +6,14 @@ import com.unciv.UnCivGame
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.ImageGetter
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 yieldGroup = YieldGroup()
init {
isTransform=false // performance helper - nothing here is rotated or scaled
@ -40,7 +42,7 @@ class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo) : TileGroup(
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
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.models.gamebasics.tr
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.onClick
import com.unciv.ui.worldscreen.TileGroupMap
@ -54,7 +55,8 @@ class MapEditorScreen(): CameraStageBaseScreen(){
}
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) {
tileGroup.showEntireMap = 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.TileResource
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.center
@ -118,7 +119,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
else tileInfo.baseTerrain=terrain.name
tileInfo.setTransients()
val group = TileGroup(tileInfo)
val group = TileGroup(tileInfo, TileSetStrings())
group.showEntireMap=true
group.forMapEditorIcon=true
group.update(true,true,true)
@ -244,7 +245,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
fun setCurrentHex(tileInfo: TileInfo){
val tileGroup = TileGroup(tileInfo)
val tileGroup = TileGroup(tileInfo,TileSetStrings())
.apply {
showEntireMap=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.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.ui.cityscreen.YieldGroup
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.UnitGroup
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 tileSetLocation = "TileSets/"+UnCivGame.Current.settings.tileSet +"/"
/*
Layers:
@ -33,7 +31,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
City name
*/
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 = ""
protected var baseTerrainOverlayImage: Image? = null
protected var baseTerrain:String=""
@ -60,9 +58,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
val circleCrosshairFogLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) }
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
protected val fogImage = ImageGetter.getImage(tileSetLocation+"CrosshatchHexagon")
protected val fogImage = ImageGetter.getImage(tileSetStrings.crosshatchHexagon)
var yieldGroup = YieldGroup()
var showEntireMap = UnCivGame.Current.viewEntireMapForDebug
var forMapEditorIcon = false
@ -121,16 +118,15 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
}
fun getTileBaseImageLocation(isRevealed: Boolean): String {
if(!isRevealed) return tileSetLocation+"Hexagon"
if(!isRevealed) return tileSetStrings.hexagon
if(tileInfo.isCityCenter()){
val terrainAndCity = "$tileSetLocation${tileInfo.baseTerrain}+City"
val terrainAndCity = tileSetStrings.getCityTile(baseTerrain)
if(ImageGetter.imageExists(terrainAndCity))
return terrainAndCity
if(ImageGetter.imageExists(tileSetLocation+"City"))
return tileSetLocation+"City"
if(ImageGetter.imageExists(tileSetStrings.cityTile))
return tileSetStrings.cityTile
}
// these are templates because apparently chain appending is faster or something?
val baseTerrainTileLocation = "$tileSetLocation${tileInfo.baseTerrain}"
val baseTerrainTileLocation = tileSetStrings.getBaseTerrainTile(tileInfo.baseTerrain)
if(tileInfo.terrainFeature!=null){
val baseTerrainAndFeatureTileLocation = "$baseTerrainTileLocation+${tileInfo.terrainFeature}"
if(ImageGetter.imageExists(baseTerrainAndFeatureTileLocation))
@ -138,7 +134,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
}
if(ImageGetter.imageExists(baseTerrainTileLocation)) return baseTerrainTileLocation
return tileSetLocation+"Hexagon"
return tileSetStrings.hexagon
}
private fun updateTileImage(isRevealed: Boolean) {
@ -227,7 +223,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
baseTerrainOverlayImage=null
}
val imagePath = "$tileSetLocation${tileInfo.baseTerrain}Overlay"
val imagePath = tileSetStrings.getBaseTerrainOverlay(baseTerrain)
if (!ImageGetter.imageExists(imagePath)) return
baseTerrainOverlayImage = ImageGetter.getImage(imagePath)
baseTerrainOverlayImage!!.run {
@ -240,7 +236,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
private fun updateCityImage() {
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
return
@ -336,7 +332,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
if (roadStatus == RoadStatus.None) continue // no road image
val image = if (roadStatus == RoadStatus.Road) ImageGetter.getDot(Color.BROWN)
else ImageGetter.getImage(tileSetLocation+"Railroad.png")
else ImageGetter.getImage(tileSetStrings.railroad)
roadImage.image = image
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
@ -355,12 +351,12 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
featureLayerGroup.addActor(image)
}
}
private fun updateTileColor(isViewable: Boolean) {
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()
if (!isViewable) tileBaseImage.color = tileBaseImage.color.lerp(Color.BLACK, 0.6f)
@ -373,7 +369,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
terrainFeatureOverlayImage = null
if(terrainFeature!=null) {
val terrainFeatureOverlayLocation = tileSetLocation +"$terrainFeature"+"Overlay"
val terrainFeatureOverlayLocation = tileSetStrings.getTerrainFeatureOverlay(terrainFeature!!)
if(!ImageGetter.imageExists(terrainFeatureOverlayLocation)) return
terrainFeatureOverlayImage = ImageGetter.getImage(terrainFeatureOverlayLocation)
featureLayerGroup.addActor(terrainFeatureOverlayImage)
@ -460,5 +456,4 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
fun hideCircle() {
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.TileInfo
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.center
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
@ -20,12 +20,6 @@ class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo)
unitImage?.selectUnit()
}
init {
yieldGroup.center(this)
yieldGroup.moveBy(-22f, 0f)
}
fun update(isViewable: Boolean, showSubmarine: Boolean) {
val city = tileInfo.getCity()
@ -42,14 +36,10 @@ class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo)
super.update(isViewable || UnCivGame.Current.viewEntireMapForDebug,
UnCivGame.Current.settings.showResourcesAndImprovements, showSubmarine)
yieldGroup.isVisible = !UnCivGame.Current.settings.showResourcesAndImprovements
if (yieldGroup.isVisible)
yieldGroup.setStats(tileInfo.getTileStats(currentPlayerCiv))
// order by z index!
cityImage?.toFront()
terrainFeatureOverlayImage?.toFront()
yieldGroup.toFront()
improvementImage?.toFront()
resourceImage?.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.TileMap
import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.tilegroups.WorldTileGroup
import com.unciv.ui.utils.*
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)
internal fun addTiles() {
val daTileGroups = tileMap.values.map { WorldTileGroup(worldScreen, it) }
val tileSetStrings = TileSetStrings()
val daTileGroups = tileMap.values.map { WorldTileGroup(worldScreen, it, tileSetStrings) }
for(tileGroup in daTileGroups) tileGroups[tileGroup.tileInfo]=tileGroup

View File

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