mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
still working on the new savegame scheme
main game works fine, saving/loading will not be possible
This commit is contained in:
@@ -17,6 +17,7 @@ import java.io.InputStream
|
||||
import java.io.Reader
|
||||
import java.io.StringReader
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
import java.util.zip.GZIPInputStream
|
||||
import java.util.zip.GZIPOutputStream
|
||||
|
||||
@@ -172,6 +173,16 @@ object Common {
|
||||
return hashMap
|
||||
}
|
||||
})
|
||||
// UUID
|
||||
jsoner.setSerializer(UUID::class.java, object : Json.Serializer<UUID> {
|
||||
override fun write(json: Json, obj: UUID, knownType: Class<*>?) {
|
||||
json.writeValue(obj.toString())
|
||||
}
|
||||
|
||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): UUID {
|
||||
return UUID.fromString(jsonData.asString())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private data class LayerInfo(val h: String, val b: String, val x: Int, val y: Int)
|
||||
|
||||
@@ -29,6 +29,11 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
private val actorProgressMultiplier = 1f
|
||||
|
||||
override fun run() {
|
||||
callback()
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
disk.saveMode = 2 * isAuto.toInt() // no quick
|
||||
|
||||
if (hasThumbnail) {
|
||||
@@ -81,9 +86,9 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
// Commented out; nothing to write
|
||||
|
||||
// Write ItemCodex//
|
||||
val itemCodexContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(ItemCodex).toByteArray(Common.CHARSET))))
|
||||
val items = DiskEntry(-17, 0, creation_t, time_t, itemCodexContent)
|
||||
addFile(disk, items)
|
||||
// val itemCodexContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(ItemCodex).toByteArray(Common.CHARSET))))
|
||||
// val items = DiskEntry(-17, 0, creation_t, time_t, itemCodexContent)
|
||||
// addFile(disk, items)
|
||||
// Gotta save dynamicIDs
|
||||
|
||||
// Write WireCodex//
|
||||
@@ -104,15 +109,15 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
// addFile(disk, factions)
|
||||
|
||||
// Write Apocryphas//
|
||||
val apocryphasContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(Apocryphas).toByteArray(Common.CHARSET))))
|
||||
val apocryphas = DiskEntry(-1024, 0, creation_t, time_t, apocryphasContent)
|
||||
addFile(disk, apocryphas)
|
||||
// val apocryphasContent = EntryFile(Common.zip(ByteArray64.fromByteArray(Common.jsoner.toJson(Apocryphas).toByteArray(Common.CHARSET))))
|
||||
// val apocryphas = DiskEntry(-1024, 0, creation_t, time_t, apocryphasContent)
|
||||
// addFile(disk, apocryphas)
|
||||
|
||||
// Write World //
|
||||
val worldNum = ingame.world.worldIndex
|
||||
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
addFile(disk, world)
|
||||
// val worldNum = ingame.world.worldIndex
|
||||
// val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
// val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
// addFile(disk, world)
|
||||
|
||||
WriteSavegame.saveProgress += 1f
|
||||
|
||||
@@ -125,7 +130,7 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
|
||||
Echo("Writing chunks... ${(cw*ch*layer) + chunkNumber + 1}/${cw*ch*layers.size}")
|
||||
|
||||
val chunkBytes = WriteWorld.encodeChunk(layers[layer]!!, cx, cy)
|
||||
val entryID = worldNum.toLong().shl(32) or layer.toLong().shl(24) or chunkNumber
|
||||
val entryID = 0x1_0000_0000L or layer.toLong().shl(24) or chunkNumber
|
||||
|
||||
val entryContent = EntryFile(chunkBytes)
|
||||
val entry = DiskEntry(entryID, 0, creation_t, time_t, entryContent)
|
||||
|
||||
@@ -34,6 +34,11 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
|
||||
|
||||
override fun run() {
|
||||
callback()
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
val skimmer = DiskSkimmer(file, Common.CHARSET)
|
||||
|
||||
if (hasThumbnail) {
|
||||
@@ -82,7 +87,7 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
// Write World //
|
||||
val worldNum = ingame.world.worldIndex
|
||||
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
|
||||
val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||
val world = DiskEntry(-1-1-1-1-1-1-1, 0, creation_t, time_t, worldMeta)
|
||||
addFile(disk, world); skimmer.appendEntryOnly(world)
|
||||
|
||||
WriteSavegame.saveProgress += 1f
|
||||
@@ -101,7 +106,7 @@ class QuickSaveThread(val disk: VirtualDisk, val file: File, val ingame: Terraru
|
||||
// println("Chunk xy from number $chunkNumber -> (${chunkXY.x}, ${chunkXY.y})")
|
||||
|
||||
val chunkBytes = WriteWorld.encodeChunk(layer, chunkXY.x, chunkXY.y)
|
||||
val entryID = worldNum.toLong().shl(32) or layerNum.toLong().shl(24) or chunkNumber.toLong()
|
||||
val entryID = 0x1_0000_0000L or layerNum.toLong().shl(24) or chunkNumber.toLong()
|
||||
|
||||
val entryContent = EntryFile(chunkBytes)
|
||||
val entry = DiskEntry(entryID, 0, creation_t, time_t, entryContent)
|
||||
|
||||
@@ -3,6 +3,8 @@ package net.torvald.terrarum.serialise
|
||||
import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.spriteassembler.ADProperties
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.NoSuchActorWithIDException
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
@@ -49,17 +51,53 @@ object WriteActor {
|
||||
* Created by minjaesong on 2021-10-07.
|
||||
*/
|
||||
object WritePlayer {
|
||||
operator fun invoke(player: IngamePlayer, disk: VirtualDisk) {
|
||||
|
||||
/**
|
||||
* Will happily overwrite existing entry
|
||||
*/
|
||||
private fun addFile(disk: VirtualDisk, file: DiskEntry) {
|
||||
disk.entries[file.entryID] = file
|
||||
file.parentEntryID = 0
|
||||
val dir = VDUtil.getAsDirectory(disk, 0)
|
||||
if (!dir.contains(file.entryID)) dir.add(file.entryID)
|
||||
}
|
||||
|
||||
operator fun invoke(player: IngamePlayer, playerDisk: VirtualDisk) {
|
||||
val time_t = App.getTIME_T()
|
||||
val actorJson = WriteActor.encodeToByteArray64(player)
|
||||
val adl = player.animDesc?.getRawADL() // NULLABLE!
|
||||
val adl = player.animDesc!!.getRawADL()
|
||||
val adlGlow = player.animDescGlow?.getRawADL() // NULLABLE!
|
||||
}
|
||||
|
||||
operator fun invoke(player: IngamePlayer, skimmer: DiskSkimmer) {
|
||||
val jsonContents = EntryFile(actorJson)
|
||||
val jsonCreationDate = playerDisk.getEntry(-1)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, jsonCreationDate, time_t, jsonContents))
|
||||
|
||||
val adlContents = EntryFile(ByteArray64.fromByteArray(adl.toByteArray(Common.CHARSET)))
|
||||
val adlCreationDate = playerDisk.getEntry(-2)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, adlCreationDate, time_t, adlContents))
|
||||
|
||||
if (adlGlow != null) {
|
||||
val adlGlowContents = EntryFile(ByteArray64.fromByteArray(adlGlow.toByteArray(Common.CHARSET)))
|
||||
val adlGlowCreationDate = playerDisk.getEntry(-3)?.creationDate ?: time_t
|
||||
addFile(playerDisk, DiskEntry(-1L, 0L, adlGlowCreationDate, time_t, adlGlowContents))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Player-specific [ReadActor].
|
||||
*
|
||||
* Created by minjaesong on 2021-10-07.
|
||||
*/
|
||||
object ReadPlayer {
|
||||
|
||||
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): IngamePlayer =
|
||||
ReadActor(disk, dataStream) as IngamePlayer
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Actor's JSON representation is expected to have "class" property on the root object, such as:
|
||||
@@ -71,8 +109,8 @@ object WritePlayer {
|
||||
*/
|
||||
object ReadActor {
|
||||
|
||||
operator fun invoke(disk: SimpleFileSystem, worldDataStream: Reader): Actor =
|
||||
fillInDetails(disk, Common.jsoner.fromJson(null, worldDataStream))
|
||||
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): Actor =
|
||||
fillInDetails(disk, Common.jsoner.fromJson(null, dataStream))
|
||||
|
||||
fun readActorBare(worldDataStream: Reader): Actor =
|
||||
Common.jsoner.fromJson(null, worldDataStream)
|
||||
@@ -89,19 +127,30 @@ object ReadActor {
|
||||
|
||||
actor.sprite = SpriteAnimation(actor)
|
||||
if (animFileGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
||||
actor.reassembleSprite(
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
val bodypartsFile = disk.getFile(-1025)
|
||||
|
||||
if (bodypartsFile != null)
|
||||
actor.reassembleSprite(
|
||||
disk,
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
else
|
||||
actor.reassembleSprite(
|
||||
actor.sprite!!,
|
||||
ADProperties(ByteArray64Reader(animFile!!.bytes, Common.CHARSET)),
|
||||
actor.spriteGlow,
|
||||
if (animFileGlow == null) null else ADProperties(ByteArray64Reader(animFileGlow.bytes, Common.CHARSET))
|
||||
)
|
||||
}
|
||||
|
||||
return actor
|
||||
}
|
||||
|
||||
fun readActorAndAddToWorld(ingame: TerrarumIngame, disk: SimpleFileSystem, worldDataStream: Reader): Actor {
|
||||
val actor = invoke(disk, worldDataStream)
|
||||
fun readActorAndAddToWorld(ingame: TerrarumIngame, disk: SimpleFileSystem, dataStream: Reader): Actor {
|
||||
val actor = invoke(disk, dataStream)
|
||||
|
||||
// replace existing player
|
||||
val oldPlayerID = ingame.actorNowPlaying?.referenceID
|
||||
|
||||
@@ -24,12 +24,11 @@ object WriteMeta {
|
||||
randseed1 = RoguelikeRandomiser.RNG.state1,
|
||||
weatseed0 = WeatherMixer.RNG.state0,
|
||||
weatseed1 = WeatherMixer.RNG.state1,
|
||||
playerid = ingame.actorGamer.referenceID,
|
||||
creation_t = ingame.creationTime,
|
||||
lastplay_t = time_t,
|
||||
playtime_t = ingame.totalPlayTime + currentPlayTime_t,
|
||||
loadorder = ModMgr.loadOrder.toTypedArray(),
|
||||
worlds = ingame.gameworldIndices.toTypedArray()
|
||||
//worlds = ingame.gameworldIndices.toTypedArray()
|
||||
)
|
||||
|
||||
return Common.jsoner.toJson(meta)
|
||||
@@ -52,8 +51,8 @@ object WriteMeta {
|
||||
val creation_t: Long = 0,
|
||||
val lastplay_t: Long = 0,
|
||||
val playtime_t: Long = 0,
|
||||
val loadorder: Array<String> = arrayOf(), // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
val worlds: Array<Int> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
val loadorder: Array<String> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
//val worlds: Array<Int> = arrayOf() // do not use list; Could not instantiate instance of class: java.util.Collections$SingletonList
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
||||
@@ -56,6 +56,10 @@ object WriteSavegame {
|
||||
|
||||
|
||||
fun immediate(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
savingStatus = 0
|
||||
|
||||
Echo("Immediate save fired")
|
||||
@@ -68,6 +72,10 @@ object WriteSavegame {
|
||||
}
|
||||
|
||||
fun quick(disk: VirtualDisk, file: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
||||
return
|
||||
|
||||
// TODO //
|
||||
|
||||
savingStatus = 0
|
||||
|
||||
Echo("Quicksave queued")
|
||||
@@ -111,6 +119,8 @@ object LoadSavegame {
|
||||
fun getFileReader(disk: VirtualDisk, id: Long): Reader = ByteArray64Reader(getFileBytes(disk, id), Common.CHARSET)
|
||||
|
||||
operator fun invoke(disk: VirtualDisk) {
|
||||
TODO()
|
||||
|
||||
val newIngame = TerrarumIngame(App.batch)
|
||||
|
||||
val meta = ReadMeta(disk)
|
||||
@@ -118,7 +128,7 @@ object LoadSavegame {
|
||||
// NOTE: do NOT set ingame.actorNowPlaying as one read directly from the disk;
|
||||
// you'll inevitably read the player actor twice, and they're separate instances of the player!
|
||||
val currentWorld = (ReadActor.readActorBare(getFileReader(disk, Terrarum.PLAYER_REF_ID.toLong())) as IngamePlayer).worldCurrentlyPlaying
|
||||
val world = ReadWorld(getFileReader(disk, currentWorld.toLong()))
|
||||
val world = ReadWorld(getFileReader(disk, -1-1-1-1-1-1))
|
||||
|
||||
// set lateinit vars on the gameworld FIRST
|
||||
world.layerTerrain = BlockLayer(world.width, world.height)
|
||||
@@ -153,7 +163,6 @@ object LoadSavegame {
|
||||
|
||||
|
||||
// load all the world blocklayer chunks
|
||||
val worldnum = world.worldIndex.toLong()
|
||||
val cw = LandUtil.CHUNK_W
|
||||
val ch = LandUtil.CHUNK_H
|
||||
val chunkCount = world.width * world.height / (cw * ch)
|
||||
@@ -162,7 +171,7 @@ object LoadSavegame {
|
||||
for (layer in worldLayer.indices) {
|
||||
loadscreen.addMessage("${Lang["MENU_IO_LOADING"]} ${chunk*worldLayer.size+layer+1}/${chunkCount*2}")
|
||||
|
||||
val chunkFile = VDUtil.getAsNormalFile(disk, worldnum.shl(32) or layer.toLong().shl(24) or chunk)
|
||||
val chunkFile = VDUtil.getAsNormalFile(disk, 0x1_0000_0000L or layer.toLong().shl(24) or chunk)
|
||||
val chunkXY = LandUtil.chunkNumToChunkXY(world, chunk.toInt())
|
||||
|
||||
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer[layer]!!, chunkXY.x, chunkXY.y)
|
||||
|
||||
Reference in New Issue
Block a user