All UI changes in threads are now run in a postRunnable - should hopefully get rid of IndexOutOfBoundsExceptions

This commit is contained in:
Yair Morgenstern 2020-05-18 23:08:19 +03:00
parent 507c677d08
commit 7330daff48
10 changed files with 55 additions and 42 deletions

View File

@ -65,7 +65,6 @@ class MainMenuScreen: CameraStageBaseScreen() {
Actions.fadeIn(0.3f) Actions.fadeIn(0.3f)
)) ))
} }
} }

View File

@ -29,7 +29,7 @@ object Battle {
attacker.unit.useMovementPoints(1f) attacker.unit.useMovementPoints(1f)
} }
} }
attack(attacker,getMapCombatantOfTile(attackableTile.tileToAttack)!!) attack(attacker, getMapCombatantOfTile(attackableTile.tileToAttack)!!)
} }
fun attack(attacker: ICombatant, defender: ICombatant) { fun attack(attacker: ICombatant, defender: ICombatant) {

View File

@ -143,13 +143,15 @@ class MultiplayerScreen(previousScreen: CameraStageBaseScreen) : PickerScreen()
else else
GameSaver.saveGame(game, gameName, true) GameSaver.saveGame(game, gameName, true)
reloadGameListUI() Gdx.app.postRunnable { reloadGameListUI() }
} catch (ex: Exception) { } catch (ex: Exception) {
val errorPopup = Popup(this) Gdx.app.postRunnable {
errorPopup.addGoodSizedLabel("Could not download game!".tr()) val errorPopup = Popup(this)
errorPopup.row() errorPopup.addGoodSizedLabel("Could not download game!".tr())
errorPopup.addCloseButton() errorPopup.row()
errorPopup.open() errorPopup.addCloseButton()
errorPopup.open()
}
} }
addGameButton.setText(addGameText) addGameButton.setText(addGameText)
addGameButton.enable() addGameButton.enable()

View File

@ -67,7 +67,7 @@ class MapDownloadPopup(loadMapScreen: LoadMapScreen): Popup(loadMapScreen) {
open() open()
} }
} catch (ex: Exception) { } catch (ex: Exception) {
addGoodSizedLabel("Could not get list of maps!").row() Gdx.app.postRunnable { addGoodSizedLabel("Could not get list of maps!").row() }
} }
} }

View File

@ -54,13 +54,15 @@ class NewMapScreen : PickerScreen() {
} }
} catch (exception: Exception) { } catch (exception: Exception) {
rightButtonSetEnabled(true) Gdx.app.postRunnable {
val cantMakeThatMapPopup = Popup(this) rightButtonSetEnabled(true)
cantMakeThatMapPopup.addGoodSizedLabel("It looks like we can't make a map with the parameters you requested!".tr()) val cantMakeThatMapPopup = Popup(this)
.row() cantMakeThatMapPopup.addGoodSizedLabel("It looks like we can't make a map with the parameters you requested!".tr())
cantMakeThatMapPopup.addCloseButton() .row()
cantMakeThatMapPopup.open() cantMakeThatMapPopup.addCloseButton()
Gdx.input.inputProcessor = stage cantMakeThatMapPopup.open()
Gdx.input.inputProcessor = stage
}
} }
} }

View File

@ -98,12 +98,14 @@ class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSe
//Save gameId to clipboard because you have to do it anyway. //Save gameId to clipboard because you have to do it anyway.
Gdx.app.clipboard.contents = newGame!!.gameId Gdx.app.clipboard.contents = newGame!!.gameId
//Popup to notify the User that the gameID got copied to the clipboard //Popup to notify the User that the gameID got copied to the clipboard
ResponsePopup("gameID copied to clipboard".tr(), UncivGame.Current.worldScreen, 2500) Gdx.app.postRunnable { ResponsePopup("gameID copied to clipboard".tr(), UncivGame.Current.worldScreen, 2500) }
} catch (ex: Exception) { } catch (ex: Exception) {
val cantUploadNewGamePopup = Popup(this) Gdx.app.postRunnable {
cantUploadNewGamePopup.addGoodSizedLabel("Could not upload game!") val cantUploadNewGamePopup = Popup(this)
cantUploadNewGamePopup.addCloseButton() cantUploadNewGamePopup.addGoodSizedLabel("Could not upload game!")
cantUploadNewGamePopup.open() cantUploadNewGamePopup.addCloseButton()
cantUploadNewGamePopup.open()
}
newGame = null newGame = null
} }
} }

View File

