From 2b505620022a47e82b934fa601e6b7992698e98d Mon Sep 17 00:00:00 2001 From: minjaesong Date: Mon, 26 Jun 2023 23:10:52 +0900 Subject: [PATCH] save juggling for autosaves --- src/net/torvald/terrarum/IngameInstance.kt | 32 ++++++++++++++++--- .../terrarum/modulebasegame/TerrarumIngame.kt | 12 +++---- .../serialise/QuickSaveThread.kt | 2 ++ .../modulebasegame/ui/UIInventoryEscMenu.kt | 4 +-- .../ui/UIPerformanceControlPanel.kt | 2 +- .../torvald/terrarum/savegame/VirtualDisk.kt | 2 +- 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/net/torvald/terrarum/IngameInstance.kt b/src/net/torvald/terrarum/IngameInstance.kt index 69bb4a403..1f36f2060 100644 --- a/src/net/torvald/terrarum/IngameInstance.kt +++ b/src/net/torvald/terrarum/IngameInstance.kt @@ -410,14 +410,14 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo /** * Copies most recent `save` to `save.1`, leaving `save` for overwriting, previous `save.1` will be copied to `save.2` */ - fun makeSavegameBackupCopy(file: File, isAuto: Boolean) { + fun makeSavegameBackupCopy(file: File) { if (!file.exists()) { return } - val file1 = File("${file.absolutePath}.${if (isAuto) "a" else "1"}") - val file2 = File("${file.absolutePath}.${if (isAuto) "b" else "1"}") - val file3 = File("${file.absolutePath}.${if (isAuto) "c" else "1"}") + val file1 = File("${file.absolutePath}.1") + val file2 = File("${file.absolutePath}.2") + val file3 = File("${file.absolutePath}.3") try { // do not overwrite clean .2 with dirty .1 @@ -442,6 +442,30 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo } + fun makeSavegameBackupCopyAuto(file0: File): File { + val file1 = File("${file0.absolutePath}.a") + val file2 = File("${file0.absolutePath}.b") + val file3 = File("${file0.absolutePath}.c") + + try { + // do not overwrite clean .2 with dirty .1 + val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r } + val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r } + if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) file1.copyTo(file3, true) + } catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {} + try { + if (file2.exists() && !file3.exists()) + file2.copyTo(file3, true) + if (file1.exists() && !file2.exists()) + file1.copyTo(file2, true) + + file0.copyTo(file1, true) + } catch (e: IOException) {} + + return file1 + } + + // simple euclidean norm, squared private val actorDistanceCalculator = DistanceCalculator { t: ActorWithBody, p: PointND -> diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 7856becf0..79a0439fb 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -421,10 +421,10 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) { uiAutosaveNotifier.setAsOpen() val saveTime_t = App.getTIME_T() WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.PLAYER, playerDisk, getPlayerSaveFiledesc(playerSavefileName), this, true, autosaveOnErrorAction) { - makeSavegameBackupCopy(getPlayerSaveFiledesc(playerSavefileName), true) + makeSavegameBackupCopy(getPlayerSaveFiledesc(playerSavefileName)) WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.WORLD, worldDisk, getWorldSaveFiledesc(worldSavefileName), this, true, autosaveOnErrorAction) { - makeSavegameBackupCopy(getWorldSaveFiledesc(worldSavefileName), true) // don't put it on the postInit() or render(); must be called using callback + makeSavegameBackupCopy(getWorldSaveFiledesc(worldSavefileName)) // don't put it on the postInit() or render(); must be called using callback uiAutosaveNotifier.setAsClose() } } @@ -1113,13 +1113,13 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) { uiAutosaveNotifier.setAsOpen() val saveTime_t = App.getTIME_T() - val playerSavefile = getPlayerSaveFiledesc(INGAME.playerSavefileName) - val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName) + val playerSavefile0 = getPlayerSaveFiledesc(INGAME.playerSavefileName) + val worldSavefile0 = getWorldSaveFiledesc(INGAME.worldSavefileName) - INGAME.makeSavegameBackupCopy(playerSavefile, true) + val playerSavefile = INGAME.makeSavegameBackupCopyAuto(playerSavefile0) WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) { - INGAME.makeSavegameBackupCopy(worldSavefile, true) + val worldSavefile = INGAME.makeSavegameBackupCopyAuto(worldSavefile0) WriteSavegame(saveTime_t, WriteSavegame.SaveMode.QUICK_WORLD, INGAME.worldDisk, worldSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) { // callback: // rebuild the disk skimmers diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt index 874117bae..384088566 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt @@ -46,6 +46,8 @@ class QuickSingleplayerWorldSavingThread( override fun save() { + printdbg(this, "Quicksaveworld has thumbnail: $hasThumbnail") + val skimmer = DiskSkimmer(outFile) if (hasThumbnail) { diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt index f73aef983..af3626f68 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIInventoryEscMenu.kt @@ -110,10 +110,10 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() { val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName) - INGAME.makeSavegameBackupCopy(playerSavefile, false) + INGAME.makeSavegameBackupCopy(playerSavefile) WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, false, onError) { - INGAME.makeSavegameBackupCopy(worldSavefile, false) + INGAME.makeSavegameBackupCopy(worldSavefile) WriteSavegame(saveTime_t, WriteSavegame.SaveMode.WORLD, INGAME.worldDisk, worldSavefile, INGAME as TerrarumIngame, false, onError) { // callback: // rebuild the disk skimmers diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt index d9c4def48..70fc7aec5 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIPerformanceControlPanel.kt @@ -29,7 +29,7 @@ class UIPerformanceControlPanel(remoCon: UIRemoCon?) : UICanvas() { private val options = arrayOf( arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY"] }, "h1"), - arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,5,120,5,60000"), + arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,1,120,1,60000"), arrayOf("notificationshowuptime", { Lang["MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION"] + " (${Lang["CONTEXT_TIME_SECOND_PLURAL"]})" }, "spinnerimul,2,10,1,1000"), arrayOf("", { Lang["MENU_LABEL_JVM_DNT"] }, "h1"), arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX"] + " (GB)" }, "spinner,2,32,1"), diff --git a/src/net/torvald/terrarum/savegame/VirtualDisk.kt b/src/net/torvald/terrarum/savegame/VirtualDisk.kt index de3771bb0..77e975527 100644 --- a/src/net/torvald/terrarum/savegame/VirtualDisk.kt +++ b/src/net/torvald/terrarum/savegame/VirtualDisk.kt @@ -72,7 +72,7 @@ Version 254 is a customised version of TEVD tailored to be used as a savegame fo Int8 Disk properties flag 1 0th bit: readonly Int8 Save type (0b 0000 00ab) - b: unset - full save; set - quick save + b: unset - full save; set - quicksave (only applicable to worlds -- quicksave just means the disk is in dirty state) a: set - generated by autosave Int8 Kind of the Save file 0: Undefined (or very old version of the game)