From b2479028af3d88ee5059c8db4284b86b26f2b679 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 4 Dec 2022 16:09:07 +0900 Subject: [PATCH] adding 'kind flag' to the savegame format so the file can be determined if it contains player or world data --- .../terrarum/debuggerapp/SavegameCracker.kt | 2 +- .../serialise/GameSavingThread.kt | 2 + .../serialise/QuickSaveThread.kt | 3 ++ .../torvald/terrarum/savegame/DiskSkimmer.kt | 14 +++++- src/net/torvald/terrarum/savegame/VDUtil.kt | 4 +- .../torvald/terrarum/savegame/VirtualDisk.kt | 47 +++++++++++++++---- .../savegame/finder/VirtualDiskCracker.kt | 6 +-- 7 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/net/torvald/terrarum/debuggerapp/SavegameCracker.kt b/src/net/torvald/terrarum/debuggerapp/SavegameCracker.kt index 761423761..ce62f345f 100644 --- a/src/net/torvald/terrarum/debuggerapp/SavegameCracker.kt +++ b/src/net/torvald/terrarum/debuggerapp/SavegameCracker.kt @@ -195,7 +195,7 @@ class SavegameCracker( it.entries.toSortedMap().forEach { (i, entry) -> if (i != 0L) println( ccNoun + i.toString(10).padStart(11, ' ') + " " + - ccNoun2 + (diskIDtoReadableFilename(entry.entryID) + cc0).padEnd(40) { if (it == 0) ' ' else '.' } + + ccNoun2 + (diskIDtoReadableFilename(entry.entryID, it.saveKind) + cc0).padEnd(40) { if (it == 0) ' ' else '.' } + ccConst + " " + entry.contents.getSizePure() + " bytes" ) } diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/GameSavingThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/GameSavingThread.kt index 770461bea..16904d516 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/GameSavingThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/GameSavingThread.kt @@ -62,6 +62,7 @@ class WorldSavingThread( override fun save() { disk.saveMode = 2 * isAuto.toInt() // no quick + disk.saveKind = VDSaveKind.WORLD_DATA if (hasThumbnail) { while (!IngameRenderer.fboRGBexportedLatch) { @@ -224,6 +225,7 @@ class PlayerSavingThread( override fun save() { disk.saveMode = 2 * isAuto.toInt() // no quick + disk.saveKind = VDSaveKind.PLAYER_DATA disk.capacity = 0L WriteSavegame.saveProgress = 0f diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt index 716201be6..be6a8e7d0 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt @@ -140,9 +140,12 @@ class QuickSingleplayerWorldSavingThread( } + disk.saveKind = VDSaveKind.WORLD_DATA + skimmer.rewriteDirectories() skimmer.injectDiskCRC(disk.hashCode()) skimmer.setSaveMode(1 + 2 * isAuto.toInt()) + skimmer.setSaveKind(VDSaveKind.WORLD_DATA) printdbg(this, "Game saved with size of ${outFile.length()} bytes") diff --git a/src/net/torvald/terrarum/savegame/DiskSkimmer.kt b/src/net/torvald/terrarum/savegame/DiskSkimmer.kt index c8e93aecf..2b161a5c8 100644 --- a/src/net/torvald/terrarum/savegame/DiskSkimmer.kt +++ b/src/net/torvald/terrarum/savegame/DiskSkimmer.kt @@ -169,10 +169,10 @@ removefile: if (typeFlag > 0) { entryToOffsetTable[entryID] = offset - debugPrintln("[DiskSkimmer] ... successfully read the entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID)})") + debugPrintln("[DiskSkimmer] ... successfully read the entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID, getSaveKind())})") } else { - debugPrintln("[DiskSkimmer] ... discarding entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID)})") + debugPrintln("[DiskSkimmer] ... discarding entry $entryID at offset $offset (name: ${diskIDtoReadableFilename(entryID, getSaveKind())})") } } @@ -343,11 +343,21 @@ removefile: fa.writeByte(bits) } + fun setSaveKind(bits: Int) { + fa.seek(50L) + fa.writeByte(bits) + } + fun getSaveMode(): Int { fa.seek(49L) return fa.read() } + fun getSaveKind(): Int { + fa.seek(50L) + return fa.read() + } + override fun getDiskName(charset: Charset): String { val bytes = ByteArray(268) fa.seek(10L) diff --git a/src/net/torvald/terrarum/savegame/VDUtil.kt b/src/net/torvald/terrarum/savegame/VDUtil.kt index f93c2228a..6e4855364 100644 --- a/src/net/torvald/terrarum/savegame/VDUtil.kt +++ b/src/net/torvald/terrarum/savegame/VDUtil.kt @@ -173,7 +173,7 @@ object VDUtil { val crcMsg = "CRC failed: stored value is ${entryCRC.toHex()}, but calculated value is ${calculatedCRC.toHex()}\n" + - "at file \"${diskIDtoReadableFilename(diskEntry.entryID)}\" (entry ID ${diskEntry.entryID})" + "at file \"${diskIDtoReadableFilename(diskEntry.entryID, vdisk.saveKind)}\" (entry ID ${diskEntry.entryID})" if (calculatedCRC != entryCRC) { @@ -196,7 +196,7 @@ object VDUtil { } } catch (e: ArrayIndexOutOfBoundsException) { - System.err.println("An error occurred while reading a file (entryID: $entryID (${diskIDtoReadableFilename(entryID)}), typeFlag: $entryTypeFlag)") + System.err.println("An error occurred while reading a file (entryID: $entryID (${diskIDtoReadableFilename(entryID, vdisk.saveKind)}), typeFlag: $entryTypeFlag)") System.err.println("Stack trace:") e.printStackTrace() break diff --git a/src/net/torvald/terrarum/savegame/VirtualDisk.kt b/src/net/torvald/terrarum/savegame/VirtualDisk.kt index 130012bf6..8295267a8 100644 --- a/src/net/torvald/terrarum/savegame/VirtualDisk.kt +++ b/src/net/torvald/terrarum/savegame/VirtualDisk.kt @@ -1,6 +1,8 @@ package net.torvald.terrarum.savegame import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.savegame.VDSaveKind.PLAYER_DATA +import net.torvald.terrarum.savegame.VDSaveKind.WORLD_DATA import net.torvald.terrarum.serialise.Common import net.torvald.terrarum.serialise.toUint import java.io.File @@ -66,12 +68,18 @@ Version 254 is a customised version of TEVD tailored to be used as a savegame fo 4. for elems on list: update crc with the elem (crc = calculateCRC(crc, elem)) Int8 Version Int8 0xFE + < BEGIN extraInfoBytes > Int8 Disk properties flag 1 0th bit: readonly Int8 Save type - 0th bit: unset - full save; set - quick save - 1st bit: set - generated by autosave - Int8[14] Extra info bytes + 0th bit: unset - full save; set - quick save + 1st bit: set - generated by autosave + Int8 Kind of the Save file + 0: Undefined (old version of the game?) + 1: Player Data + 2: World Data + Int8[13] Extra info bytes + < END extraInfoBytes > Unit8[236] Rest of the long disk name (268 bytes total) (Header size: 300 bytes) @@ -141,6 +149,9 @@ class VirtualDisk( var saveMode: Int set(value) { extraInfoBytes[1] = value.toByte() } get() = extraInfoBytes[1].toUint() + var saveKind: Int + set(value) { extraInfoBytes[2] = value.toByte() } + get() = extraInfoBytes[2].toUint() override fun getDiskName(charset: Charset) = diskName.toCanonicalString(charset) val root: DiskEntry get() = entries[0]!! @@ -234,6 +245,12 @@ class VirtualDisk( } } +object VDSaveKind { + const val UNDEFINED = 0 + const val PLAYER_DATA = 1 + const val WORLD_DATA = 2 +} + object VDFileID { const val ROOT = 0L const val SAVEGAMEINFO = -1L @@ -245,11 +262,21 @@ object VDFileID { const val BODYPARTGLOW_TO_ENTRY_MAP = -1026L } -fun diskIDtoReadableFilename(id: EntryID): String = when (id) { +fun diskIDtoReadableFilename(id: EntryID, saveKind: Int?): String = when (id) { VDFileID.ROOT -> "root" VDFileID.SAVEGAMEINFO -> "savegameinfo.json" - VDFileID.THUMBNAIL, VDFileID.SPRITEDEF -> "thumbnail.tga.gz (world)/spritedef (player)" - VDFileID.SPRITEDEF_GLOW -> "spritedef-glow (player)" + VDFileID.THUMBNAIL, VDFileID.SPRITEDEF -> + if (saveKind == PLAYER_DATA) + "spritedef" + else if (saveKind == WORLD_DATA) + "thumbnail.tga.gz" + else + "thumbnail.tga.gz (world)/spritedef (player)" + VDFileID.SPRITEDEF_GLOW -> + if (saveKind == PLAYER_DATA) + "spritedef-glow" + else + "file #$id" VDFileID.LOADORDER -> "loadOrder.txt" // -16L -> "blockcodex.json.gz" // -17L -> "itemcodex.json.gz" @@ -259,7 +286,11 @@ fun diskIDtoReadableFilename(id: EntryID): String = when (id) { // -1024L -> "apocryphas.json.gz" VDFileID.BODYPART_TO_ENTRY_MAP -> "bodypart-to-entry.map" VDFileID.BODYPARTGLOW_TO_ENTRY_MAP -> "bodypartglow-to-entry.map" - in 1..65535 -> "bodypart #$id.tga.gz (player)" + in 1..65535 -> + if (saveKind == PLAYER_DATA) + "bodypart #$id.tga.gz" + else + "file #$id" in 1048576..2147483647 -> "actor #$id.json" in 0x0000_0001_0000_0000L..0x0000_FFFF_FFFF_FFFFL -> "World${id.ushr(32)}-L${id.and(0xFF00_0000).ushr(24)}-C${id.and(0xFFFFFF)}.gz" @@ -324,7 +355,7 @@ class DiskEntry( override fun equals(other: Any?) = if (other == null) false else this.hashCode() == other.hashCode() - override fun toString() = "DiskEntry(name: ${diskIDtoReadableFilename(entryID)}, ID: $entryID, parent: $parentEntryID, type: ${contents.getTypeFlag()}, contents size: ${contents.getSizeEntry()}, crc: ${hashCode().toHex()})" + override fun toString() = "DiskEntry(name: ${diskIDtoReadableFilename(entryID, null)}, ID: $entryID, parent: $parentEntryID, type: ${contents.getTypeFlag()}, contents size: ${contents.getSizeEntry()}, crc: ${hashCode().toHex()})" } diff --git a/src/net/torvald/terrarum/savegame/finder/VirtualDiskCracker.kt b/src/net/torvald/terrarum/savegame/finder/VirtualDiskCracker.kt index 9f9a8d789..aecf2c79a 100644 --- a/src/net/torvald/terrarum/savegame/finder/VirtualDiskCracker.kt +++ b/src/net/torvald/terrarum/savegame/finder/VirtualDiskCracker.kt @@ -139,7 +139,7 @@ class VirtualDiskCracker(val sysCharset: Charset = Charsets.UTF_8) : JFrame() { if (vdisk != null) { val entry = currentDirectoryEntries!![rowIndex - 1] return when(columnIndex) { - 0 -> diskIDtoReadableFilename(entry.entryID) + 0 -> diskIDtoReadableFilename(entry.entryID, vdisk?.saveKind) 1 -> Instant.ofEpochSecond(entry.modificationDate). atZone(TimeZone.getDefault().toZoneId()). format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) @@ -623,7 +623,7 @@ class VirtualDiskCracker(val sysCharset: Charset = Charsets.UTF_8) : JFrame() { private fun updateDiskInfo() { val sb = StringBuilder() directoryHierarchy.forEach { - sb.append(diskIDtoReadableFilename(it)) + sb.append(diskIDtoReadableFilename(it, vdisk?.saveKind)) sb.append('/') } sb.dropLast(1) @@ -647,7 +647,7 @@ Write protected: ${disk.isReadOnly.toEnglish()}""" private fun getFileInfoText(file: DiskEntry): String { - return """Name: ${diskIDtoReadableFilename(file.entryID)} + return """Name: ${diskIDtoReadableFilename(file.entryID, vdisk?.saveKind)} Size: ${file.getEffectiveSize()} Type: ${DiskEntry.getTypeString(file.contents)} CRC: ${file.hashCode().toHex()}