new player save format writing

This commit is contained in:
minjaesong
2021-10-08 14:25:59 +09:00
parent 3f9b41fd29
commit aec6fea49e
21 changed files with 280 additions and 116 deletions

View File

@@ -43,6 +43,9 @@ object Common {
// install custom (de)serialiser
init {
jsoner.ignoreUnknownFields = true
// BigInteger
jsoner.setSerializer(BigInteger::class.java, object : Json.Serializer<BigInteger> {
override fun write(json: Json, obj: BigInteger?, knownType: Class<*>?) {

View File

@@ -3,36 +3,31 @@ package net.torvald.terrarum.serialise
import net.torvald.gdx.graphics.PixmapIO2
import net.torvald.terrarum.*
import net.torvald.terrarum.console.Echo
import net.torvald.terrarum.gameworld.PhysicalStatus
import net.torvald.terrarum.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.tvda.*
import java.io.File
import java.util.zip.GZIPOutputStream
/**
* 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)
}
/**
* Created by minjaesong on 2021-09-14.
*/
class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: TerrarumIngame, val hasThumbnail: Boolean, val isAuto: Boolean, val callback: () -> Unit) : Runnable {
/**
* 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)
}
private val chunkProgressMultiplier = 1f
private val actorProgressMultiplier = 1f
class WorldSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: TerrarumIngame, val hasThumbnail: Boolean, val isAuto: Boolean, val callback: () -> Unit) : Runnable {
override fun run() {
callback()
return
// TODO //
disk.saveMode = 2 * isAuto.toInt() // no quick
@@ -42,15 +37,14 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
}
}
val playersList: List<IngamePlayer> = listOf(ingame.actorContainerActive, ingame.actorContainerInactive).flatMap{ it.filter { it is IngamePlayer } } as List<IngamePlayer>
val actorsList = listOf(ingame.actorContainerActive, ingame.actorContainerInactive).flatMap { it.filter { WriteWorld.actorAcceptable(it) } }
val layers = intArrayOf(0,1).map { ingame.world.getLayer(it) }
val cw = ingame.world.width / LandUtil.CHUNK_W
val ch = ingame.world.height / LandUtil.CHUNK_H
WriteSavegame.saveProgress = 0f
WriteSavegame.saveProgressMax = 2f +
(cw * ch * layers.size) * chunkProgressMultiplier +
actorsList.size * actorProgressMultiplier
WriteSavegame.saveProgressMax = 2f + (cw * ch * layers.size) + actorsList.size
val tgaout = ByteArray64GrowableOutputStream()
@@ -62,11 +56,6 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
val time_t = App.getTIME_T()
// Write Meta //
val metaContent = EntryFile(WriteMeta.encodeToByteArray64(ingame, time_t))
val meta = DiskEntry(-1, 0, creation_t, time_t, metaContent)
addFile(disk, meta)
if (hasThumbnail) {
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
IngameRenderer.fboRGBexport.dispose()
@@ -114,10 +103,13 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
// 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)
// record all player's last position
playersList.forEach {
ingame.world.playersLastStatus[it.uuid] = PhysicalStatus(it)
}
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t))
val world = DiskEntry(-1L, 0, creation_t, time_t, worldMeta)
addFile(disk, world)
WriteSavegame.saveProgress += 1f
@@ -137,7 +129,7 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
// "W1L0-92,15"
addFile(disk, entry)
WriteSavegame.saveProgress += chunkProgressMultiplier
WriteSavegame.saveProgress += 1
}
}
}
@@ -151,7 +143,7 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
val actor = DiskEntry(it.referenceID.toLong(), 0, creation_t, time_t, actorContent)
addFile(disk, actor)
WriteSavegame.saveProgress += actorProgressMultiplier
WriteSavegame.saveProgress += 1
}
@@ -174,4 +166,23 @@ class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: Ter
callback()
}
}
}
/**
* This function called means the "Avatar" was not externally created and thus has no sprite-bodypart-name-to-entry-number-map
*
* Created by minjaesong on 2021-10-08
*/
class PlayerSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: TerrarumIngame, val hasThumbnail: Boolean, val isAuto: Boolean, val callback: () -> Unit) : Runnable {
override fun run() {
disk.saveMode = 2 * isAuto.toInt() // no quick
disk.capacity = 0L
Echo("Writing The Player...")
WritePlayer(ingame.actorGamer, disk)
VDUtil.dumpToRealMachine(disk, outFile)
callback()
}
}

View File

@@ -46,7 +46,7 @@ object WriteActor {
}
/**
* Player-specific [WriteActor].
* Player-specific [WriteActor]. Will write JSON and Animation Description Languages
*
* Created by minjaesong on 2021-10-07.
*/
@@ -74,12 +74,12 @@ object WritePlayer {
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))
addFile(playerDisk, DiskEntry(-2L, 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))
addFile(playerDisk, DiskEntry(-3L, 0L, adlGlowCreationDate, time_t, adlGlowContents))
}

View File

@@ -23,11 +23,21 @@ import java.io.Reader
*/
object WriteSavegame {
enum class SaveMode {
META, PLAYER, WORLD, SHARED
}
@Volatile var savingStatus = -1 // -1: not started, 0: saving in progress, 255: saving finished
@Volatile var saveProgress = 0f
@Volatile var saveProgressMax = 1f
operator fun invoke(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
private fun getSaveThread(mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, hasThumbnail: Boolean, isAuto: Boolean, callback: () -> Unit = {}) = when (mode) {
SaveMode.WORLD -> WorldSavingThread(disk, outFile, ingame, hasThumbnail, isAuto, callback)
SaveMode.PLAYER -> PlayerSavingThread(disk, outFile, ingame, hasThumbnail, isAuto, callback)
else -> throw IllegalArgumentException("$mode")
}
operator fun invoke(mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
savingStatus = 0
Echo("Save queued")
@@ -47,7 +57,7 @@ object WriteSavegame {
}
IngameRenderer.screencapRequested = true
val savingThread = Thread(GameSavingThread(disk, outFile, ingame, true, isAuto, callback), "TerrarumBasegameGameSaveThread")
val savingThread = Thread(getSaveThread(mode, disk, outFile, ingame, true, isAuto, callback), "TerrarumBasegameGameSaveThread")
savingThread.start()
// it is caller's job to keep the game paused or keep a "save in progress" ui up
@@ -55,16 +65,13 @@ object WriteSavegame {
}
fun immediate(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
return
// TODO //
fun immediate(mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, hasThumbnail: Boolean, isAuto: Boolean, callback: () -> Unit = {}) {
savingStatus = 0
Echo("Immediate save fired")
val savingThread = Thread(GameSavingThread(disk, outFile, ingame, false, isAuto, callback), "TerrarumBasegameGameSaveThread")
val savingThread = Thread(getSaveThread(mode, disk, outFile, ingame, false, isAuto, callback), "TerrarumBasegameGameSaveThread")
savingThread.start()
// it is caller's job to keep the game paused or keep a "save in progress" ui up
@@ -134,7 +141,6 @@ object LoadSavegame {
world.layerTerrain = BlockLayer(world.width, world.height)
world.layerWall = BlockLayer(world.width, world.height)
newIngame.savegameArchive = disk
newIngame.creationTime = meta.creation_t
newIngame.lastPlayTime = meta.lastplay_t
newIngame.totalPlayTime = meta.playtime_t

View File

@@ -9,6 +9,7 @@ import net.torvald.terrarum.gameworld.BlockLayer
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.GameWorldTitleScreen
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.tvda.ByteArray64
import net.torvald.terrarum.tvda.ByteArray64Writer
@@ -22,7 +23,8 @@ object WriteWorld {
fun actorAcceptable(actor: Actor): Boolean {
return actor.referenceID !in ReferencingRanges.ACTORS_WIRES &&
actor.referenceID !in ReferencingRanges.ACTORS_WIRES_HELPER &&
actor != (CommonResourcePool.get("blockmarking_actor") as BlockMarkerActor)
actor != (CommonResourcePool.get("blockmarking_actor") as BlockMarkerActor) &&
actor !is IngamePlayer // IngamePlayers must not be saved with the world
}
private fun preWrite(ingame: TerrarumIngame, time_t: Long): GameWorld {