diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index f41c26c7a5..4757864d5e 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -3,6 +3,7 @@ package com.unciv.logic import com.unciv.Constants import com.unciv.UncivGame import com.unciv.UncivGame.Version +import com.unciv.json.json import com.unciv.logic.BackwardCompatibility.convertEncampmentData import com.unciv.logic.BackwardCompatibility.convertFortify import com.unciv.logic.BackwardCompatibility.guaranteeUnitPromotions @@ -35,9 +36,11 @@ import com.unciv.models.ruleset.nation.Difficulty import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags +import com.unciv.ui.screens.savescreens.Gzip import com.unciv.ui.screens.worldscreen.status.NextTurnProgress import com.unciv.utils.DebugUtils import com.unciv.utils.debug +import java.security.MessageDigest import java.util.UUID @@ -100,6 +103,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion var currentPlayer = "" var currentTurnStartTime = 0L var gameId = UUID.randomUUID().toString() // random string + var checksum = "" var victoryData:VictoryData? = null @@ -272,6 +276,16 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion return year.toInt() } + fun calculateChecksum():String { + val oldChecksum = checksum + checksum = "" // Checksum calculation cannot include old checksum, obvs + val bytes = MessageDigest + .getInstance("SHA-1") + .digest(json().toJson(this).toByteArray()) + checksum = oldChecksum + return Gzip.encode(bytes) + } + //endregion //region State changing functions diff --git a/core/src/com/unciv/logic/civilization/managers/PolicyManager.kt b/core/src/com/unciv/logic/civilization/managers/PolicyManager.kt index c297ad7ff7..d3921672c8 100644 --- a/core/src/com/unciv/logic/civilization/managers/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/managers/PolicyManager.kt @@ -211,6 +211,8 @@ class PolicyManager : IsPartOfGameInfoSerialization { if (unique.conditionals.any {it.type == UniqueType.TriggerUponAdoptingPolicyOrBelief && it.params[0] == policy.name}) UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo, triggerNotificationText = triggerNotificationText) + civInfo.cache.updateCivResources() + // This ALSO has the side-effect of updating the CivInfo statForNextTurn so we don't need to call it explicitly for (cityInfo in civInfo.cities) cityInfo.cityStats.update() diff --git a/core/src/com/unciv/logic/files/UncivFiles.kt b/core/src/com/unciv/logic/files/UncivFiles.kt index 7e9e95fefa..db20695e9f 100644 --- a/core/src/com/unciv/logic/files/UncivFiles.kt +++ b/core/src/com/unciv/logic/files/UncivFiles.kt @@ -18,8 +18,8 @@ import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.doMigrations import com.unciv.models.metadata.isMigrationNecessary import com.unciv.ui.screens.savescreens.Gzip -import com.unciv.utils.Log import com.unciv.utils.Concurrency +import com.unciv.utils.Log import com.unciv.utils.debug import kotlinx.coroutines.Job import java.io.File @@ -371,8 +371,10 @@ class UncivFiles( } /** Returns gzipped serialization of [game], optionally gzipped ([forceZip] overrides [saveZipped]) */ - fun gameInfoToString(game: GameInfo, forceZip: Boolean? = null): String { + fun gameInfoToString(game: GameInfo, forceZip: Boolean? = null, updateChecksum:Boolean=true): String { game.version = GameInfo.CURRENT_COMPATIBILITY_VERSION + + if (updateChecksum) game.checksum = game.calculateChecksum() val plainJson = json().toJson(game) return if (forceZip ?: saveZipped) Gzip.zip(plainJson) else plainJson } diff --git a/core/src/com/unciv/logic/multiplayer/storage/OnlineMultiplayerServer.kt b/core/src/com/unciv/logic/multiplayer/storage/OnlineMultiplayerServer.kt index 05d38938b5..d5f3925e01 100644 --- a/core/src/com/unciv/logic/multiplayer/storage/OnlineMultiplayerServer.kt +++ b/core/src/com/unciv/logic/multiplayer/storage/OnlineMultiplayerServer.kt @@ -102,7 +102,7 @@ class OnlineMultiplayerServer( * @throws MultiplayerAuthException if the authentication failed */ suspend fun tryUploadGame(gameInfo: GameInfo, withPreview: Boolean) { - val zippedGameInfo = UncivFiles.gameInfoToString(gameInfo, forceZip = true) + val zippedGameInfo = UncivFiles.gameInfoToString(gameInfo, forceZip = true, updateChecksum = true) fileStorage().saveFileData(gameInfo.gameId, zippedGameInfo) // We upload the preview after the game because otherwise the following race condition will happen: diff --git a/core/src/com/unciv/ui/screens/savescreens/Gzip.kt b/core/src/com/unciv/ui/screens/savescreens/Gzip.kt index 42bc79be7c..22cfeb0d0c 100644 --- a/core/src/com/unciv/ui/screens/savescreens/Gzip.kt +++ b/core/src/com/unciv/ui/screens/savescreens/Gzip.kt @@ -10,8 +10,8 @@ import java.util.zip.GZIPOutputStream object Gzip { - fun zip(data:String):String = encoder(compress(data)) - fun unzip(data:String):String = decompress(decoder(data)) + fun zip(data:String):String = encode(compress(data)) + fun unzip(data:String):String = decompress(decode(data)) private fun compress(data: String): ByteArray { val bos = ByteArrayOutputStream(data.length) @@ -40,11 +40,11 @@ object Gzip { } - private fun encoder(bytes:ByteArray): String{ + fun encode(bytes:ByteArray): String{ return String(Base64Coder.encode(bytes)) } - private fun decoder(base64Str: String): ByteArray{ + private fun decode(base64Str: String): ByteArray{ return Base64Coder.decode(base64Str) } }