mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-29 15:01:09 -04:00
Fixed rare "cloning exploredTiles" concurrency bug
Removed .replace in ImageGetter.getImage() thus lowering memory consumption
This commit is contained in:
parent
691d905c9f
commit
7b21505a53
@ -83,7 +83,11 @@ class CivilizationInfo {
|
|||||||
for(diplomacyManager in diplomacy.values.map { it.clone() })
|
for(diplomacyManager in diplomacy.values.map { it.clone() })
|
||||||
toReturn.diplomacy.put(diplomacyManager.otherCivName, diplomacyManager)
|
toReturn.diplomacy.put(diplomacyManager.otherCivName, diplomacyManager)
|
||||||
toReturn.cities = cities.map { it.clone() }
|
toReturn.cities = cities.map { it.clone() }
|
||||||
toReturn.exploredTiles.addAll(exploredTiles)
|
|
||||||
|
// This is the only thing that is NOT switched out, which makes it a source of ConcurrentModification errors.
|
||||||
|
// Cloning it by-pointer is a horrific move, since the serialization would go over it ANYWAY and still led to concurrency prolems.
|
||||||
|
// Cloning it by iiterating on the tilemap values may seem ridiculous, but it's a perfectly thread-safe way to go about it, unlike the other solutions.
|
||||||
|
toReturn.exploredTiles.addAll(gameInfo.tileMap.values.asSequence().map { it.position }.filter { it in exploredTiles })
|
||||||
toReturn.notifications.addAll(notifications)
|
toReturn.notifications.addAll(notifications)
|
||||||
toReturn.citiesCreated = citiesCreated
|
toReturn.citiesCreated = citiesCreated
|
||||||
return toReturn
|
return toReturn
|
||||||
|
@ -404,7 +404,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
|
|||||||
companion object {
|
companion object {
|
||||||
fun getCivGroup(civ: CivilizationInfo, afterCivNameText:String,currentPlayer:CivilizationInfo): Table {
|
fun getCivGroup(civ: CivilizationInfo, afterCivNameText:String,currentPlayer:CivilizationInfo): Table {
|
||||||
val civGroup = Table()
|
val civGroup = Table()
|
||||||
val civGroupBackground = ImageGetter.getDrawable("OtherIcons/civTableBackground.png")
|
val civGroupBackground = ImageGetter.getDrawable("OtherIcons/civTableBackground")
|
||||||
|
|
||||||
val civNameText = civ.civName.tr()+afterCivNameText
|
val civNameText = civ.civName.tr()+afterCivNameText
|
||||||
val label = civNameText.toLabel()
|
val label = civNameText.toLabel()
|
||||||
|
@ -29,12 +29,12 @@ class CityScreenCityPickerTable(val cityScreen: CityScreen) : Table(){
|
|||||||
|
|
||||||
val cityNameTable = Table()
|
val cityNameTable = Table()
|
||||||
if(city.isBeingRazed){
|
if(city.isBeingRazed){
|
||||||
val fireImage = ImageGetter.getImage("OtherIcons/Fire.png")
|
val fireImage = ImageGetter.getImage("OtherIcons/Fire")
|
||||||
cityNameTable.add(fireImage).size(20f).padRight(5f)
|
cityNameTable.add(fireImage).size(20f).padRight(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(city.isCapital()){
|
if(city.isCapital()){
|
||||||
val starImage = Image(ImageGetter.getDrawable("OtherIcons/Star.png").tint(Color.LIGHT_GRAY))
|
val starImage = Image(ImageGetter.getDrawable("OtherIcons/Star").tint(Color.LIGHT_GRAY))
|
||||||
cityNameTable.add(starImage).size(20f).padRight(5f)
|
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo, tileSetStrin
|
|||||||
isTransform=false // performance helper - nothing here is rotated or scaled
|
isTransform=false // performance helper - nothing here is rotated or scaled
|
||||||
addActor(yieldGroup)
|
addActor(yieldGroup)
|
||||||
if (city.location == tileInfo.position) {
|
if (city.location == tileInfo.position) {
|
||||||
populationImage = ImageGetter.getImage("StatIcons/City_Center_(Civ6).png")
|
populationImage = ImageGetter.getImage("StatIcons/City_Center_(Civ6)")
|
||||||
addActor(populationImage)
|
addActor(populationImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ class MapScreenLoadTable(mapEditorScreen: MapEditorScreen): PopupTable(mapEditor
|
|||||||
}
|
}
|
||||||
add(loadFromClipboardButton).row()
|
add(loadFromClipboardButton).row()
|
||||||
|
|
||||||
val closeOptionsButtton = TextButton("Close".tr(), CameraStageBaseScreen.skin)
|
val closeOptionsButton = TextButton("Close".tr(), CameraStageBaseScreen.skin)
|
||||||
closeOptionsButtton.onClick { remove() }
|
closeOptionsButton.onClick { remove() }
|
||||||
add(closeOptionsButtton).row()
|
add(closeOptionsButton).row()
|
||||||
|
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class ImprovementPickerScreen(tileInfo: TileInfo, onAccept: ()->Unit) : PickerSc
|
|||||||
val group = Table()
|
val group = Table()
|
||||||
|
|
||||||
val image = if(improvement.name.startsWith("Remove"))
|
val image = if(improvement.name.startsWith("Remove"))
|
||||||
ImageGetter.getImage("OtherIcons/Stop.png")
|
ImageGetter.getImage("OtherIcons/Stop")
|
||||||
else
|
else
|
||||||
ImageGetter.getImprovementIcon(improvement.name,30f)
|
ImageGetter.getImprovementIcon(improvement.name,30f)
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class TechButton(techName:String, val techManager: TechManager) : Table(CameraSt
|
|||||||
init {
|
init {
|
||||||
touchable = Touchable.enabled
|
touchable = Touchable.enabled
|
||||||
defaults().pad(10f)
|
defaults().pad(10f)
|
||||||
background = ImageGetter.getDrawable("OtherIcons/civTableBackground.png")
|
background = ImageGetter.getDrawable("OtherIcons/civTableBackground")
|
||||||
if(ImageGetter.techIconExists(techName))
|
if(ImageGetter.techIconExists(techName))
|
||||||
add(ImageGetter.getTechIconGroup(techName)) // this is 60*60
|
add(ImageGetter.getTechIconGroup(techName)) // this is 60*60
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
if (!tileGroup.tileInfo.airUnits.isNotEmpty()) return
|
if (!tileGroup.tileInfo.airUnits.isNotEmpty()) return
|
||||||
val secondarycolor = city.civInfo.getNation().getSecondaryColor()
|
val secondarycolor = city.civInfo.getNation().getSecondaryColor()
|
||||||
val airUnitTable = Table().apply { defaults().pad(5f) }
|
val airUnitTable = Table().apply { defaults().pad(5f) }
|
||||||
airUnitTable.background = ImageGetter.getDrawable("OtherIcons/civTableBackground.png")
|
airUnitTable.background = ImageGetter.getDrawable("OtherIcons/civTableBackground")
|
||||||
.tint(city.civInfo.getNation().getColor())
|
.tint(city.civInfo.getNation().getColor())
|
||||||
val aircraftImage = ImageGetter.getImage("OtherIcons/Aircraft")
|
val aircraftImage = ImageGetter.getImage("OtherIcons/Aircraft")
|
||||||
aircraftImage.color = secondarycolor
|
aircraftImage.color = secondarycolor
|
||||||
@ -92,16 +92,16 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
val secondaryColor = city.civInfo.getNation().getSecondaryColor()
|
val secondaryColor = city.civInfo.getNation().getSecondaryColor()
|
||||||
val iconTable = Table()
|
val iconTable = Table()
|
||||||
iconTable.touchable=Touchable.enabled
|
iconTable.touchable=Touchable.enabled
|
||||||
iconTable.background = ImageGetter.getDrawable("OtherIcons/civTableBackground.png")
|
iconTable.background = ImageGetter.getDrawable("OtherIcons/civTableBackground")
|
||||||
.tint(city.civInfo.getNation().getColor())
|
.tint(city.civInfo.getNation().getColor())
|
||||||
|
|
||||||
if (city.resistanceCounter > 0) {
|
if (city.resistanceCounter > 0) {
|
||||||
val resistanceImage = ImageGetter.getImage("StatIcons/Resistance.png")
|
val resistanceImage = ImageGetter.getImage("StatIcons/Resistance")
|
||||||
iconTable.add(resistanceImage).size(20f).pad(2f).padLeft(5f)
|
iconTable.add(resistanceImage).size(20f).pad(2f).padLeft(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (city.isBeingRazed) {
|
if (city.isBeingRazed) {
|
||||||
val fireImage = ImageGetter.getImage("OtherIcons/Fire.png")
|
val fireImage = ImageGetter.getImage("OtherIcons/Fire")
|
||||||
iconTable.add(fireImage).size(20f).pad(2f).padLeft(5f)
|
iconTable.add(fireImage).size(20f).pad(2f).padLeft(5f)
|
||||||
}
|
}
|
||||||
if (city.isCapital()) {
|
if (city.isCapital()) {
|
||||||
@ -110,7 +110,7 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
.apply { color = secondaryColor }
|
.apply { color = secondaryColor }
|
||||||
iconTable.add(cityStateImage).size(20f).pad(2f).padLeft(10f)
|
iconTable.add(cityStateImage).size(20f).pad(2f).padLeft(10f)
|
||||||
} else {
|
} else {
|
||||||
val starImage = ImageGetter.getImage("OtherIcons/Star.png").apply { color = Color.LIGHT_GRAY }
|
val starImage = ImageGetter.getImage("OtherIcons/Star").apply { color = Color.LIGHT_GRAY }
|
||||||
iconTable.add(starImage).size(20f).pad(2f).padLeft(10f)
|
iconTable.add(starImage).size(20f).pad(2f).padLeft(10f)
|
||||||
}
|
}
|
||||||
} else if (city.civInfo.isCurrentPlayer() && city.isConnectedToCapital()) {
|
} else if (city.civInfo.isCurrentPlayer() && city.isConnectedToCapital()) {
|
||||||
|
@ -57,7 +57,7 @@ open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings)
|
|||||||
|
|
||||||
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") // for when a unit is targete
|
||||||
protected val fogImage = ImageGetter.getImage(tileSetStrings.crosshatchHexagon)
|
protected val fogImage = ImageGetter.getImage(tileSetStrings.crosshatchHexagon)
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import com.unciv.models.gamebasics.Nation
|
|||||||
import com.unciv.models.gamebasics.tile.ResourceType
|
import com.unciv.models.gamebasics.tile.ResourceType
|
||||||
|
|
||||||
object ImageGetter {
|
object ImageGetter {
|
||||||
private const val whiteDotLocation = "OtherIcons/whiteDot.png"
|
private const val whiteDotLocation = "OtherIcons/whiteDot"
|
||||||
|
|
||||||
// When we used to load images directly from different files, without using a texture atlas,
|
// When we used to load images directly from different files, without using a texture atlas,
|
||||||
// The draw() phase of the main screen would take a really long time because the BatchRenderer would
|
// The draw() phase of the main screen would take a really long time because the BatchRenderer would
|
||||||
@ -28,7 +28,7 @@ object ImageGetter {
|
|||||||
fun getDot(dotColor: Color) = getWhiteDot().apply { color = dotColor}
|
fun getDot(dotColor: Color) = getWhiteDot().apply { color = dotColor}
|
||||||
|
|
||||||
fun getExternalImage(fileName:String): Image {
|
fun getExternalImage(fileName:String): Image {
|
||||||
return Image(TextureRegion(Texture("ExtraImages/$fileName.png")))
|
return Image(TextureRegion(Texture("ExtraImages/$fileName")))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImage(fileName: String): Image {
|
fun getImage(fileName: String): Image {
|
||||||
@ -44,7 +44,7 @@ object ImageGetter {
|
|||||||
|
|
||||||
private fun getTextureRegion(fileName: String): TextureRegion {
|
private fun getTextureRegion(fileName: String): TextureRegion {
|
||||||
try {
|
try {
|
||||||
val region = atlas.findRegion(fileName.replace(".png",""))
|
val region = atlas.findRegion(fileName)
|
||||||
|
|
||||||
if(region==null)
|
if(region==null)
|
||||||
throw Exception("Could not find $fileName")
|
throw Exception("Could not find $fileName")
|
||||||
|
@ -63,7 +63,7 @@ class Tutorials{
|
|||||||
val currentTutorial = tutorialTexts[0]
|
val currentTutorial = tutorialTexts[0]
|
||||||
val label = Label(currentTutorial.texts[0], CameraStageBaseScreen.skin)
|
val label = Label(currentTutorial.texts[0], CameraStageBaseScreen.skin)
|
||||||
label.setAlignment(Align.center)
|
label.setAlignment(Align.center)
|
||||||
if(Gdx.files.internal("ExtraImages/"+currentTutorial.name+".png").exists())
|
if(Gdx.files.internal("ExtraImages/"+currentTutorial.name).exists())
|
||||||
tutorialTable.add(Table().apply { add(ImageGetter.getExternalImage(currentTutorial.name)) }).row()
|
tutorialTable.add(Table().apply { add(ImageGetter.getExternalImage(currentTutorial.name)) }).row()
|
||||||
tutorialTable.add(label).pad(10f).row()
|
tutorialTable.add(label).pad(10f).row()
|
||||||
val button = TextButton("Close".tr(), CameraStageBaseScreen.skin)
|
val button = TextButton("Close".tr(), CameraStageBaseScreen.skin)
|
||||||
|
@ -35,7 +35,7 @@ class UnitGroup(val unit: MapUnit, val size: Float): Group() {
|
|||||||
fun getBackgroundImageForUnit(unit: MapUnit): Image {
|
fun getBackgroundImageForUnit(unit: MapUnit): Image {
|
||||||
return when {
|
return when {
|
||||||
unit.isEmbarked() -> ImageGetter.getImage("OtherIcons/Banner")
|
unit.isEmbarked() -> ImageGetter.getImage("OtherIcons/Banner")
|
||||||
unit.isFortified() -> ImageGetter.getImage("OtherIcons/Shield.png")
|
unit.isFortified() -> ImageGetter.getImage("OtherIcons/Shield")
|
||||||
else -> ImageGetter.getCircle()
|
else -> ImageGetter.getCircle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class NotificationsScroll(internal val worldScreen: WorldScreen) : ScrollPane(nu
|
|||||||
|
|
||||||
listItem.add(ImageGetter.getCircle()
|
listItem.add(ImageGetter.getCircle()
|
||||||
.apply { color=notification.color }).size(10f).pad(5f)
|
.apply { color=notification.color }).size(10f).pad(5f)
|
||||||
listItem.background(ImageGetter.getDrawable("OtherIcons/civTableBackground.png"))
|
listItem.background(ImageGetter.getDrawable("OtherIcons/civTableBackground"))
|
||||||
listItem.add(label).pad(5f).padRight(10f)
|
listItem.add(label).pad(5f).padRight(10f)
|
||||||
|
|
||||||
// using a large click area with no gap in between each message item.
|
// using a large click area with no gap in between each message item.
|
||||||
|
@ -204,7 +204,7 @@ class WorldScreen : CameraStageBaseScreen() {
|
|||||||
|
|
||||||
if (civInfo.tech.currentTechnology() == null) {
|
if (civInfo.tech.currentTechnology() == null) {
|
||||||
val buttonPic = Table()
|
val buttonPic = Table()
|
||||||
buttonPic.background = ImageGetter.getDrawable("OtherIcons/civTableBackground.png")
|
buttonPic.background = ImageGetter.getDrawable("OtherIcons/civTableBackground")
|
||||||
.tint(colorFromRGB(7, 46, 43))
|
.tint(colorFromRGB(7, 46, 43))
|
||||||
buttonPic.defaults().pad(10f)
|
buttonPic.defaults().pad(10f)
|
||||||
buttonPic.add("{Pick a tech}!".toLabel().setFontColor(Color.WHITE).setFontSize(22))
|
buttonPic.add("{Pick a tech}!".toLabel().setFontColor(Color.WHITE).setFontSize(22))
|
||||||
@ -328,15 +328,17 @@ 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,
|
// This is so that updates happen in the MAIN THREAD, where there is a GL Context,
|
||||||
|
// otherwise images will not load properly!
|
||||||
|
if (shouldUpdate) {
|
||||||
shouldUpdate = false
|
shouldUpdate = false
|
||||||
|
|
||||||
if (currentPlayerCiv != gameInfo.getCurrentPlayerCivilization()) {
|
if (currentPlayerCiv != gameInfo.getCurrentPlayerCivilization()) {
|
||||||
|
UnCivGame.Current.worldScreen.dispose() // for memory saving
|
||||||
UnCivGame.Current.screen = PlayerReadyScreen(gameInfo.getCurrentPlayerCivilization())
|
UnCivGame.Current.screen = PlayerReadyScreen(gameInfo.getCurrentPlayerCivilization())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise images will not load properly!
|
|
||||||
update()
|
update()
|
||||||
showTutorialsOnNextTurn()
|
showTutorialsOnNextTurn()
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ class WorldScreenTopBar(val screen: WorldScreen) : Table() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun getMenuButton(): Image {
|
internal fun getMenuButton(): Image {
|
||||||
val menuButton = ImageGetter.getImage("OtherIcons/MenuIcon.png")
|
val menuButton = ImageGetter.getImage("OtherIcons/MenuIcon")
|
||||||
.apply { setSize(50f, 50f) }
|
.apply { setSize(50f, 50f) }
|
||||||
menuButton.color = Color.WHITE
|
menuButton.color = Color.WHITE
|
||||||
menuButton.onClick {
|
menuButton.onClick {
|
||||||
|
@ -47,7 +47,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
"Disband unit" -> return ImageGetter.getImage("OtherIcons/DisbandUnit")
|
"Disband unit" -> return ImageGetter.getImage("OtherIcons/DisbandUnit")
|
||||||
"Sleep" -> return ImageGetter.getImage("OtherIcons/Sleep")
|
"Sleep" -> return ImageGetter.getImage("OtherIcons/Sleep")
|
||||||
"Explore" -> return ImageGetter.getUnitIcon("Scout")
|
"Explore" -> return ImageGetter.getUnitIcon("Scout")
|
||||||
"Stop exploration" -> return ImageGetter.getImage("OtherIcons/Stop.png")
|
"Stop exploration" -> return ImageGetter.getImage("OtherIcons/Stop")
|
||||||
"Create Fishing Boats" -> return ImageGetter.getImprovementIcon("Fishing Boats")
|
"Create Fishing Boats" -> return ImageGetter.getImprovementIcon("Fishing Boats")
|
||||||
"Create Oil well" -> return ImageGetter.getImprovementIcon("Oil well")
|
"Create Oil well" -> return ImageGetter.getImprovementIcon("Oil well")
|
||||||
"Pillage" -> return ImageGetter.getImage("OtherIcons/Pillage")
|
"Pillage" -> return ImageGetter.getImage("OtherIcons/Pillage")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user