From 3037ce4141a65a8898a155bcc5ad75f6df6790ee Mon Sep 17 00:00:00 2001 From: GGGuenni Date: Sun, 24 Jan 2021 15:12:44 +0100 Subject: [PATCH] multiple game support for TurnChecker (#3540) * TurnChecker now checks every multiplayer game Not just the currently open game * Adding game saving to turn checker so multiplayerScreen stays up to date * remove unused imports * removing unused functions --- .../unciv/app/MultiplayerTurnCheckWorker.kt | 54 +++++++++++++++++-- core/src/com/unciv/logic/GameSaver.kt | 18 +++++-- .../unciv/ui/worldscreen/mainmenu/DropBox.kt | 6 +-- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/android/src/com/unciv/app/MultiplayerTurnCheckWorker.kt b/android/src/com/unciv/app/MultiplayerTurnCheckWorker.kt index 58aa0cc83d..5c26e5a1e0 100644 --- a/android/src/com/unciv/app/MultiplayerTurnCheckWorker.kt +++ b/android/src/com/unciv/app/MultiplayerTurnCheckWorker.kt @@ -13,6 +13,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.work.* import com.badlogic.gdx.backends.android.AndroidApplication import com.unciv.logic.GameInfo +import com.unciv.logic.GameSaver import com.unciv.models.metadata.GameSettings import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer import java.io.PrintWriter @@ -41,6 +42,7 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame private const val FAIL_COUNT = "FAIL_COUNT" private const val GAME_ID = "GAME_ID" + private const val GAME_NAMES = "GAME_NAMES" private const val USER_ID = "USER_ID" private const val CONFIGURED_DELAY = "CONFIGURED_DELAY" private const val PERSISTENT_NOTIFICATION_ENABLED = "PERSISTENT_NOTIFICATION_ENABLED" @@ -160,12 +162,29 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame } } - fun startTurnChecker(applicationContext: Context, gameInfo: GameInfo, settings: GameSettings) { - if (gameInfo.currentPlayerCiv.playerId == settings.userId) { + fun startTurnChecker(applicationContext: Context, currentGameInfo: GameInfo, settings: GameSettings) { + val gameFiles = GameSaver.getSaves(true) + val gameIds = Array(gameFiles.count()) {""} + val gameNames = Array(gameFiles.count()) {""} + + var count = 0 + for (gameFile in gameFiles) { + try { + gameIds[count] = GameSaver.getGameIdFromFile(gameFile) + gameNames[count] = gameFile.name() + count++ + } catch (ex: Exception) { + //only getGameIdFromFile can throw an exception + //nothing will be added to the arrays if it fails + //just skip one file + } + } + + if (currentGameInfo.currentPlayerCiv.playerId == settings.userId) { // May be useful to remind a player that he forgot to complete his turn. notifyUserAboutTurn(applicationContext) } else { - val inputData = workDataOf(Pair(FAIL_COUNT, 0), Pair(GAME_ID, gameInfo.gameId), + val inputData = workDataOf(Pair(FAIL_COUNT, 0), Pair(GAME_ID, gameIds), Pair(GAME_NAMES, gameNames), Pair(USER_ID, settings.userId), Pair(CONFIGURED_DELAY, settings.multiplayerTurnCheckerDelayInMinutes), Pair(PERSISTENT_NOTIFICATION_ENABLED, settings.multiplayerTurnCheckerPersistentNotificationEnabled)) @@ -205,9 +224,33 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame override fun doWork(): Result { val showPersistNotific = inputData.getBoolean(PERSISTENT_NOTIFICATION_ENABLED, true) val configuredDelay = inputData.getInt(CONFIGURED_DELAY, 5) + try { - val currentTurnPlayer = OnlineMultiplayer().tryDownloadCurrentTurnCiv(inputData.getString(GAME_ID)!!) - if (currentTurnPlayer.playerId == inputData.getString(USER_ID)!!) { + val gameIds = inputData.getStringArray(GAME_ID)!! + val gameNames = inputData.getStringArray(GAME_NAMES)!! + var arrayIndex = 0 + // We only want to notify the user or update persisted notification once but still want + // to download all games to update the files hence this bool + var foundGame = false + + for (gameId in gameIds){ + //gameId could be an empty string if startTurnChecker fails to load all files + if (gameId.isEmpty()) + continue + + val game = OnlineMultiplayer().tryDownloadGameUninitialized(gameId) + val currentTurnPlayer = game.getCivilization(game.currentPlayer) + + //Save game so MultiplayerScreen gets updated + GameSaver.saveGame(game, gameNames[arrayIndex], true) + + if (currentTurnPlayer.playerId == inputData.getString(USER_ID)!!) { + foundGame = true + } + arrayIndex++ + } + + if (foundGame){ notifyUserAboutTurn(applicationContext) with(NotificationManagerCompat.from(applicationContext)) { cancel(NOTIFICATION_ID_SERVICE) @@ -218,6 +261,7 @@ class MultiplayerTurnCheckWorker(appContext: Context, workerParams: WorkerParame val inputDataFailReset = Data.Builder().putAll(inputData).putInt(FAIL_COUNT, 0).build() enqueue(applicationContext, configuredDelay, inputDataFailReset) } + } catch (ex: Exception) { val failCount = inputData.getInt(FAIL_COUNT, 0) if (failCount > 3) { diff --git a/core/src/com/unciv/logic/GameSaver.kt b/core/src/com/unciv/logic/GameSaver.kt index a1bc4197b6..5eb300c3a9 100644 --- a/core/src/com/unciv/logic/GameSaver.kt +++ b/core/src/com/unciv/logic/GameSaver.kt @@ -77,6 +77,15 @@ object GameSaver { return game } + /** + * WARNING! transitive GameInfo data not initialized + * The returned GameInfo can not be used for most circumstances because its not initialized! + * It is therefore stateless and save to call for Multiplayer Turn Notifier, unlike gameInfoFromString(). + */ + fun gameInfoFromStringWithoutTransients(gameData: String): GameInfo { + return json().fromJson(GameInfo::class.java, gameData) + } + fun deleteSave(GameName: String, multiplayer: Boolean = false){ getSave(GameName, multiplayer).delete() } @@ -155,13 +164,12 @@ object GameSaver { } /** - * Returns current turn's player from GameInfo JSON-String for multiplayer. + * Returns the gameId from a GameInfo which was saved as JSON for multiplayer * Does not initialize transitive GameInfo data. - * It is therefore stateless and save to call for Multiplayer Turn Notifier, unlike gameInfoFromString(). + * It is therefore stateless and save to call for Multiplayer Turn Notifier. */ - fun currentTurnCivFromString(gameData: String): CivilizationInfo { - val game = json().fromJson(GameInfo::class.java, gameData) - return game.getCivilization(game.currentPlayer) + fun getGameIdFromFile(gameFile: FileHandle): String { + return json().fromJson(GameInfo::class.java, gameFile).gameId } } diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt index c42ef1d288..377677f753 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt @@ -127,13 +127,13 @@ class OnlineMultiplayer { } /** - * Returns current turn's player. + * WARNING! * Does not initialize transitive GameInfo data. * It is therefore stateless and save to call for Multiplayer Turn Notifier, unlike tryDownloadGame(). */ - fun tryDownloadCurrentTurnCiv(gameId: String): CivilizationInfo { + fun tryDownloadGameUninitialized(gameId: String): GameInfo { val zippedGameInfo = DropBox.downloadFileAsString(getGameLocation(gameId)) - return GameSaver.currentTurnCivFromString(Gzip.unzip(zippedGameInfo)) + return GameSaver.gameInfoFromStringWithoutTransients(Gzip.unzip(zippedGameInfo)) } }