mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 12:05:54 -04:00
AutoPlayEndTurn can run on a different thread (#11329)
* AutoPlay now builds military units more * AutoPlayEndTurn now launches in a new thread if there are more than 30 units/cities * Moved AutoPlay to WorldScreen and added isAIOrAutoPlaying() to Civilization * Fixed AI not wanting to pass through city-state tiles * Added black space to the end of AutoPlay * Partially fixed some NextTurnButton AutoPlay Behaviour * AutoPlay now persists across next turn WorldScreens * Made player's turn using AutoPlay run on a different thread * Remove the extra isAutoPlaying variable * AutoPlay class now manages all AutoPlay threads * Made AutoPlayMilitary and AutoPlayCivilian both able to run on a new thread. * Added more comments to AutoPlay * Maybe finally fixed the problems?
This commit is contained in:
parent
6b2fe87887
commit
a3d56845f9
@ -37,6 +37,7 @@ import com.unciv.ui.screens.mainmenuscreen.MainMenuScreen
|
|||||||
import com.unciv.ui.screens.savescreens.LoadGameScreen
|
import com.unciv.ui.screens.savescreens.LoadGameScreen
|
||||||
import com.unciv.ui.screens.worldscreen.PlayerReadyScreen
|
import com.unciv.ui.screens.worldscreen.PlayerReadyScreen
|
||||||
import com.unciv.ui.screens.worldscreen.WorldScreen
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
import com.unciv.ui.screens.worldscreen.unit.AutoPlay
|
||||||
import com.unciv.utils.Concurrency
|
import com.unciv.utils.Concurrency
|
||||||
import com.unciv.utils.DebugUtils
|
import com.unciv.utils.DebugUtils
|
||||||
import com.unciv.utils.Display
|
import com.unciv.utils.Display
|
||||||
@ -173,8 +174,9 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci
|
|||||||
* Automatically runs on the appropriate thread.
|
* Automatically runs on the appropriate thread.
|
||||||
*
|
*
|
||||||
* Sets the returned `WorldScreen` as the only active screen.
|
* Sets the returned `WorldScreen` as the only active screen.
|
||||||
|
* @param autoPlay pass in the old WorldScreen AutoPlay to retain the state throughout turns. Otherwise leave it is the default.
|
||||||
*/
|
*/
|
||||||
suspend fun loadGame(newGameInfo: GameInfo, callFromLoadScreen: Boolean = false): WorldScreen = withThreadPoolContext toplevel@{
|
suspend fun loadGame(newGameInfo: GameInfo, autoPlay: AutoPlay = AutoPlay(settings.autoPlay), callFromLoadScreen: Boolean = false): WorldScreen = withThreadPoolContext toplevel@{
|
||||||
val prevGameInfo = gameInfo
|
val prevGameInfo = gameInfo
|
||||||
gameInfo = newGameInfo
|
gameInfo = newGameInfo
|
||||||
|
|
||||||
@ -204,7 +206,7 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci
|
|||||||
screenStack.clear()
|
screenStack.clear()
|
||||||
|
|
||||||
worldScreen = null // This allows the GC to collect our old WorldScreen, otherwise we keep two WorldScreens in memory.
|
worldScreen = null // This allows the GC to collect our old WorldScreen, otherwise we keep two WorldScreens in memory.
|
||||||
val newWorldScreen = WorldScreen(newGameInfo, newGameInfo.getPlayerToViewAs(), worldScreenRestoreState)
|
val newWorldScreen = WorldScreen(newGameInfo, autoPlay, newGameInfo.getPlayerToViewAs(), worldScreenRestoreState)
|
||||||
worldScreen = newWorldScreen
|
worldScreen = newWorldScreen
|
||||||
|
|
||||||
val moreThanOnePlayer = newGameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
|
val moreThanOnePlayer = newGameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
|
||||||
@ -290,7 +292,7 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci
|
|||||||
fun popScreen(): BaseScreen? {
|
fun popScreen(): BaseScreen? {
|
||||||
if (screenStack.size == 1) {
|
if (screenStack.size == 1) {
|
||||||
musicController.pause()
|
musicController.pause()
|
||||||
settings.autoPlay.stopAutoPlay()
|
worldScreen?.autoPlay?.stopAutoPlay()
|
||||||
ConfirmPopup(
|
ConfirmPopup(
|
||||||
screen = screenStack.last(),
|
screen = screenStack.last(),
|
||||||
question = "Do you want to exit the game?",
|
question = "Do you want to exit the game?",
|
||||||
|
@ -389,16 +389,17 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
// Automation done here
|
// Automation done here
|
||||||
TurnManager(player).automateTurn()
|
TurnManager(player).automateTurn()
|
||||||
|
|
||||||
|
val worldScreen = UncivGame.Current.worldScreen
|
||||||
// Do we need to break if player won?
|
// Do we need to break if player won?
|
||||||
if (simulateUntilWin && player.victoryManager.hasWon()) {
|
if (simulateUntilWin && player.victoryManager.hasWon()) {
|
||||||
simulateUntilWin = false
|
simulateUntilWin = false
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen?.autoPlay?.stopAutoPlay()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we need to stop AutoPlay?
|
// Do we need to stop AutoPlay?
|
||||||
if (UncivGame.Current.settings.autoPlay.isAutoPlaying() && player.victoryManager.hasWon() && !oneMoreTurnMode)
|
if (worldScreen != null && worldScreen.autoPlay.isAutoPlaying() && player.victoryManager.hasWon() && !oneMoreTurnMode)
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
TurnManager(player).endTurn(progressBar)
|
TurnManager(player).endTurn(progressBar)
|
||||||
|
@ -164,7 +164,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
|||||||
&& city.getCenterTile().getTilesInDistance(5).none { it.militaryUnit?.civ == civInfo })
|
&& city.getCenterTile().getTilesInDistance(5).none { it.militaryUnit?.civ == civInfo })
|
||||||
modifier = 5f // there's a settler just sitting here, doing nothing - BAD
|
modifier = 5f // there's a settler just sitting here, doing nothing - BAD
|
||||||
|
|
||||||
if (civInfo.playerType == PlayerType.Human) modifier /= 2 // Players prefer to make their own unit choices usually
|
if (!civInfo.isAIOrAutoPlaying()) modifier /= 2 // Players prefer to make their own unit choices usually
|
||||||
modifier *= personality.scaledFocus(PersonalityValue.Military)
|
modifier *= personality.scaledFocus(PersonalityValue.Military)
|
||||||
addChoice(relativeCostEffectiveness, militaryUnit, modifier)
|
addChoice(relativeCostEffectiveness, militaryUnit, modifier)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, cachedForTurn: Int,
|
|||||||
cloningSource?.bestRoadAvailable ?:
|
cloningSource?.bestRoadAvailable ?:
|
||||||
//Player can choose not to auto-build roads & railroads.
|
//Player can choose not to auto-build roads & railroads.
|
||||||
if (civInfo.isHuman() && (!UncivGame.Current.settings.autoBuildingRoads
|
if (civInfo.isHuman() && (!UncivGame.Current.settings.autoBuildingRoads
|
||||||
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()))
|
|| UncivGame.Current.settings.autoPlay.fullAutoPlayAI))
|
||||||
RoadStatus.None
|
RoadStatus.None
|
||||||
else civInfo.tech.getBestRoadAvailable()
|
else civInfo.tech.getBestRoadAvailable()
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ object UnitAutomation {
|
|||||||
|
|
||||||
internal fun tryUpgradeUnit(unit: MapUnit): Boolean {
|
internal fun tryUpgradeUnit(unit: MapUnit): Boolean {
|
||||||
if (unit.civ.isHuman() && (!UncivGame.Current.settings.automatedUnitsCanUpgrade
|
if (unit.civ.isHuman() && (!UncivGame.Current.settings.automatedUnitsCanUpgrade
|
||||||
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) return false
|
|| UncivGame.Current.settings.autoPlay.fullAutoPlayAI)) return false
|
||||||
|
|
||||||
val upgradeUnits = getUnitsToUpgradeTo(unit)
|
val upgradeUnits = getUnitsToUpgradeTo(unit)
|
||||||
if (upgradeUnits.none()) return false // for resource reasons, usually
|
if (upgradeUnits.none()) return false // for resource reasons, usually
|
||||||
|
@ -325,7 +325,7 @@ class WorkerAutomation(
|
|||||||
.maxByOrNull { it.second }?.first
|
.maxByOrNull { it.second }?.first
|
||||||
|
|
||||||
if (tile.improvement != null && civInfo.isHuman() && (!UncivGame.Current.settings.automatedWorkersReplaceImprovements
|
if (tile.improvement != null && civInfo.isHuman() && (!UncivGame.Current.settings.automatedWorkersReplaceImprovements
|
||||||
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) {
|
|| UncivGame.Current.settings.autoPlay.fullAutoPlayAI)) {
|
||||||
// Note that we might still want to build roads or remove fallout, so we can't exit the function immedietly
|
// Note that we might still want to build roads or remove fallout, so we can't exit the function immedietly
|
||||||
bestBuildableImprovement = null
|
bestBuildableImprovement = null
|
||||||
}
|
}
|
||||||
|
@ -560,7 +560,7 @@ object Battle {
|
|||||||
city.puppetCity(attackerCiv)
|
city.puppetCity(attackerCiv)
|
||||||
//Although in Civ5 Venice is unable to re-annex their capital, that seems a bit silly. No check for May not annex cities here.
|
//Although in Civ5 Venice is unable to re-annex their capital, that seems a bit silly. No check for May not annex cities here.
|
||||||
city.annexCity()
|
city.annexCity()
|
||||||
} else if (attackerCiv.isHuman() && !(UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) {
|
} else if (attackerCiv.isHuman() && !(UncivGame.Current.settings.autoPlay.fullAutoPlayAI)) {
|
||||||
// we're not taking our former capital
|
// we're not taking our former capital
|
||||||
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.id))
|
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.id))
|
||||||
} else automateCityConquer(attackerCiv, city)
|
} else automateCityConquer(attackerCiv, city)
|
||||||
|
@ -709,7 +709,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
val isCurrentPlayersTurn = city.civ.gameInfo.isUsersTurn()
|
val isCurrentPlayersTurn = city.civ.gameInfo.isUsersTurn()
|
||||||
|| !city.civ.gameInfo.gameParameters.isOnlineMultiplayer
|
|| !city.civ.gameInfo.gameParameters.isOnlineMultiplayer
|
||||||
if ((isCurrentPlayersTurn && (UncivGame.Current.settings.autoAssignCityProduction
|
if ((isCurrentPlayersTurn && (UncivGame.Current.settings.autoAssignCityProduction
|
||||||
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) // only automate if the active human player has the setting to automate production
|
|| UncivGame.Current.settings.autoPlay.fullAutoPlayAI)) // only automate if the active human player has the setting to automate production
|
||||||
|| !city.civ.isHuman() || city.isPuppet) {
|
|| !city.civ.isHuman() || city.isPuppet) {
|
||||||
ConstructionAutomation(this).chooseNextConstruction()
|
ConstructionAutomation(this).chooseNextConstruction()
|
||||||
}
|
}
|
||||||
|
@ -333,6 +333,11 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
if (firstCityIfNoCapital) cities.firstOrNull() else null
|
if (firstCityIfNoCapital) cities.firstOrNull() else null
|
||||||
fun isHuman() = playerType == PlayerType.Human
|
fun isHuman() = playerType == PlayerType.Human
|
||||||
fun isAI() = playerType == PlayerType.AI
|
fun isAI() = playerType == PlayerType.AI
|
||||||
|
fun isAIOrAutoPlaying(): Boolean {
|
||||||
|
if (playerType == PlayerType.AI) return true
|
||||||
|
val worldScreen = UncivGame.Current.worldScreen ?: return false
|
||||||
|
return worldScreen.viewingCiv == this && worldScreen.autoPlay.isAutoPlaying()
|
||||||
|
}
|
||||||
fun isOneCityChallenger() = playerType == PlayerType.Human && gameInfo.gameParameters.oneCityChallenge
|
fun isOneCityChallenger() = playerType == PlayerType.Human && gameInfo.gameParameters.oneCityChallenge
|
||||||
|
|
||||||
fun isCurrentPlayer() = gameInfo.currentPlayerCiv == this
|
fun isCurrentPlayer() = gameInfo.currentPlayerCiv == this
|
||||||
@ -384,12 +389,11 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun wantsToFocusOn(focus: Victory.Focus): Boolean {
|
fun wantsToFocusOn(focus: Victory.Focus): Boolean {
|
||||||
return thingsToFocusOnForVictory.contains(focus) &&
|
return thingsToFocusOnForVictory.contains(focus) && isAIOrAutoPlaying()
|
||||||
(isAI() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPersonality(): Personality {
|
fun getPersonality(): Personality {
|
||||||
return if (isAI() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) gameInfo.ruleset.personalities[nation.personality] ?: Personality.neutralPersonality
|
return if (isAIOrAutoPlaying()) gameInfo.ruleset.personalities[nation.personality] ?: Personality.neutralPersonality
|
||||||
else Personality.neutralPersonality
|
else Personality.neutralPersonality
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
|||||||
if (diplomacyManager != null && (diplomacyManager.hasOpenBorders || diplomacyManager.diplomaticStatus == DiplomaticStatus.War))
|
if (diplomacyManager != null && (diplomacyManager.hasOpenBorders || diplomacyManager.diplomaticStatus == DiplomaticStatus.War))
|
||||||
return true
|
return true
|
||||||
// Players can always pass through city-state tiles
|
// Players can always pass through city-state tiles
|
||||||
if ((civInfo.isHuman() && !UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) && otherCiv.isCityState()) return true
|
if (!civInfo.isAIOrAutoPlaying() && otherCiv.isCityState()) return true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,6 @@ class OnlineMultiplayer {
|
|||||||
} else if (onlinePreview != null && hasNewerGameState(preview, onlinePreview)) {
|
} else if (onlinePreview != null && hasNewerGameState(preview, onlinePreview)) {
|
||||||
onlineGame.doManualUpdate(preview)
|
onlineGame.doManualUpdate(preview)
|
||||||
}
|
}
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
|
||||||
UncivGame.Current.loadGame(gameInfo)
|
UncivGame.Current.loadGame(gameInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,22 +339,6 @@ class GameSettings {
|
|||||||
var autoPlayPolicies: Boolean = true
|
var autoPlayPolicies: Boolean = true
|
||||||
var autoPlayReligion: Boolean = true
|
var autoPlayReligion: Boolean = true
|
||||||
var autoPlayDiplomacy: Boolean = true
|
var autoPlayDiplomacy: Boolean = true
|
||||||
|
|
||||||
var turnsToAutoPlay: Int = 0
|
|
||||||
var autoPlayTurnInProgress: Boolean = false
|
|
||||||
|
|
||||||
fun startAutoPlay() {
|
|
||||||
turnsToAutoPlay = autoPlayMaxTurns
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stopAutoPlay() {
|
|
||||||
turnsToAutoPlay = 0
|
|
||||||
autoPlayTurnInProgress = false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isAutoPlaying(): Boolean = turnsToAutoPlay > 0
|
|
||||||
|
|
||||||
fun isAutoPlayingAndFullAI(): Boolean = isAutoPlaying() && fullAutoPlayAI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SuspiciousCallableReferenceInLambda") // By @Azzurite, safe as long as that warning below is followed
|
@Suppress("SuspiciousCallableReferenceInLambda") // By @Azzurite, safe as long as that warning below is followed
|
||||||
|
@ -339,7 +339,7 @@ object UniqueTriggerActivation {
|
|||||||
if (notification != null)
|
if (notification != null)
|
||||||
civInfo.addNotification(notification, NotificationCategory.General)
|
civInfo.addNotification(notification, NotificationCategory.General)
|
||||||
|
|
||||||
if (civInfo.isAI() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) {
|
if (civInfo.isAI() || UncivGame.Current.settings.autoPlay.fullAutoPlayAI) {
|
||||||
NextTurnAutomation.chooseGreatPerson(civInfo)
|
NextTurnAutomation.chooseGreatPerson(civInfo)
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -76,7 +76,7 @@ object MayaCalendar {
|
|||||||
val year = game.getYear()
|
val year = game.getYear()
|
||||||
if (!isNewCycle(year, game.getYear(-1))) return
|
if (!isNewCycle(year, game.getYear(-1))) return
|
||||||
civInfo.greatPeople.triggerMayanGreatPerson()
|
civInfo.greatPeople.triggerMayanGreatPerson()
|
||||||
if (civInfo.isAI() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())
|
if (civInfo.isAI() || UncivGame.Current.settings.autoPlay.fullAutoPlayAI)
|
||||||
NextTurnAutomation.chooseGreatPerson(civInfo)
|
NextTurnAutomation.chooseGreatPerson(civInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package com.unciv.ui.popups.options
|
package com.unciv.ui.popups.options
|
||||||
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.GUI
|
||||||
import com.unciv.models.metadata.GameSettings
|
import com.unciv.models.metadata.GameSettings
|
||||||
import com.unciv.ui.components.widgets.UncivSlider
|
import com.unciv.ui.components.widgets.UncivSlider
|
||||||
import com.unciv.ui.components.extensions.toLabel
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
|
||||||
fun autoPlayTab(
|
fun autoPlayTab(optionsPopup: OptionsPopup
|
||||||
optionsPopup: OptionsPopup
|
|
||||||
): Table = Table(BaseScreen.skin).apply {
|
): Table = Table(BaseScreen.skin).apply {
|
||||||
pad(10f)
|
pad(10f)
|
||||||
defaults().pad(5f)
|
defaults().pad(5f)
|
||||||
@ -56,7 +57,8 @@ fun autoPlayTab(
|
|||||||
"Show AutoPlay button",
|
"Show AutoPlay button",
|
||||||
settings.autoPlay.showAutoPlayButton, true
|
settings.autoPlay.showAutoPlayButton, true
|
||||||
) { settings.autoPlay.showAutoPlayButton = it
|
) { settings.autoPlay.showAutoPlayButton = it
|
||||||
settings.autoPlay.stopAutoPlay() }
|
GUI.getWorldScreenIfActive()?.autoPlay?.stopAutoPlay()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
optionsPopup.addCheckbox(
|
optionsPopup.addCheckbox(
|
||||||
|
@ -135,7 +135,7 @@ fun debugTab(
|
|||||||
val clipboardContentsString = Gdx.app.clipboard.contents.trim()
|
val clipboardContentsString = Gdx.app.clipboard.contents.trim()
|
||||||
val loadedGame = UncivFiles.gameInfoFromString(clipboardContentsString)
|
val loadedGame = UncivFiles.gameInfoFromString(clipboardContentsString)
|
||||||
loadedGame.gameParameters.isOnlineMultiplayer = false
|
loadedGame.gameParameters.isOnlineMultiplayer = false
|
||||||
optionsPopup.game.loadGame(loadedGame, true)
|
optionsPopup.game.loadGame(loadedGame, callFromLoadScreen = true)
|
||||||
optionsPopup.close()
|
optionsPopup.close()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
ToastPopup(ex.message ?: ex::class.java.simpleName, optionsPopup.stageToShowOn).open(true)
|
ToastPopup(ex.message ?: ex::class.java.simpleName, optionsPopup.stageToShowOn).open(true)
|
||||||
|
@ -9,12 +9,13 @@ import com.unciv.ui.images.ImageGetter
|
|||||||
import com.unciv.ui.components.extensions.isEnabled
|
import com.unciv.ui.components.extensions.isEnabled
|
||||||
import com.unciv.ui.components.input.onClick
|
import com.unciv.ui.components.input.onClick
|
||||||
import com.unciv.ui.components.input.onDoubleClick
|
import com.unciv.ui.components.input.onDoubleClick
|
||||||
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
|
||||||
class GreatPersonPickerScreen(val civInfo: Civilization) : PickerScreen() {
|
class GreatPersonPickerScreen(val worldScreen: WorldScreen, val civInfo: Civilization) : PickerScreen() {
|
||||||
private var theChosenOne: BaseUnit? = null
|
private var theChosenOne: BaseUnit? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
closeButton.isVisible = false
|
closeButton.isVisible = false
|
||||||
rightSideButton.setText("Choose a free great person".tr())
|
rightSideButton.setText("Choose a free great person".tr())
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import com.unciv.ui.popups.Popup
|
|||||||
import com.unciv.ui.popups.ToastPopup
|
import com.unciv.ui.popups.ToastPopup
|
||||||
import com.unciv.logic.github.Github
|
import com.unciv.logic.github.Github
|
||||||
import com.unciv.logic.github.Github.folderNameToRepoName
|
import com.unciv.logic.github.Github.folderNameToRepoName
|
||||||
|
import com.unciv.ui.popups.closeAllPopups
|
||||||
import com.unciv.utils.Concurrency
|
import com.unciv.utils.Concurrency
|
||||||
import com.unciv.utils.Log
|
import com.unciv.utils.Log
|
||||||
import com.unciv.utils.launchOnGLThread
|
import com.unciv.utils.launchOnGLThread
|
||||||
@ -122,14 +123,13 @@ class LoadGameScreen : LoadOrSaveScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onLoadGame() {
|
private fun onLoadGame() {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
|
||||||
if (selectedSave == null) return
|
if (selectedSave == null) return
|
||||||
val loadingPopup = LoadingPopup(this)
|
val loadingPopup = LoadingPopup(this)
|
||||||
Concurrency.run(loadGame) {
|
Concurrency.run(loadGame) {
|
||||||
try {
|
try {
|
||||||
// This is what can lead to ANRs - reading the file and setting the transients, that's why this is in another thread
|
// This is what can lead to ANRs - reading the file and setting the transients, that's why this is in another thread
|
||||||
val loadedGame = game.files.loadGameFromFile(selectedSave!!)
|
val loadedGame = game.files.loadGameFromFile(selectedSave!!)
|
||||||
game.loadGame(loadedGame, true)
|
game.loadGame(loadedGame, callFromLoadScreen = true)
|
||||||
} catch (notAPlayer: UncivShowableException) {
|
} catch (notAPlayer: UncivShowableException) {
|
||||||
launchOnGLThread {
|
launchOnGLThread {
|
||||||
val (message) = getLoadExceptionMessage(notAPlayer)
|
val (message) = getLoadExceptionMessage(notAPlayer)
|
||||||
@ -155,7 +155,7 @@ class LoadGameScreen : LoadOrSaveScreen() {
|
|||||||
try {
|
try {
|
||||||
val clipboardContentsString = Gdx.app.clipboard.contents.trim()
|
val clipboardContentsString = Gdx.app.clipboard.contents.trim()
|
||||||
val loadedGame = UncivFiles.gameInfoFromString(clipboardContentsString)
|
val loadedGame = UncivFiles.gameInfoFromString(clipboardContentsString)
|
||||||
game.loadGame(loadedGame, true)
|
game.loadGame(loadedGame, callFromLoadScreen = true)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
launchOnGLThread { handleLoadGameException(ex, "Could not load game from clipboard!") }
|
launchOnGLThread { handleLoadGameException(ex, "Could not load game from clipboard!") }
|
||||||
} finally {
|
} finally {
|
||||||
@ -181,7 +181,7 @@ class LoadGameScreen : LoadOrSaveScreen() {
|
|||||||
Concurrency.run(Companion.loadFromCustomLocation) {
|
Concurrency.run(Companion.loadFromCustomLocation) {
|
||||||
game.files.loadGameFromCustomLocation(
|
game.files.loadGameFromCustomLocation(
|
||||||
{
|
{
|
||||||
Concurrency.run { game.loadGame(it, true) }
|
Concurrency.run { game.loadGame(it, callFromLoadScreen = true) }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
if (it !is PlatformSaverLoader.Cancelled)
|
if (it !is PlatformSaverLoader.Cancelled)
|
||||||
|
@ -35,7 +35,7 @@ object QuickSave {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun load(screen: WorldScreen) {
|
fun load(screen: WorldScreen) {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
screen.autoPlay.stopAutoPlay()
|
||||||
val files = UncivGame.Current.files
|
val files = UncivGame.Current.files
|
||||||
val toast = ToastPopup("Quickloading...", screen)
|
val toast = ToastPopup("Quickloading...", screen)
|
||||||
Concurrency.run("QuickLoadGame") {
|
Concurrency.run("QuickLoadGame") {
|
||||||
@ -58,7 +58,6 @@ object QuickSave {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun autoLoadGame(screen: MainMenuScreen) {
|
fun autoLoadGame(screen: MainMenuScreen) {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
|
||||||
val loadingPopup = LoadingPopup(screen)
|
val loadingPopup = LoadingPopup(screen)
|
||||||
Concurrency.run("autoLoadGame") {
|
Concurrency.run("autoLoadGame") {
|
||||||
// Load game from file to class on separate thread to avoid ANR...
|
// Load game from file to class on separate thread to avoid ANR...
|
||||||
|
@ -85,7 +85,7 @@ class VictoryScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
//**************** Set up the tabs ****************
|
//**************** Set up the tabs ****************
|
||||||
splitPane.setFirstWidget(tabs)
|
splitPane.setFirstWidget(tabs)
|
||||||
val iconSize = Constants.headingFontSize.toFloat()
|
val iconSize = Constants.headingFontSize.toFloat()
|
||||||
@ -161,7 +161,7 @@ class VictoryScreen(
|
|||||||
displayWonOrLost("[$winningCiv] has won a [$victoryType] Victory!", victory.defeatString)
|
displayWonOrLost("[$winningCiv] has won a [$victoryType] Victory!", victory.defeatString)
|
||||||
music.chooseTrack(playerCiv.civName, MusicMood.Defeat, EnumSet.of(MusicTrackChooserFlags.SuffixMustMatch))
|
music.chooseTrack(playerCiv.civName, MusicMood.Defeat, EnumSet.of(MusicTrackChooserFlags.SuffixMustMatch))
|
||||||
}
|
}
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayWonOrLost(vararg descriptions: String) {
|
private fun displayWonOrLost(vararg descriptions: String) {
|
||||||
|
@ -59,6 +59,7 @@ import com.unciv.ui.screens.worldscreen.status.NextTurnButton
|
|||||||
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
|
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
|
||||||
import com.unciv.ui.screens.worldscreen.status.StatusButtons
|
import com.unciv.ui.screens.worldscreen.status.StatusButtons
|
||||||
import com.unciv.ui.screens.worldscreen.topbar.WorldScreenTopBar
|
import com.unciv.ui.screens.worldscreen.topbar.WorldScreenTopBar
|
||||||
|
import com.unciv.ui.screens.worldscreen.unit.AutoPlay
|
||||||
import com.unciv.ui.screens.worldscreen.unit.UnitTable
|
import com.unciv.ui.screens.worldscreen.unit.UnitTable
|
||||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsTable
|
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsTable
|
||||||
import com.unciv.utils.Concurrency
|
import com.unciv.utils.Concurrency
|
||||||
@ -81,6 +82,7 @@ import kotlin.concurrent.timer
|
|||||||
*/
|
*/
|
||||||
class WorldScreen(
|
class WorldScreen(
|
||||||
val gameInfo: GameInfo,
|
val gameInfo: GameInfo,
|
||||||
|
val autoPlay: AutoPlay,
|
||||||
val viewingCiv: Civilization,
|
val viewingCiv: Civilization,
|
||||||
restoreState: RestoreState? = null
|
restoreState: RestoreState? = null
|
||||||
) : BaseScreen() {
|
) : BaseScreen() {
|
||||||
@ -130,6 +132,7 @@ class WorldScreen(
|
|||||||
|
|
||||||
internal val undoHandler = UndoHandler(this)
|
internal val undoHandler = UndoHandler(this)
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// notifications are right-aligned, they take up only as much space as necessary.
|
// notifications are right-aligned, they take up only as much space as necessary.
|
||||||
notificationsScroll.width = stage.width / 2
|
notificationsScroll.width = stage.width / 2
|
||||||
@ -328,7 +331,7 @@ class WorldScreen(
|
|||||||
launchOnGLThread {
|
launchOnGLThread {
|
||||||
loadingGamePopup.close()
|
loadingGamePopup.close()
|
||||||
}
|
}
|
||||||
startNewScreenJob(latestGame)
|
startNewScreenJob(latestGame, autoPlay)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
launchOnGLThread {
|
launchOnGLThread {
|
||||||
val (message) = LoadGameScreen.getLoadExceptionMessage(ex, "Couldn't download the latest game state!")
|
val (message) = LoadGameScreen.getLoadExceptionMessage(ex, "Couldn't download the latest game state!")
|
||||||
@ -406,19 +409,18 @@ class WorldScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the game has ended, lets stop AutoPlay
|
// If the game has ended, lets stop AutoPlay
|
||||||
if (game.settings.autoPlay.isAutoPlaying()
|
if (autoPlay.isAutoPlaying() && !gameInfo.oneMoreTurnMode && (viewingCiv.isDefeated() || gameInfo.checkForVictory())) {
|
||||||
&& !gameInfo.oneMoreTurnMode && (viewingCiv.isDefeated() || gameInfo.checkForVictory())) {
|
autoPlay.stopAutoPlay()
|
||||||
game.settings.autoPlay.stopAutoPlay()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasOpenPopups() && !game.settings.autoPlay.isAutoPlaying() && isPlayersTurn) {
|
if (!hasOpenPopups() && !autoPlay.isAutoPlaying() && isPlayersTurn) {
|
||||||
when {
|
when {
|
||||||
viewingCiv.shouldShowDiplomaticVotingResults() ->
|
viewingCiv.shouldShowDiplomaticVotingResults() ->
|
||||||
UncivGame.Current.pushScreen(DiplomaticVoteResultScreen(gameInfo.diplomaticVictoryVotesCast, viewingCiv))
|
UncivGame.Current.pushScreen(DiplomaticVoteResultScreen(gameInfo.diplomaticVictoryVotesCast, viewingCiv))
|
||||||
!gameInfo.oneMoreTurnMode && (viewingCiv.isDefeated() || gameInfo.checkForVictory()) ->
|
!gameInfo.oneMoreTurnMode && (viewingCiv.isDefeated() || gameInfo.checkForVictory()) ->
|
||||||
game.pushScreen(VictoryScreen(this))
|
game.pushScreen(VictoryScreen(this))
|
||||||
viewingCiv.greatPeople.freeGreatPeople > 0 ->
|
viewingCiv.greatPeople.freeGreatPeople > 0 ->
|
||||||
game.pushScreen(GreatPersonPickerScreen(viewingCiv))
|
game.pushScreen(GreatPersonPickerScreen(this, viewingCiv))
|
||||||
viewingCiv.popupAlerts.any() -> AlertPopup(this, viewingCiv.popupAlerts.first())
|
viewingCiv.popupAlerts.any() -> AlertPopup(this, viewingCiv.popupAlerts.first())
|
||||||
viewingCiv.tradeRequests.isNotEmpty() -> {
|
viewingCiv.tradeRequests.isNotEmpty() -> {
|
||||||
// In the meantime this became invalid, perhaps because we accepted previous trades
|
// In the meantime this became invalid, perhaps because we accepted previous trades
|
||||||
@ -648,7 +650,7 @@ class WorldScreen(
|
|||||||
|
|
||||||
progressBar.increment()
|
progressBar.increment()
|
||||||
|
|
||||||
startNewScreenJob(gameInfoClone)
|
startNewScreenJob(gameInfoClone, autoPlay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,7 +703,7 @@ class WorldScreen(
|
|||||||
} else {
|
} else {
|
||||||
if (!game.settings.autoPlay.showAutoPlayButton) {
|
if (!game.settings.autoPlay.showAutoPlayButton) {
|
||||||
statusButtons.autoPlayStatusButton = null
|
statusButtons.autoPlayStatusButton = null
|
||||||
game.settings.autoPlay.stopAutoPlay()
|
autoPlay.stopAutoPlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -725,7 +727,7 @@ class WorldScreen(
|
|||||||
resizeDeferTimer = timer("Resize", daemon = true, 500L, Long.MAX_VALUE) {
|
resizeDeferTimer = timer("Resize", daemon = true, 500L, Long.MAX_VALUE) {
|
||||||
resizeDeferTimer?.cancel()
|
resizeDeferTimer?.cancel()
|
||||||
resizeDeferTimer = null
|
resizeDeferTimer = null
|
||||||
startNewScreenJob(gameInfo, true) // start over
|
startNewScreenJob(gameInfo, autoPlay, true) // start over
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,10 +807,10 @@ class WorldScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** This exists so that no reference to the current world screen remains, so the old world screen can get garbage collected during [UncivGame.loadGame]. */
|
/** This exists so that no reference to the current world screen remains, so the old world screen can get garbage collected during [UncivGame.loadGame]. */
|
||||||
private fun startNewScreenJob(gameInfo: GameInfo, autosaveDisabled: Boolean = false) {
|
private fun startNewScreenJob(gameInfo: GameInfo, autoPlay: AutoPlay, autosaveDisabled: Boolean = false) {
|
||||||
Concurrency.run {
|
Concurrency.run {
|
||||||
val newWorldScreen = try {
|
val newWorldScreen = try {
|
||||||
UncivGame.Current.loadGame(gameInfo)
|
UncivGame.Current.loadGame(gameInfo, autoPlay)
|
||||||
} catch (notAPlayer: UncivShowableException) {
|
} catch (notAPlayer: UncivShowableException) {
|
||||||
withGLContext {
|
withGLContext {
|
||||||
val (message) = LoadGameScreen.getLoadExceptionMessage(notAPlayer)
|
val (message) = LoadGameScreen.getLoadExceptionMessage(notAPlayer)
|
||||||
|
@ -11,7 +11,7 @@ import com.unciv.ui.screens.worldscreen.WorldScreen
|
|||||||
|
|
||||||
class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen, scrollable = Scrollability.All) {
|
class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen, scrollable = Scrollability.All) {
|
||||||
init {
|
init {
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
defaults().fillX()
|
defaults().fillX()
|
||||||
|
|
||||||
addButton("Main menu") {
|
addButton("Main menu") {
|
||||||
|
@ -3,13 +3,14 @@ package com.unciv.ui.screens.worldscreen.status
|
|||||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
import com.badlogic.gdx.scenes.scene2d.Stage
|
import com.badlogic.gdx.scenes.scene2d.Stage
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.unciv.GUI
|
|
||||||
import com.unciv.logic.automation.civilization.NextTurnAutomation
|
import com.unciv.logic.automation.civilization.NextTurnAutomation
|
||||||
import com.unciv.logic.automation.unit.UnitAutomation
|
import com.unciv.logic.automation.unit.UnitAutomation
|
||||||
import com.unciv.logic.civilization.managers.TurnManager
|
import com.unciv.logic.civilization.managers.TurnManager
|
||||||
import com.unciv.ui.components.input.KeyboardBinding
|
import com.unciv.ui.components.input.KeyboardBinding
|
||||||
import com.unciv.ui.popups.AnimatedMenuPopup
|
import com.unciv.ui.popups.AnimatedMenuPopup
|
||||||
import com.unciv.ui.screens.worldscreen.WorldScreen
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
import com.unciv.ui.screens.worldscreen.unit.AutoPlay
|
||||||
|
import com.unciv.utils.Concurrency
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "context" menu for the AutoPlay button
|
* The "context" menu for the AutoPlay button
|
||||||
@ -20,18 +21,19 @@ class AutoPlayMenu(
|
|||||||
private val nextTurnButton: NextTurnButton,
|
private val nextTurnButton: NextTurnButton,
|
||||||
private val worldScreen: WorldScreen
|
private val worldScreen: WorldScreen
|
||||||
) : AnimatedMenuPopup(stage, getActorTopRight(positionNextTo)) {
|
) : AnimatedMenuPopup(stage, getActorTopRight(positionNextTo)) {
|
||||||
private val settings = GUI.getSettings()
|
|
||||||
|
private val autoPlay: AutoPlay = worldScreen.autoPlay
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// We need to activate the end turn button again after the menu closes
|
// We need to activate the end turn button again after the menu closes
|
||||||
afterCloseCallback = { worldScreen.shouldUpdate = true }
|
afterCloseCallback = { worldScreen.shouldUpdate = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createContentTable(): Table {
|
override fun createContentTable(): Table {
|
||||||
val table = super.createContentTable()!!
|
val table = super.createContentTable()!!
|
||||||
// Using the same keyboard binding for bypassing this menu and the default option
|
// Using the same keyboard binding for bypassing this menu and the default option
|
||||||
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer)
|
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer)
|
||||||
table.add(getButton("Start AutoPlay", KeyboardBinding.AutoPlay, ::autoPlay)).row()
|
table.add(getButton("Start AutoPlay", KeyboardBinding.AutoPlay, ::multiturnAutoPlay)).row()
|
||||||
table.add(getButton("AutoPlay End Turn", KeyboardBinding.AutoPlayMenuEndTurn, ::autoPlayEndTurn)).row()
|
table.add(getButton("AutoPlay End Turn", KeyboardBinding.AutoPlayMenuEndTurn, ::autoPlayEndTurn)).row()
|
||||||
table.add(getButton("AutoPlay Military Once", KeyboardBinding.AutoPlayMenuMilitary, ::autoPlayMilitary)).row()
|
table.add(getButton("AutoPlay Military Once", KeyboardBinding.AutoPlayMenuMilitary, ::autoPlayMilitary)).row()
|
||||||
table.add(getButton("AutoPlay Civilians Once", KeyboardBinding.AutoPlayMenuCivilians, ::autoPlayCivilian)).row()
|
table.add(getButton("AutoPlay Civilians Once", KeyboardBinding.AutoPlayMenuCivilians, ::autoPlayCivilian)).row()
|
||||||
@ -41,33 +43,61 @@ class AutoPlayMenu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun autoPlayEndTurn() {
|
private fun autoPlayEndTurn() {
|
||||||
TurnManager(worldScreen.viewingCiv).automateTurn()
|
val endTurnFunction = {
|
||||||
worldScreen.nextTurn()
|
nextTurnButton.update()
|
||||||
|
TurnManager(worldScreen.viewingCiv).automateTurn()
|
||||||
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
|
worldScreen.nextTurn()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worldScreen.viewingCiv.units.getCivUnitsSize() + worldScreen.viewingCiv.cities.size >= 30) {
|
||||||
|
autoPlay.runAutoPlayJobInNewThread("AutoPlayEndTurn", worldScreen, false, endTurnFunction)
|
||||||
|
} else {
|
||||||
|
autoPlay.autoPlayTurnInProgress = true
|
||||||
|
endTurnFunction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun autoPlay() {
|
private fun multiturnAutoPlay() {
|
||||||
settings.autoPlay.startAutoPlay()
|
worldScreen.autoPlay.startMultiturnAutoPlay()
|
||||||
nextTurnButton.update()
|
nextTurnButton.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun autoPlayMilitary() {
|
private fun autoPlayMilitary() {
|
||||||
val civInfo = worldScreen.viewingCiv
|
val civInfo = worldScreen.viewingCiv
|
||||||
val isAtWar = civInfo.isAtWar()
|
val autoPlayMilitaryFunction = {
|
||||||
val sortedUnits = civInfo.units.getCivUnits().filter { it.isMilitary() }.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
|
val isAtWar = civInfo.isAtWar()
|
||||||
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
|
val sortedUnits = civInfo.units.getCivUnits().filter { it.isMilitary() }.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
|
||||||
|
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
|
||||||
|
|
||||||
for (city in civInfo.cities) UnitAutomation.tryBombardEnemy(city)
|
for (city in civInfo.cities) UnitAutomation.tryBombardEnemy(city)
|
||||||
worldScreen.shouldUpdate = true
|
worldScreen.shouldUpdate = true
|
||||||
worldScreen.render(0f)
|
}
|
||||||
|
if (civInfo.units.getCivUnitsSize() > 30) {
|
||||||
|
autoPlay.runAutoPlayJobInNewThread("AutoPlayMilitary", worldScreen, true, autoPlayMilitaryFunction)
|
||||||
|
} else {
|
||||||
|
autoPlay.autoPlayTurnInProgress = true
|
||||||
|
autoPlayMilitaryFunction()
|
||||||
|
autoPlay.autoPlayTurnInProgress = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun autoPlayCivilian() {
|
private fun autoPlayCivilian() {
|
||||||
val civInfo = worldScreen.viewingCiv
|
val civInfo = worldScreen.viewingCiv
|
||||||
val isAtWar = civInfo.isAtWar()
|
val autoPlayCivilainFunction = {
|
||||||
val sortedUnits = civInfo.units.getCivUnits().filter { it.isCivilian() }.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
|
val isAtWar = civInfo.isAtWar()
|
||||||
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
|
val sortedUnits = civInfo.units.getCivUnits().filter { it.isCivilian() }
|
||||||
worldScreen.shouldUpdate = true
|
.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
|
||||||
worldScreen.render(0f)
|
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
|
||||||
|
worldScreen.shouldUpdate = true
|
||||||
|
}
|
||||||
|
if (civInfo.units.getCivUnitsSize() > 50) {
|
||||||
|
autoPlay.runAutoPlayJobInNewThread("AutoPlayCivilian", worldScreen, true, autoPlayCivilainFunction)
|
||||||
|
} else {
|
||||||
|
autoPlay.autoPlayTurnInProgress = true
|
||||||
|
autoPlayCivilainFunction()
|
||||||
|
autoPlay.autoPlayTurnInProgress = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun autoPlayEconomy() {
|
private fun autoPlayEconomy() {
|
||||||
|
@ -23,17 +23,16 @@ class AutoPlayStatusButton(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
add(Stack(autoPlayImage)).pad(5f)
|
add(Stack(autoPlayImage)).pad(5f)
|
||||||
val settings = GUI.getSettings()
|
|
||||||
onActivation(binding = KeyboardBinding.AutoPlayMenu) {
|
onActivation(binding = KeyboardBinding.AutoPlayMenu) {
|
||||||
if (settings.autoPlay.isAutoPlaying())
|
if (worldScreen.autoPlay.isAutoPlaying())
|
||||||
settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
else if (worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv)
|
else if (worldScreen.isPlayersTurn)
|
||||||
AutoPlayMenu(stage,this, nextTurnButton, worldScreen)
|
AutoPlayMenu(stage,this, nextTurnButton, worldScreen)
|
||||||
}
|
}
|
||||||
val directAutoPlay = {
|
val directAutoPlay = {
|
||||||
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer
|
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer
|
||||||
&& worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv) {
|
&& worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv) {
|
||||||
settings.autoPlay.startAutoPlay()
|
worldScreen.autoPlay.startMultiturnAutoPlay()
|
||||||
nextTurnButton.update()
|
nextTurnButton.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,9 +47,8 @@ class AutoPlayStatusButton(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
val settings = GUI.getSettings()
|
if (isPressed && worldScreen.autoPlay.isAutoPlaying()) {
|
||||||
if (isPressed && settings.autoPlay.isAutoPlaying()) {
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
settings.autoPlay.stopAutoPlay()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ enum class NextTurnAction(protected val text: String, val color: Color) {
|
|||||||
},
|
},
|
||||||
AutoPlay("AutoPlay", Color.WHITE) {
|
AutoPlay("AutoPlay", Color.WHITE) {
|
||||||
override fun isChoice(worldScreen: WorldScreen) =
|
override fun isChoice(worldScreen: WorldScreen) =
|
||||||
UncivGame.Current.settings.autoPlay.isAutoPlaying()
|
worldScreen.autoPlay.isAutoPlaying()
|
||||||
override fun action(worldScreen: WorldScreen) =
|
override fun action(worldScreen: WorldScreen) =
|
||||||
UncivGame.Current.settings.autoPlay.stopAutoPlay()
|
worldScreen.autoPlay.stopAutoPlay()
|
||||||
},
|
},
|
||||||
Working(Constants.working, Color.GRAY) {
|
Working(Constants.working, Color.GRAY) {
|
||||||
override fun isChoice(worldScreen: WorldScreen) =
|
override fun isChoice(worldScreen: WorldScreen) =
|
||||||
|
@ -14,6 +14,7 @@ import com.unciv.ui.images.IconTextButton
|
|||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.popups.hasOpenPopups
|
import com.unciv.ui.popups.hasOpenPopups
|
||||||
import com.unciv.ui.screens.worldscreen.WorldScreen
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
import com.unciv.utils.Concurrency
|
||||||
|
|
||||||
class NextTurnButton(
|
class NextTurnButton(
|
||||||
private val worldScreen: WorldScreen
|
private val worldScreen: WorldScreen
|
||||||
@ -33,19 +34,17 @@ class NextTurnButton(
|
|||||||
fun update() {
|
fun update() {
|
||||||
nextTurnAction = getNextTurnAction(worldScreen)
|
nextTurnAction = getNextTurnAction(worldScreen)
|
||||||
updateButton(nextTurnAction)
|
updateButton(nextTurnAction)
|
||||||
val settings = GUI.getSettings()
|
val autoPlay = worldScreen.autoPlay
|
||||||
if (!settings.autoPlay.autoPlayTurnInProgress && settings.autoPlay.isAutoPlaying()
|
if (autoPlay.shouldContinueAutoPlaying() && worldScreen.isPlayersTurn
|
||||||
&& worldScreen.isPlayersTurn && !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning()) {
|
&& !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning()) {
|
||||||
settings.autoPlay.autoPlayTurnInProgress = true
|
autoPlay.runAutoPlayJobInNewThread("MultiturnAutoPlay", worldScreen, false) {
|
||||||
if (!worldScreen.viewingCiv.isSpectator())
|
|
||||||
TurnManager(worldScreen.viewingCiv).automateTurn()
|
TurnManager(worldScreen.viewingCiv).automateTurn()
|
||||||
worldScreen.nextTurn()
|
worldScreen.nextTurn()
|
||||||
if (!settings.autoPlay.autoPlayUntilEnd)
|
autoPlay.endTurnMultiturnAutoPlay()
|
||||||
settings.autoPlay.turnsToAutoPlay--
|
}
|
||||||
settings.autoPlay.autoPlayTurnInProgress = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled = nextTurnAction.getText (worldScreen) == "AutoPlay"
|
isEnabled = nextTurnAction.getText (worldScreen) == "AutoPlay"
|
||||||
|| (!worldScreen.hasOpenPopups() && worldScreen.isPlayersTurn
|
|| (!worldScreen.hasOpenPopups() && worldScreen.isPlayersTurn
|
||||||
&& !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning())
|
&& !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning())
|
||||||
if (isEnabled) addTooltip(KeyboardBinding.NextTurn) else addTooltip("")
|
if (isEnabled) addTooltip(KeyboardBinding.NextTurn) else addTooltip("")
|
||||||
|
@ -98,7 +98,7 @@ class NextTurnProgress(
|
|||||||
// On first update the button text is not yet updated. To stabilize geometry, do it now
|
// On first update the button text is not yet updated. To stabilize geometry, do it now
|
||||||
if (progress == 0) nextTurnButton?.apply {
|
if (progress == 0) nextTurnButton?.apply {
|
||||||
disable()
|
disable()
|
||||||
if (UncivGame.Current.settings.autoPlay.isAutoPlaying())
|
if (GUI.getWorldScreenIfActive()?.autoPlay?.isAutoPlaying() == true)
|
||||||
updateButton(NextTurnAction.AutoPlay)
|
updateButton(NextTurnAction.AutoPlay)
|
||||||
else updateButton(NextTurnAction.Working)
|
else updateButton(NextTurnAction.Working)
|
||||||
barWidth = width - removeHorizontalPad -
|
barWidth = width - removeHorizontalPad -
|
||||||
|
73
core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt
Normal file
73
core/src/com/unciv/ui/screens/worldscreen/unit/AutoPlay.kt
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package com.unciv.ui.screens.worldscreen.unit
|
||||||
|
|
||||||
|
import com.unciv.models.metadata.GameSettings
|
||||||
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
import com.unciv.utils.Concurrency
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
|
class AutoPlay(private var autoPlaySettings: GameSettings.GameSettingsAutoPlay) {
|
||||||
|
/**
|
||||||
|
* How many turns we should multiturn AutoPlay for.
|
||||||
|
* In the case that [autoPlaySettings].autoPlayUntilEnd is true, the value should not be decremented after each turn.
|
||||||
|
*/
|
||||||
|
var turnsToAutoPlay: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not we are currently processing the viewing player's turn.
|
||||||
|
* This can be on the main thread or on a different thread.
|
||||||
|
*/
|
||||||
|
var autoPlayTurnInProgress: Boolean = false
|
||||||
|
var autoPlayJob: Job? = null
|
||||||
|
|
||||||
|
fun startMultiturnAutoPlay() {
|
||||||
|
autoPlayTurnInProgress = false
|
||||||
|
turnsToAutoPlay = autoPlaySettings.autoPlayMaxTurns
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the end of the user's turn being AutoPlayed.
|
||||||
|
* Only decrements [turnsToAutoPlay] if [autoPlaySettings].autoPlayUntilEnd is false.
|
||||||
|
*/
|
||||||
|
fun endTurnMultiturnAutoPlay() {
|
||||||
|
if (!autoPlaySettings.autoPlayUntilEnd && turnsToAutoPlay > 0)
|
||||||
|
turnsToAutoPlay--
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops multiturn AutoPlay and sets [autoPlayTurnInProgress] to false
|
||||||
|
*/
|
||||||
|
fun stopAutoPlay() {
|
||||||
|
turnsToAutoPlay = 0
|
||||||
|
autoPlayTurnInProgress = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the provided job on a new thread if there isn't already an AutoPlay thread running.
|
||||||
|
* Will set autoPlayTurnInProgress to true for the duration of the job.
|
||||||
|
*
|
||||||
|
* @param setPlayerTurnAfterEnd keep this as the default (true) if it will still be the viewing player's turn after the job is finished.
|
||||||
|
* Set it to false if the turn will end.
|
||||||
|
* @throws IllegalStateException if an AutoPlay job is currently running as this is called.
|
||||||
|
*/
|
||||||
|
fun runAutoPlayJobInNewThread(jobName: String, worldScreen: WorldScreen, setPlayerTurnAfterEnd: Boolean = true, job: () -> Unit) {
|
||||||
|
if (autoPlayTurnInProgress) throw IllegalStateException("Trying to start an AutoPlay job while a job is currently running")
|
||||||
|
autoPlayTurnInProgress = true
|
||||||
|
worldScreen.isPlayersTurn = false
|
||||||
|
autoPlayJob = Concurrency.runOnNonDaemonThreadPool(jobName) {
|
||||||
|
job()
|
||||||
|
autoPlayTurnInProgress = false
|
||||||
|
if (setPlayerTurnAfterEnd)
|
||||||
|
worldScreen.isPlayersTurn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAutoPlaying(): Boolean = turnsToAutoPlay > 0 || autoPlayTurnInProgress
|
||||||
|
|
||||||
|
fun fullAutoPlayAI(): Boolean = isAutoPlaying() && autoPlaySettings.fullAutoPlayAI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if we should play at least 1 more turn and we are not currenlty processing any AutoPlay
|
||||||
|
*/
|
||||||
|
fun shouldContinueAutoPlaying(): Boolean = !autoPlayTurnInProgress && turnsToAutoPlay > 0
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ object UnitActionsPillage {
|
|||||||
internal fun getPillageActions(unit: MapUnit, tile: Tile): Sequence<UnitAction> {
|
internal fun getPillageActions(unit: MapUnit, tile: Tile): Sequence<UnitAction> {
|
||||||
val pillageAction = getPillageAction(unit, tile)
|
val pillageAction = getPillageAction(unit, tile)
|
||||||
?: return emptySequence()
|
?: return emptySequence()
|
||||||
if (pillageAction.action == null || unit.civ.isAI() || (unit.civ.isHuman() && UncivGame.Current.settings.autoPlay.isAutoPlaying()))
|
if (pillageAction.action == null || unit.civ.isAIOrAutoPlaying())
|
||||||
return sequenceOf(pillageAction)
|
return sequenceOf(pillageAction)
|
||||||
else return sequenceOf(UnitAction(UnitActionType.Pillage, 65f, pillageAction.title) {
|
else return sequenceOf(UnitAction(UnitActionType.Pillage, 65f, pillageAction.title) {
|
||||||
val pillageText = "Are you sure you want to pillage this [${tile.getImprovementToPillageName()!!}]?"
|
val pillageText = "Are you sure you want to pillage this [${tile.getImprovementToPillageName()!!}]?"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user