diff --git a/src/net/torvald/terrarum/App.java b/src/net/torvald/terrarum/App.java index b54f165d5..b918a4db0 100644 --- a/src/net/torvald/terrarum/App.java +++ b/src/net/torvald/terrarum/App.java @@ -64,8 +64,11 @@ public class App implements ApplicationListener { public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG; public static final String getVERSION_STRING() { + + var snap = TerrarumAppConfiguration.INSTANCE.getVERSION_SNAPSHOT(); + return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) + - (VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG); + (VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG) + (snap == null ? "" : (" (" + snap + ")")); } /** diff --git a/src/net/torvald/terrarum/TerrarumAppConfiguration.kt b/src/net/torvald/terrarum/TerrarumAppConfiguration.kt index e04b246fc..2ddae38ec 100644 --- a/src/net/torvald/terrarum/TerrarumAppConfiguration.kt +++ b/src/net/torvald/terrarum/TerrarumAppConfiguration.kt @@ -1,6 +1,8 @@ package net.torvald.terrarum import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.serialise.toUint +import java.util.* /** * You directly modify the source code to tune the engine to suit your needs. @@ -68,6 +70,8 @@ basegame // Commit counts up to the Release 0.3.2: 2732 // Commit counts up to the Release 0.3.3: ???? + val VERSION_SNAPSHOT = if (App.IS_DEVELOPMENT_BUILD) Snapshot(0) else null + const val VERSION_TAG: String = "" ////////////////////////////////////////////////////////// @@ -77,4 +81,35 @@ basegame const val TILE_SIZE = 16 const val TILE_SIZEF = TILE_SIZE.toFloat() const val TILE_SIZED = TILE_SIZE.toDouble() +} + +data class Snapshot(var revision: Int) { + private var today = Calendar.getInstance(); + private var year = today.get(Calendar.YEAR) - 2000 + private var week = today.get(Calendar.WEEK_OF_YEAR) + + private var string = "" + private var bytes = byteArrayOf() + + private fun update() { + string = "${year}w${week}${Char(0x61 + revision)}" + bytes = byteArrayOf( + revision.and(4).shl(7).or(year.and(127)).toByte(), + week.shl(2).or(revision.and(3)).toByte() + ) + } + + init { + update() + } + + override fun toString() = string + fun toBytes() = bytes + + constructor(b: ByteArray) : this(0) { + year = b[0].toUint() and 127 + week = b[1].toUint() ushr 2 + revision = (b[0].toUint() ushr 7 shl 2) or b[1].toUint().and(3) + update() + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/PlayerSavingThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/PlayerSavingThread.kt index 57e9c57b1..14aff08e8 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/PlayerSavingThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/PlayerSavingThread.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.serialise import net.torvald.gdx.graphics.PixmapIO2 import net.torvald.terrarum.App +import net.torvald.terrarum.TerrarumAppConfiguration import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.savegame.* @@ -41,6 +42,7 @@ class PlayerSavingThread( disk.saveKind = VDSaveKind.PLAYER_DATA disk.saveOrigin = disk.saveOrigin and 15 // remove flag "imported" if applicable disk.capacity = 0L + disk.snapshot = TerrarumAppConfiguration.VERSION_SNAPSHOT WriteSavegame.saveProgress = 0f diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt index 455c9447e..1fbae8a24 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/QuickSaveThread.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.serialise import net.torvald.gdx.graphics.PixmapIO2 import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.TerrarumAppConfiguration import net.torvald.terrarum.modulebasegame.IngameRenderer import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer @@ -150,6 +151,7 @@ class QuickSingleplayerWorldSavingThread( skimmer.injectDiskCRC(disk.hashCode()) skimmer.setSaveMode(1 + 2 * isAuto.toInt()) skimmer.setSaveKind(VDSaveKind.WORLD_DATA) + skimmer.setSaveSnapshotVersion(TerrarumAppConfiguration.VERSION_SNAPSHOT) skimmer.setSaveOrigin(skimmer.getSaveOrigin() and 15) // remove flag "imported" if applicable skimmer.setLastModifiedTime(time_t) skimmer.setCreationTime(creation_t) diff --git a/src/net/torvald/terrarum/modulebasegame/serialise/WorldSavingThread.kt b/src/net/torvald/terrarum/modulebasegame/serialise/WorldSavingThread.kt index 090aa711c..13e086fda 100644 --- a/src/net/torvald/terrarum/modulebasegame/serialise/WorldSavingThread.kt +++ b/src/net/torvald/terrarum/modulebasegame/serialise/WorldSavingThread.kt @@ -42,6 +42,7 @@ class WorldSavingThread( disk.saveMode = 2 * isAuto.toInt() // no quick disk.saveKind = VDSaveKind.WORLD_DATA disk.saveOrigin = disk.saveOrigin and 15 // remove flag "imported" if applicable + disk.snapshot = TerrarumAppConfiguration.VERSION_SNAPSHOT // wait for screencap var emergencyStopCnt = 0 diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt b/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt index b34f13ce5..08fd2f978 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UILoadDemoSavefiles.kt @@ -526,14 +526,18 @@ class UIItemPlayerCells( loadable.rebuild() loadable.getFile(SAVEGAMEINFO)?.bytes?.let { var lastPlayTime0 = 0L + var genver = "" JsonFetcher.readFromJsonString(ByteArray64Reader(it, Common.CHARSET)).forEachSiblings { name, value -> if (name == "worldCurrentlyPlaying") worldUUID = UUID.fromString(value.asString()) if (name == "totalPlayTime") totalPlayTime = parseDuration(value.asLong()) if (name == "lastPlayTime") lastPlayTime0 = value.asLong() - if (name == "genver") versionString = value.asLong().let { "${it.ushr(48)}.${it.ushr(24).and(0xFFFFFF)}.${it.and(0xFFFFFF)}" } + if (name == "genver") genver = value.asLong().let { "${it.ushr(48)}.${it.ushr(24).and(0xFFFFFF)}.${it.and(0xFFFFFF)}" } } + val snap = loadable.getSaveSnapshotVersion() + versionString = genver + (if (snap != null) "-$snap" else "") + App.savegamePlayersName[playerUUID]?.let { if (it.isNotBlank()) playerName = it else "(name)" } App.savegameWorldsName[worldUUID]?.let { if (it.isNotBlank()) worldName = it } lastPlayTime = Instant.ofEpochSecond(lastPlayTime0) @@ -749,6 +753,7 @@ class UIItemWorldCells( private val metaFile: EntryFile? private val saveName: String private val saveMode: Int + private val snapshot: String private val isQuick: Boolean private val isAuto: Boolean private var saveDamaged: Boolean = false @@ -760,6 +765,7 @@ class UIItemWorldCells( saveName = skimmer.getDiskName(Common.CHARSET) saveMode = skimmer.getSaveMode() + snapshot = skimmer.getSaveSnapshotVersion()?.toString() ?: "" isQuick = (saveMode % 2 == 1) isAuto = (saveMode.ushr(1) != 0) diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UILoadManage.kt b/src/net/torvald/terrarum/modulebasegame/ui/UILoadManage.kt index 2a7ae7d3b..4786ef8bf 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UILoadManage.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UILoadManage.kt @@ -447,12 +447,16 @@ class UILoadManage(val full: UILoadSavegame) : UICanvas() { if (!this.initialised) this.rebuild() this.getFile(SAVEGAMEINFO)!!.bytes.let { var lastPlayTime = 0L - var versionString = "" + var genver = "" val isAuto = (this.getSaveMode() and 0b10 != 0) JsonFetcher.readFromJsonString(ByteArray64Reader(it, Common.CHARSET)).forEachSiblings { name, value -> if (name == "lastPlayTime") lastPlayTime = value.asLong() - if (name == "genver") versionString = value.asLong().let { "${it.ushr(48)}.${it.ushr(24).and(0xFFFFFF)}.${it.and(0xFFFFFF)}" } + if (name == "genver") genver = value.asLong().let { "${it.ushr(48)}.${it.ushr(24).and(0xFFFFFF)}.${it.and(0xFFFFFF)}" } } + val snap = this.getSaveSnapshotVersion()?.toString() + +// val versionString = genver + (if (snap != null) "-$snap" else "") + val versionString = if (snap != null) "$snap" else genver return SavegameMeta( lastPlayTime, diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UINewCharacter.kt b/src/net/torvald/terrarum/modulebasegame/ui/UINewCharacter.kt index 840aad85a..6ab18a835 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UINewCharacter.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UINewCharacter.kt @@ -80,6 +80,7 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() { disk.saveMode = 2 // auto, no quick disk.capacity = 0L disk.saveOrigin = VDSaveOrigin.INGAME + disk.snapshot = TerrarumAppConfiguration.VERSION_SNAPSHOT WritePlayer(player, disk, null, time_t) VDUtil.dumpToRealMachine(disk, outFile) diff --git a/src/net/torvald/terrarum/savegame/DiskSkimmer.kt b/src/net/torvald/terrarum/savegame/DiskSkimmer.kt index 57ec8fd0a..0020e71e3 100644 --- a/src/net/torvald/terrarum/savegame/DiskSkimmer.kt +++ b/src/net/torvald/terrarum/savegame/DiskSkimmer.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.savegame import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.Snapshot import net.torvald.terrarum.serialise.toUint import net.torvald.terrarum.serialise.toUlong import java.io.* @@ -389,6 +390,16 @@ removefile: fa.close() } + fun setSaveSnapshotVersion(snapshot: Snapshot?) { + val fa = RandomAccessFile(diskFile, "rwd") + fa.seek(51L) + if (snapshot == null) + fa.write(byteArrayOf(0, 0)) + else + fa.write(snapshot.toBytes()) + fa.close() + } + /** * @return Save type (0b 0000 00ab) * b: unset - full save; set - quicksave (only applicable to worlds -- quicksave just means the disk is in dirty state) @@ -418,6 +429,17 @@ removefile: return fa.read().also { fa.close() } } + fun getSaveSnapshotVersion(): Snapshot? { + val fa = RandomAccessFile(diskFile, "rwd") + fa.seek(52L) + + val b1 = fa.read().toByte() + val b2 = fa.read().toByte().also { fa.close() } + + return if (b1 == b2 && b1 == 0.toByte()) null + else Snapshot(byteArrayOf(b1, b2)) + } + override fun getDiskName(charset: Charset): String { diff --git a/src/net/torvald/terrarum/savegame/VirtualDisk.kt b/src/net/torvald/terrarum/savegame/VirtualDisk.kt index ddd9e383b..5234bab4e 100644 --- a/src/net/torvald/terrarum/savegame/VirtualDisk.kt +++ b/src/net/torvald/terrarum/savegame/VirtualDisk.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.savegame import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.Snapshot import net.torvald.terrarum.savegame.VDSaveKind.PLAYER_DATA import net.torvald.terrarum.savegame.VDSaveKind.WORLD_DATA import net.torvald.terrarum.serialise.Common @@ -79,7 +80,15 @@ Version 254 is a customised version of TEVD tailored to be used as a savegame fo Int8 Savefile Origin Flags (lower nybble: persistent, upper nybble: can be removed if conditions are met) 0: Created in-game 16: Imported (will be removed once the file is loaded by the player and saved in-game) - Int8[12] Extra info bytes reserved for future usage + Int16 Snapshot Number + 0b A_yyyyyyy wwwwww_aa + where: + y: Current Year - 2000 (2023 -> 23) + w: ISO Week Number (1-53) + Aaa: Alphabet (a->000, b->001, ... e->100, f->101, ..., h->111) + e.g. 23w40f is encoded as 1_0010111 101000_01 + Int8[10] Extra info bytes reserved for future usage + -- END extraInfoBytes -- UInt8[236] Rest of the long disk name (268 bytes total) @@ -156,6 +165,25 @@ class VirtualDisk( var saveOrigin: Int set(value) { extraInfoBytes[3] = value.toByte() } get() = extraInfoBytes[3].toUint() + var snapshot: Snapshot? + set(value) { + if (value == null) { + extraInfoBytes[4] = 0 + extraInfoBytes[5] = 0 + } + else { + value.toBytes().forEachIndexed { index, byte -> + extraInfoBytes[4+index] = byte + } + } + } + get() { + return if (extraInfoBytes[4] == extraInfoBytes[5] && extraInfoBytes[4] == 0.toByte()) null + else { + Snapshot(extraInfoBytes.sliceArray(4..5)) + } + } + override fun getDiskName(charset: Charset) = diskName.toCanonicalString(charset) val root: DiskEntry get() = entries[0]!! diff --git a/src/net/torvald/unsafe/UnsafePtr.kt b/src/net/torvald/unsafe/UnsafePtr.kt index a3e127287..44858f755 100644 --- a/src/net/torvald/unsafe/UnsafePtr.kt +++ b/src/net/torvald/unsafe/UnsafePtr.kt @@ -113,8 +113,8 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) { // appear (e.g. getting garbage values when it fucking shouldn't) // using ifs instead of assertions: inactive assert statements still slows down the app - if (destroyed) { throw DanglingPointerException("The pointer is already destroyed ($this)") } - if (index !in 0 until size) { throw AddressOverflowException("Index: $index; alloc size: $size") } +// if (destroyed) { throw DanglingPointerException("The pointer is already destroyed ($this)") } +// if (index !in 0 until size) { throw AddressOverflowException("Index: $index; alloc size: $size") } } operator fun get(index: Long): Byte {