@ -55,9 +55,9 @@ class SaveGameScreen : PickerScreen() {
rightSideButton.setText("Save game".tr()) rightSideButton.setText("Save game".tr())
rightSideButton.onClick { rightSideButton.onClick {
rightSideButton.setText("Saving...".tr()) rightSideButton.setText("Saving...".tr())
thread(name="SaveGame"){ thread(name="SaveGame") {
GameSaver.saveGame(UncivGame.Current.gameInfo, textField.text) GameSaver.saveGame(UncivGame.Current.gameInfo, textField.text)
UncivGame.Current.setWorldScreen() Gdx.app.postRunnable { UncivGame.Current.setWorldScreen() }
} }
} }
rightSideButton.enable() rightSideButton.enable()

View File

@ -461,17 +461,19 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
try { try {
OnlineMultiplayer().tryUploadGame(gameInfoClone) OnlineMultiplayer().tryUploadGame(gameInfoClone)
} catch (ex: Exception) { } catch (ex: Exception) {
val cantUploadNewGamePopup = Popup(this) Gdx.app.postRunnable { // Since we're changing the UI, that should be done on the main thread
cantUploadNewGamePopup.addGoodSizedLabel("Could not upload game!").row() val cantUploadNewGamePopup = Popup(this)
cantUploadNewGamePopup.addCloseButton() cantUploadNewGamePopup.addGoodSizedLabel("Could not upload game!").row()
cantUploadNewGamePopup.open() cantUploadNewGamePopup.addCloseButton()
cantUploadNewGamePopup.open()
}
isPlayersTurn = true // Since we couldn't push the new game clone, then it's like we never clicked the "next turn" button isPlayersTurn = true // Since we couldn't push the new game clone, then it's like we never clicked the "next turn" button
shouldUpdate = true shouldUpdate = true
return@thread return@thread
} }
} }
} catch (ex: Exception) { } catch (ex: Exception) {
game.crashController.crashOccurred() Gdx.app.postRunnable { game.crashController.crashOccurred() }
throw ex throw ex
} }

View File

@ -220,19 +220,24 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen)
innerTable.add(errorTable).colspan(2).row() innerTable.add(errorTable).colspan(2).row()
downloadMusicButton.onClick { downloadMusicButton.onClick {
downloadMusicButton.disable()
errorTable.clear()
errorTable.add("Downloading...".toLabel())
// So the whole game doesn't get stuck while downloading the file // So the whole game doesn't get stuck while downloading the file
thread(name = "Music") { thread(name = "Music") {
try { try {
downloadMusicButton.disable()
errorTable.clear()
errorTable.add("Downloading...".toLabel())
val file = DropBox.downloadFile("/Music/thatched-villagers.mp3") val file = DropBox.downloadFile("/Music/thatched-villagers.mp3")
musicLocation.write(file, false) musicLocation.write(file, false)
rebuildInnerTable() Gdx.app.postRunnable {
worldScreen.game.startMusic() rebuildInnerTable()
worldScreen.game.startMusic()
}
} catch (ex: Exception) { } catch (ex: Exception) {
errorTable.clear() Gdx.app.postRunnable {
errorTable.add("Could not download music!".toLabel(Color.RED)) errorTable.clear()
errorTable.add("Could not download music!".toLabel(Color.RED))
}
} }
} }
} }

View File

@ -59,14 +59,16 @@ class UnitContextMenu(val tileMapHolder: WorldMapHolder, val selectedUnit: MapUn
fun onMoveButtonClick() { fun onMoveButtonClick() {
// this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread // this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread
thread(name="TileToMoveTo") { thread(name = "TileToMoveTo") {
// these are the heavy parts, finding where we want to go // these are the heavy parts, finding where we want to go
// Since this runs in a different thread, even if we check movement.canReach() // Since this runs in a different thread, even if we check movement.canReach()
// then it might change until we get to the getTileToMoveTo, so we just try/catch it // then it might change until we get to the getTileToMoveTo, so we just try/catch it
val tileToMoveTo:TileInfo val tileToMoveTo: TileInfo
try{ try {
tileToMoveTo = selectedUnit.movement.getTileToMoveToThisTurn(targetTile) tileToMoveTo = selectedUnit.movement.getTileToMoveToThisTurn(targetTile)
}catch (ex:Exception){ return@thread } // can't move here } catch (ex: Exception) {
return@thread
} // can't move here
Gdx.app.postRunnable { Gdx.app.postRunnable {
try { try {
@ -76,7 +78,7 @@ class UnitContextMenu(val tileMapHolder: WorldMapHolder, val selectedUnit: MapUn
// I can't think of any way to avoid this, // I can't think of any way to avoid this,
// but it's so rare and edge-case-y that ignoring its failure is actually acceptable, hence the empty catch // but it's so rare and edge-case-y that ignoring its failure is actually acceptable, hence the empty catch
selectedUnit.movement.moveToTile(tileToMoveTo) selectedUnit.movement.moveToTile(tileToMoveTo)
if(selectedUnit.action == Constants.unitActionExplore) selectedUnit.action = null // remove explore on manual move if (selectedUnit.action == Constants.unitActionExplore) selectedUnit.action = null // remove explore on manual move
Sounds.play(UncivSound.Whoosh) Sounds.play(UncivSound.Whoosh)
if (selectedUnit.currentTile != targetTile) if (selectedUnit.currentTile != targetTile)
selectedUnit.action = "moveTo " + targetTile.position.x.toInt() + "," + targetTile.position.y.toInt() selectedUnit.action = "moveTo " + targetTile.position.x.toInt() + "," + targetTile.position.y.toInt()
@ -86,8 +88,7 @@ class UnitContextMenu(val tileMapHolder: WorldMapHolder, val selectedUnit: MapUn
tileMapHolder.worldScreen.shouldUpdate = true tileMapHolder.worldScreen.shouldUpdate = true
tileMapHolder.unitActionOverlay?.remove() tileMapHolder.unitActionOverlay?.remove()
} catch (e: Exception) { } catch (e: Exception) {}
}
} }
} }