mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-29 15:01:09 -04:00
Fixed concurrency problems when working on "next turn" by working on a clone of the game state
This commit is contained in:
parent
05d3aa9193
commit
202c1828a7
@ -29,19 +29,19 @@ enum class GameSpeed{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameParameters{
|
class GameParameters { // Default values are the default new game
|
||||||
var difficulty="Prince"
|
var difficulty = "Prince"
|
||||||
var gameSpeed = GameSpeed.Standard
|
var gameSpeed = GameSpeed.Standard
|
||||||
var mapRadius=20
|
var mapRadius = 20
|
||||||
var players = ArrayList<Player>().apply {
|
var players = ArrayList<Player>().apply {
|
||||||
add(Player().apply { playerType=PlayerType.Human })
|
add(Player().apply { playerType = PlayerType.Human })
|
||||||
for(i in 1..3) add(Player())
|
for (i in 1..3) add(Player())
|
||||||
}
|
}
|
||||||
var numberOfCityStates=0
|
var numberOfCityStates = 0
|
||||||
var mapType= MapType.Perlin
|
var mapType = MapType.Perlin
|
||||||
var noBarbarians=false
|
var noBarbarians = false
|
||||||
var mapFileName :String?=null
|
var mapFileName: String? = null
|
||||||
var victoryTypes :ArrayList<VictoryType> = VictoryType.values().toCollection(ArrayList()) // By default, all victory types
|
var victoryTypes: ArrayList<VictoryType> = VictoryType.values().toCollection(ArrayList()) // By default, all victory types
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameStarter{
|
class GameStarter{
|
||||||
|
@ -16,9 +16,7 @@ class PlayerReadyScreen(currentPlayerCiv: CivilizationInfo) : CameraStageBaseScr
|
|||||||
.setFontColor(currentPlayerCiv.getNation().getSecondaryColor()))
|
.setFontColor(currentPlayerCiv.getNation().getSecondaryColor()))
|
||||||
|
|
||||||
table.onClick {
|
table.onClick {
|
||||||
UnCivGame.Current.worldScreen = WorldScreen(currentPlayerCiv).apply {
|
UnCivGame.Current.worldScreen = WorldScreen(currentPlayerCiv)
|
||||||
shouldUpdate = true
|
|
||||||
}
|
|
||||||
UnCivGame.Current.setWorldScreen()
|
UnCivGame.Current.setWorldScreen()
|
||||||
}
|
}
|
||||||
table.setFillParent(true)
|
table.setFillParent(true)
|
||||||
|
@ -165,16 +165,16 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
|||||||
notificationsScroll.setPosition(stage.width - notificationsScroll.width - 5f,
|
notificationsScroll.setPosition(stage.width - notificationsScroll.width - 5f,
|
||||||
nextTurnButton.y - notificationsScroll.height - 5f)
|
nextTurnButton.y - notificationsScroll.height - 5f)
|
||||||
|
|
||||||
when {
|
val isSomethingOpen = tutorials.isTutorialShowing || stage.actors.any { it is TradePopup }
|
||||||
!gameInfo.oneMoreTurnMode && gameInfo.civilizations.any { it.victoryManager.hasWon() } -> game.screen = VictoryScreen()
|
|| AlertPopup.isOpen
|
||||||
viewingCiv.policies.freePolicies>0 -> game.screen = PolicyPickerScreen(viewingCiv)
|
if(!isSomethingOpen) {
|
||||||
viewingCiv.greatPeople.freeGreatPeople>0 -> game.screen = GreatPersonPickerScreen()
|
when {
|
||||||
viewingCiv.tradeRequests.isNotEmpty() ->{
|
!gameInfo.oneMoreTurnMode && gameInfo.civilizations.any { it.victoryManager.hasWon() } -> game.screen = VictoryScreen()
|
||||||
TradePopup(this)
|
viewingCiv.policies.freePolicies > 0 -> game.screen = PolicyPickerScreen(viewingCiv)
|
||||||
|
viewingCiv.greatPeople.freeGreatPeople > 0 -> game.screen = GreatPersonPickerScreen()
|
||||||
|
viewingCiv.tradeRequests.isNotEmpty() -> TradePopup(this)
|
||||||
|
viewingCiv.popupAlerts.any() -> AlertPopup(this, viewingCiv.popupAlerts.first())
|
||||||
}
|
}
|
||||||
!tutorials.isTutorialShowing
|
|
||||||
&& viewingCiv.popupAlerts.any() && !AlertPopup.isOpen ->
|
|
||||||
AlertPopup(this,viewingCiv.popupAlerts.first())
|
|
||||||
}
|
}
|
||||||
updateNextTurnButton()
|
updateNextTurnButton()
|
||||||
}
|
}
|
||||||
@ -259,42 +259,53 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
|||||||
return@onClick
|
return@onClick
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTurn(nextTurnButton) // If none of the above
|
nextTurn() // If none of the above
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextTurnButton
|
return nextTurnButton
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextTurn(nextTurnButton: TextButton) {
|
private fun nextTurn() {
|
||||||
isPlayersTurn = false
|
isPlayersTurn = false
|
||||||
shouldUpdate = true
|
shouldUpdate = true
|
||||||
|
|
||||||
|
|
||||||
thread {
|
thread {
|
||||||
|
val gameInfoClone = gameInfo.clone()
|
||||||
|
gameInfoClone.setTransients()
|
||||||
try {
|
try {
|
||||||
gameInfo.nextTurn()
|
gameInfoClone.nextTurn()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
game.settings.hasCrashedRecently = true
|
game.settings.hasCrashedRecently = true
|
||||||
game.settings.save()
|
game.settings.save()
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameInfo.turns % game.settings.turnsBetweenAutosaves == 0) {
|
game.gameInfo = gameInfoClone
|
||||||
GameSaver().autoSave(gameInfo) {
|
|
||||||
nextTurnButton.enable() // only enable the user to next turn once we've saved the current one
|
|
||||||
updateNextTurnButton()
|
|
||||||
}
|
|
||||||
} else nextTurnButton.enable() // Enable immediately
|
|
||||||
|
|
||||||
// If we put this BEFORE the save game, then we try to save the game...
|
val shouldAutoSave = gameInfoClone.turns % game.settings.turnsBetweenAutosaves == 0
|
||||||
// but the main thread does other stuff, including showing tutorials which guess what? Changes the game data
|
|
||||||
// BOOM! Exception!
|
|
||||||
// That's why this needs to be after the game is saved.
|
|
||||||
isPlayersTurn = true
|
|
||||||
shouldUpdate = true
|
|
||||||
|
|
||||||
// do this on main thread
|
// create a new worldscreen to show the new stuff we've changed, and switch out the current screen.
|
||||||
|
// do this on main thread - it's the only one that has a GL context to create images from
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
updateNextTurnButton()
|
if(gameInfoClone.currentPlayerCiv.civName == viewingCiv.civName) {
|
||||||
|
val newWorldScreen = WorldScreen(gameInfoClone.currentPlayerCiv)
|
||||||
|
newWorldScreen.tileMapHolder.scrollX = tileMapHolder.scrollX
|
||||||
|
newWorldScreen.tileMapHolder.scrollY = tileMapHolder.scrollY
|
||||||
|
newWorldScreen.tileMapHolder.scaleX = tileMapHolder.scaleX
|
||||||
|
newWorldScreen.tileMapHolder.scaleY = tileMapHolder.scaleY
|
||||||
|
newWorldScreen.tileMapHolder.updateVisualScroll()
|
||||||
|
game.worldScreen = newWorldScreen
|
||||||
|
game.setWorldScreen()
|
||||||
|
}
|
||||||
|
else UnCivGame.Current.screen = PlayerReadyScreen(gameInfoClone.getCurrentPlayerCivilization())
|
||||||
|
|
||||||
|
if(shouldAutoSave) {
|
||||||
|
game.worldScreen.nextTurnButton.disable()
|
||||||
|
GameSaver().autoSave(gameInfoClone) {
|
||||||
|
game.worldScreen.nextTurnButton.enable() // only enable the user to next turn once we've saved the current one
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +335,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var shouldUpdate=true
|
var shouldUpdate=false
|
||||||
|
|
||||||
|
|
||||||
override fun render(delta: Float) {
|
override fun render(delta: Float) {
|
||||||
@ -333,12 +344,6 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
|||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
shouldUpdate = false
|
shouldUpdate = false
|
||||||
|
|
||||||
if (viewingCiv != gameInfo.getCurrentPlayerCivilization()) {
|
|
||||||
UnCivGame.Current.worldScreen.dispose() // for memory saving
|
|
||||||
UnCivGame.Current.screen = PlayerReadyScreen(gameInfo.getCurrentPlayerCivilization())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
update()
|
update()
|
||||||
showTutorialsOnNextTurn()
|
showTutorialsOnNextTurn()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user