mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
adding 'kind flag' to the savegame format so the file can be determined if it contains player or world data
This commit is contained in:
@@ -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"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()})"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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()}
|
||||
|
||||
Reference in New Issue
Block a user