saving performed on separate thread so that save-in-progress UI would work

This commit is contained in:
minjaesong
2021-09-14 14:28:38 +09:00
parent b084f9e5a9
commit ce19a85a93
6 changed files with 189 additions and 103 deletions

View File

@@ -0,0 +1,145 @@
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.modulebasegame.IngameRenderer
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.tvda.*
import java.io.File
import java.util.zip.GZIPOutputStream
/**
* Created by minjaesong on 2021-09-14.
*/
class GameSavingThread(val disk: VirtualDisk, val outFile: File, val ingame: TerrarumIngame) : 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)
}
override fun run() {
while (!IngameRenderer.fboRGBexportedLatch) {
Thread.sleep(1L)
}
val tgaout = ByteArray64GrowableOutputStream()
val gzout = GZIPOutputStream(tgaout)
Echo("Writing metadata...")
val creation_t = ingame.creationTime
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)
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
IngameRenderer.fboRGBexport.dispose()
val thumbContent = EntryFile(tgaout.toByteArray64())
val thumb = DiskEntry(-2, 0, creation_t, time_t, thumbContent)
addFile(disk, thumb)
// Write BlockCodex//
// val blockCodexContent = EntryFile(zip(ByteArray64.fromByteArray(Common.jsoner.toJson(BlockCodex).toByteArray(Common.CHARSET))))
// val blocks = DiskEntry(-16, 0, "blocks".toByteArray(Common.CHARSET), creation_t, time_t, blockCodexContent)
// addFile(disk, blocks)
// 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)
// Gotta save dynamicIDs
// Write WireCodex//
// val wireCodexContent = EntryFile(zip(ByteArray64.fromByteArray(Common.jsoner.toJson(WireCodex).toByteArray(Common.CHARSET))))
// val wires = DiskEntry(-18, 0, "wires".toByteArray(Common.CHARSET), creation_t, time_t, wireCodexContent)
// addFile(disk, wires)
// Commented out; nothing to write
// Write MaterialCodex//
// val materialCodexContent = EntryFile(zip(ByteArray64.fromByteArray(Common.jsoner.toJson(MaterialCodex).toByteArray(Common.CHARSET))))
// val materials = DiskEntry(-19, 0, "materials".toByteArray(Common.CHARSET), creation_t, time_t, materialCodexContent)
// addFile(disk, materials)
// Commented out; nothing to write
// Write FactionCodex//
// val factionCodexContent = EntryFile(zip(ByteArray64.fromByteArray(Common.jsoner.toJson(FactionCodex).toByteArray(Common.CHARSET))))
// val factions = DiskEntry(-20, 0, "factions".toByteArray(Common.CHARSET), creation_t, time_t, factionCodexContent)
// 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)
// 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 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.saveProgressMax = (cw * ch * layers.size).toFloat()
for (layer in layers.indices) {
for (cx in 0 until cw) {
for (cy in 0 until ch) {
val chunkNumber = (cx * ch + cy).toLong()
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 entryContent = EntryFile(chunkBytes)
val entry = DiskEntry(entryID, 0, creation_t, time_t, entryContent)
// "W1L0-92,15"
addFile(disk, entry)
WriteSavegame.saveProgress += 1
}
}
}
Echo("Writing actors...")
// Write Actors //
listOf(ingame.actorContainerActive, ingame.actorContainerInactive).forEach { actors ->
actors.forEach {
if (WriteWorld.actorAcceptable(it)) {
val actorContent = EntryFile(WriteActor.encodeToByteArray64(it))
val actor = DiskEntry(it.referenceID.toLong(), 0, creation_t, time_t, actorContent)
addFile(disk, actor)
}
}
}
disk.capacity = 0
VDUtil.dumpToRealMachine(disk, outFile)
Echo ("${ccW}Game saved with size of $ccG${outFile.length()}$ccW bytes")
IngameRenderer.fboRGBexportedLatch = false
WriteSavegame.savingStatus = 255
}
}