From 31f6a406c2117d22a01c057dfe9d683839fc3c61 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Sun, 9 Jul 2023 10:12:16 +0300 Subject: [PATCH] Resolved #9745 - memory improvement, cache uniquemap for tiles with identical terrain --- core/src/com/unciv/logic/map/TileMap.kt | 6 ++++++ core/src/com/unciv/logic/map/tile/Tile.kt | 19 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 282ce35f16..43ce3c1bcc 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -12,8 +12,10 @@ import com.unciv.models.metadata.Player import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.nation.Nation import com.unciv.models.ruleset.tile.TerrainType +import com.unciv.models.ruleset.unique.UniqueMap import com.unciv.models.ruleset.unique.UniqueType import java.lang.Integer.max +import java.util.concurrent.ConcurrentHashMap import kotlin.math.abs /** An Unciv map with all properties as produced by the [map editor][com.unciv.ui.screens.mapeditorscreen.MapEditorScreen] @@ -60,6 +62,9 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { @Transient var ruleset: Ruleset? = null + @Transient + var tileUniqueMapCache = ConcurrentHashMap() + @Transient var tileMatrix = ArrayList>() // this works several times faster than a hashmap, the performance difference is really astounding @@ -140,6 +145,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { toReturn.startingLocations.clear() toReturn.startingLocations.ensureCapacity(startingLocations.size) toReturn.startingLocations.addAll(startingLocations) + toReturn.tileUniqueMapCache = tileUniqueMapCache return toReturn } diff --git a/core/src/com/unciv/logic/map/tile/Tile.kt b/core/src/com/unciv/logic/map/tile/Tile.kt index 70128dbc74..d0a5ae617a 100644 --- a/core/src/com/unciv/logic/map/tile/Tile.kt +++ b/core/src/com/unciv/logic/map/tile/Tile.kt @@ -832,9 +832,7 @@ open class Tile : IsPartOfGameInfoSerialization { yieldAll(terrainFeatureObjects) }.toList().asSequence() //Save in memory, and return as sequence - val newUniqueMap = UniqueMap() - for (terrain in allTerrains) - newUniqueMap.addUniques(terrain.uniqueObjects) + updateUniqueMap() lastTerrain = when { terrainFeatures.isNotEmpty() -> ruleset.terrains[terrainFeatures.last()] @@ -842,7 +840,20 @@ open class Tile : IsPartOfGameInfoSerialization { naturalWonder != null -> getNaturalWonder() else -> getBaseTerrain() } - terrainUniqueMap = newUniqueMap + } + + private fun updateUniqueMap() { + if (!::tileMap.isInitialized) return // This tile is a fake tile, for visual display only (e.g. map editor, civilopedia) + val terrainString = allTerrains.joinToString(";") { it.name } + val cachedUniqueMap = tileMap.tileUniqueMapCache[terrainString] + terrainUniqueMap = if (cachedUniqueMap != null) cachedUniqueMap + else { + val newUniqueMap = UniqueMap() + for (terrain in allTerrains) + newUniqueMap.addUniques(terrain.uniqueObjects) + tileMap.tileUniqueMapCache[terrainString] = newUniqueMap + newUniqueMap + } } fun addTerrainFeature(terrainFeature: String) =