mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-11 02:54:04 +09:00
188 lines
7.6 KiB
Kotlin
188 lines
7.6 KiB
Kotlin
package net.torvald.terrarum.serialise
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.graphics.Pixmap
|
|
import net.torvald.terrarum.*
|
|
import net.torvald.terrarum.App.printdbg
|
|
import net.torvald.terrarum.console.Echo
|
|
import net.torvald.terrarum.gameworld.BlockLayer
|
|
import net.torvald.terrarum.langpack.Lang
|
|
import net.torvald.terrarum.modulebasegame.ChunkLoadingLoadScreen
|
|
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.serialise.Common.getUnzipInputStream
|
|
import net.torvald.terrarum.tvda.*
|
|
import java.io.File
|
|
import java.io.Reader
|
|
|
|
/**
|
|
* It's your responsibility to create a new VirtualDisk if your save is new, and create a backup for modifying existing save.
|
|
*
|
|
* Created by minjaesong on 2021-09-03.
|
|
*/
|
|
object WriteSavegame {
|
|
|
|
@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 = {}) {
|
|
savingStatus = 0
|
|
|
|
Echo("Save queued")
|
|
|
|
IngameRenderer.fboRGBexportCallback = {
|
|
Echo("Generating thumbnail...")
|
|
|
|
val w = 960
|
|
val h = 640
|
|
val p = Pixmap.createFromFrameBuffer((it.width - w).ushr(1), (it.height - h).ushr(1), w, h)
|
|
IngameRenderer.fboRGBexport = p
|
|
//PixmapIO2._writeTGA(gzout, p, true, true)
|
|
//p.dispose()
|
|
IngameRenderer.fboRGBexportedLatch = true
|
|
|
|
Echo("Done thumbnail generation")
|
|
}
|
|
IngameRenderer.fboRGBexportRequested = true
|
|
|
|
val savingThread = Thread(GameSavingThread(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
|
|
// use field 'savingStatus' to know when the saving is done
|
|
}
|
|
|
|
|
|
fun immediate(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
|
savingStatus = 0
|
|
|
|
Echo("Immediate save fired")
|
|
|
|
val savingThread = Thread(GameSavingThread(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
|
|
// use field 'savingStatus' to know when the saving is done
|
|
}
|
|
|
|
fun quick(disk: VirtualDisk, file: File, ingame: TerrarumIngame, isAuto: Boolean, callback: () -> Unit = {}) {
|
|
savingStatus = 0
|
|
|
|
Echo("Quicksave queued")
|
|
|
|
IngameRenderer.fboRGBexportCallback = {
|
|
Echo("Generating thumbnail...")
|
|
|
|
val w = 960
|
|
val h = 640
|
|
val p = Pixmap.createFromFrameBuffer((it.width - w).ushr(1), (it.height - h).ushr(1), w, h)
|
|
IngameRenderer.fboRGBexport = p
|
|
//PixmapIO2._writeTGA(gzout, p, true, true)
|
|
//p.dispose()
|
|
IngameRenderer.fboRGBexportedLatch = true
|
|
|
|
Echo("Done thumbnail generation")
|
|
}
|
|
IngameRenderer.fboRGBexportRequested = true
|
|
|
|
val savingThread = Thread(QuickSaveThread(disk, file, 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
|
|
// use field 'savingStatus' to know when the saving is done
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Load and setup the game for the first load.
|
|
*
|
|
* To load additional actors/worlds, use ReadActor/ReadWorld.
|
|
*
|
|
* Created by minjaesong on 2021-09-03.
|
|
*/
|
|
object LoadSavegame {
|
|
|
|
fun getFileBytes(disk: VirtualDisk, id: Long): ByteArray64 = VDUtil.getAsNormalFile(disk, id).getContent()
|
|
fun getFileReader(disk: VirtualDisk, id: Long): Reader = ByteArray64Reader(getFileBytes(disk, id), Common.CHARSET)
|
|
|
|
operator fun invoke(disk: VirtualDisk) {
|
|
val newIngame = TerrarumIngame(App.batch)
|
|
|
|
val meta = ReadMeta(disk)
|
|
|
|
// 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()))
|
|
|
|
// set lateinit vars on the gameworld FIRST
|
|
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
|
|
newIngame.world = world // must be set before the loadscreen, otherwise the loadscreen will try to read from the NullWorld which is already destroyed
|
|
|
|
|
|
|
|
val loadJob = { it: LoadScreenBase ->
|
|
val loadscreen = it as ChunkLoadingLoadScreen
|
|
|
|
loadscreen.addMessage(Lang["MENU_IO_LOADING"])
|
|
|
|
val actors = world.actors.distinct()//.map { ReadActor(getFileReader(disk, it.toLong())) }
|
|
// val block = Common.jsoner.fromJson(BlockCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -16)))
|
|
val item = Common.jsoner.fromJson(ItemCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -17)))
|
|
// val wire = Common.jsoner.fromJson(WireCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -18)))
|
|
// val material = Common.jsoner.fromJson(MaterialCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -19)))
|
|
// val faction = Common.jsoner.fromJson(FactionCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -20)))
|
|
val apocryphas = Common.jsoner.fromJson(Apocryphas.javaClass, getUnzipInputStream(getFileBytes(disk, -1024)))
|
|
|
|
|
|
|
|
val worldParam = TerrarumIngame.Codices(disk, meta, item, apocryphas, actors)
|
|
newIngame.gameLoadInfoPayload = worldParam
|
|
newIngame.gameLoadMode = TerrarumIngame.GameLoadMode.LOAD_FROM
|
|
|
|
|
|
// 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)
|
|
val worldLayer = arrayOf(world.getLayer(0), world.getLayer(1))
|
|
for (chunk in 0L until (world.width * world.height) / (cw * ch)) {
|
|
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 chunkXY = LandUtil.chunkNumToChunkXY(world, chunk.toInt())
|
|
|
|
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer[layer]!!, chunkXY.x, chunkXY.y)
|
|
}
|
|
}
|
|
|
|
|
|
// ModMgr.reloadModules()
|
|
|
|
|
|
Echo("${ccW}Savegame loaded from $ccY${disk.getDiskNameString(Common.CHARSET)}")
|
|
printdbg(this, "Savegame loaded from ${disk.getDiskNameString(Common.CHARSET)}")
|
|
}
|
|
|
|
val loadScreen = ChunkLoadingLoadScreen(newIngame, world.width, world.height, loadJob)
|
|
Terrarum.setCurrentIngameInstance(newIngame)
|
|
App.setLoadScreen(loadScreen)
|
|
|
|
|
|
}
|
|
|
|
} |