perf(mem): SIGNIFICANT memory save, removed 2 unnecessary groups per tile by only assigning when they actually contain units

This commit is contained in:
yairm210 2024-12-05 20:21:15 +02:00
parent 03214379f2
commit c267096f6b
3 changed files with 50 additions and 44 deletions

View File

@ -10,8 +10,9 @@ import com.unciv.ui.components.NonTransformGroup
import com.unciv.ui.components.tilegroups.TileGroup
import com.unciv.ui.images.ImageGetter
class UnitSpriteSlot : NonTransformGroup() {
var imageLocation = ""
class UnitSpriteSlot {
val spriteGroup = NonTransformGroup()
var currentImageLocation = ""
}
class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, size) {
@ -19,17 +20,14 @@ class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGro
override fun act(delta: Float) {}
override fun hit(x: Float, y: Float, touchable: Boolean): Actor? = null
override fun draw(batch: Batch?, parentAlpha: Float) {
if (civilianSlot.imageLocation.isEmpty() && militarySlot.imageLocation.isEmpty()) return
if (civilianSlot == null && militarySlot == null) return
super.draw(batch, parentAlpha)
}
// Slots are only filled if units exist, and images for those units exist
private var civilianSlot: UnitSpriteSlot? = null
private var militarySlot: UnitSpriteSlot? = null
private var civilianSlot: UnitSpriteSlot = UnitSpriteSlot()
private var militarySlot: UnitSpriteSlot = UnitSpriteSlot()
init {
addActor(civilianSlot)
addActor(militarySlot)
}
fun getSpriteSlot(unit:MapUnit) = if (unit.isCivilian()) civilianSlot else militarySlot
@ -37,7 +35,7 @@ class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGro
|| viewingCiv.viewableInvisibleUnitsTiles.contains(tileGroup.tile)
|| !tileGroup.tile.hasEnemyInvisibleUnit(viewingCiv)
private fun updateSlot(slot: UnitSpriteSlot, unit: MapUnit?, isShown: Boolean) {
private fun updateSlot(currentSlot: UnitSpriteSlot?, unit: MapUnit?, isShown: Boolean): UnitSpriteSlot? {
var location = ""
var nationName = ""
@ -47,24 +45,26 @@ class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGro
nationName = "${unit.civ.civName}-"
}
if (slot.imageLocation != "$nationName$location") {
slot.imageLocation = "$nationName$location"
slot.clear()
if ((currentSlot?.currentImageLocation ?: "") == "$nationName$location") return currentSlot // No-op
if (location == "" || !ImageGetter.imageExists(location)) return null // No such image
val slot = currentSlot ?: UnitSpriteSlot()
.apply { this@TileLayerUnitSprite.addActor(spriteGroup) }
slot.currentImageLocation = "$nationName$location"
slot.spriteGroup.clear()
if (location != "" && ImageGetter.imageExists(location)) {
val nation = unit!!.civ.nation
val pixelUnitImages = ImageGetter.getLayeredImageColored(
location,
null,
nation.getInnerColor(),
nation.getOuterColor()
)
for (pixelUnitImage in pixelUnitImages) {
slot.addActor(pixelUnitImage)
pixelUnitImage.setHexagonSize()// Treat this as A TILE, which gets overlayed on the base tile.
}
}
val nation = unit!!.civ.nation
val pixelUnitImages = ImageGetter.getLayeredImageColored(
location,
null,
nation.getInnerColor(),
nation.getOuterColor()
)
for (pixelUnitImage in pixelUnitImages) {
slot.spriteGroup.addActor(pixelUnitImage)
pixelUnitImage.setHexagonSize()// Treat this as A TILE, which gets overlayed on the base tile.
}
return slot
}
fun dim() {
@ -80,19 +80,18 @@ class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGro
val isCivilianSlotShown = isPixelUnitsEnabled && isViewable
val isMilitarySlotShown = isPixelUnitsEnabled && isViewable && isVisibleMilitary
updateSlot(civilianSlot, tileGroup.tile.civilianUnit, isShown = isCivilianSlotShown)
updateSlot(militarySlot, tileGroup.tile.militaryUnit, isShown = isMilitarySlotShown)
civilianSlot = updateSlot(civilianSlot, tileGroup.tile.civilianUnit, isShown = isCivilianSlotShown)
militarySlot = updateSlot(militarySlot, tileGroup.tile.militaryUnit, isShown = isMilitarySlotShown)
}
override fun determineVisibility() {
isVisible = civilianSlot.hasChildren() || militarySlot.hasChildren()
isVisible = civilianSlot != null || militarySlot != null
}
fun reset() {
civilianSlot.clear()
militarySlot.clear()
civilianSlot.imageLocation = ""
militarySlot.imageLocation = ""
civilianSlot?.spriteGroup?.remove()
militarySlot?.spriteGroup?.remove()
civilianSlot = null
militarySlot = null
}
}

View File

@ -486,6 +486,8 @@ object ImageGetter {
.filter { it.startsWith("TileSets") && !it.contains("/Units/") }
.map { it.split("/")[1] }.distinct()
fun getAvailableUnitsets() = textureRegionDrawables.keys.asSequence().filter { it.contains("/Units/") }
.map { it.split("/")[1] }.distinct()
fun getAvailableUnitsets() = textureRegionDrawables.keys.asSequence()
.filter { it.startsWith("TileSets") && it.contains("/Units/") }
.map { it.split("/")[1] }
.distinct()
}

View File

@ -339,17 +339,21 @@ class WorldMapHolder(
// Steal the current sprites to our new group
val unitSpriteAndIcon = Group().apply { setPosition(tileGroup.x, tileGroup.y) }
val unitSpriteSlot = tileGroup.layerUnitArt.getSpriteSlot(selectedUnit)
for (spriteImage in unitSpriteSlot.children) unitSpriteAndIcon.addActor(spriteImage)
val unitSpriteSlot = tileGroup.layerUnitArt.getSpriteSlot(selectedUnit) ?: return
for (spriteImage in unitSpriteSlot.spriteGroup.children) unitSpriteAndIcon.addActor(spriteImage)
tileGroup.parent.addActor(unitSpriteAndIcon)
// Disable the final tile, so we won't have one image "merging into" the other
val targetTileSpriteSlot = tileGroups[targetTile]!!.layerUnitArt.getSpriteSlot(selectedUnit)
targetTileSpriteSlot.isVisible = false
unitSpriteAndIcon.addAction(
Actions.sequence(
Actions.run {
// Disable the final tile, so we won't have one image "merging into" the other
// Can only be done after the new group has been updated, to get the spriteGroup
val targetTileSpriteSlot = tileGroups[targetTile]!!.layerUnitArt.getSpriteSlot(selectedUnit)
targetTileSpriteSlot?.spriteGroup?.isVisible = false
},
*pathToTile.map { tile ->
Actions.moveTo(
tileGroups[tile]!!.x,
@ -359,7 +363,8 @@ class WorldMapHolder(
}.toTypedArray(),
Actions.run {
// Re-enable the final tile
targetTileSpriteSlot.isVisible = true
val targetTileSpriteSlot = tileGroups[targetTile]!!.layerUnitArt.getSpriteSlot(selectedUnit)
targetTileSpriteSlot?.spriteGroup?.isVisible = true
worldScreen.shouldUpdate = true
},
Actions.removeActor(),