mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-16 05:24:06 +09:00
game load wip
This commit is contained in:
@@ -1,103 +1,5 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameitem.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.*
|
||||
import net.torvald.util.SortedArrayList
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
internal class RNGPool() {
|
||||
private val RNG = HQRNG()
|
||||
private val used = SortedArrayList<Int>()
|
||||
|
||||
init {
|
||||
for (i in 0 until 32767) {
|
||||
used.add(i)
|
||||
}
|
||||
}
|
||||
|
||||
fun next(): Int {
|
||||
var n = RNG.nextLong().ushr(32).toInt()
|
||||
while (used.contains(n)) {
|
||||
n = RNG.nextLong().ushr(32).toInt()
|
||||
}
|
||||
used.add(n)
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-10-03.
|
||||
*/
|
||||
object SavegameWriter {
|
||||
|
||||
// TODO create temporary files (worldinfo), create JSON files on RAM, pack those into TEVd as per Savegame container.txt
|
||||
|
||||
private val rngPool = RNGPool()
|
||||
|
||||
private val charset = Charset.forName("UTF-8")
|
||||
|
||||
private lateinit var playerName: String
|
||||
|
||||
operator fun invoke(pnameOverride: String? = null): Boolean {
|
||||
playerName = pnameOverride ?: "${Terrarum.ingame!!.actorGamer.actorValue[AVKey.NAME]}"
|
||||
if (playerName.isEmpty()) playerName = "Test subject ${Math.random().times(0x7FFFFFFF).roundToInt()}"
|
||||
|
||||
try {
|
||||
val diskImage = generateNewDiskImage()
|
||||
val outFile = File("${AppLoader.defaultSaveDir}/$playerName")
|
||||
VDUtil.dumpToRealMachine(diskImage, outFile)
|
||||
|
||||
return true
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
fun generateNewDiskImage(): VirtualDisk {
|
||||
val creationDate = System.currentTimeMillis() / 1000L
|
||||
val ingame = Terrarum.ingame!!
|
||||
val gameworld = ingame.world
|
||||
val player = ingame.actorGamer
|
||||
val disk = VDUtil.createNewDisk(0x7FFFFFFFFFFFFFFFL, "Tesv-$playerName", charset)
|
||||
val ROOT = disk.root.entryID
|
||||
|
||||
// serialise current world (stage)
|
||||
|
||||
|
||||
|
||||
// items
|
||||
/*ItemCodex.dynamicItemDescription.forEach { dynamicID, item ->
|
||||
VDUtil.registerFile(disk, DiskEntry(
|
||||
rngPool.next(), ROOT,
|
||||
dynamicID.toByteArray(charset),
|
||||
creationDate, creationDate,
|
||||
EntryFile(serialiseItem(item))
|
||||
))
|
||||
}*/
|
||||
|
||||
System.gc()
|
||||
|
||||
return disk
|
||||
}
|
||||
|
||||
fun modifyExistingSave(savefile: File): VirtualDisk {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.toLittle() = byteArrayOf(
|
||||
this.and(0xFF).toByte(),
|
||||
this.ushr(8).and(0xFF).toByte(),
|
||||
@@ -171,4 +73,4 @@ fun ByteArray.toLittleInt48() =
|
||||
fun ByteArray.toLittleFloat() = java.lang.Float.intBitsToFloat(this.toLittleInt())
|
||||
|
||||
fun Byte.toUlong() = java.lang.Byte.toUnsignedLong(this)
|
||||
fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this)
|
||||
fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this)
|
||||
@@ -10,6 +10,7 @@ import net.torvald.terrarum.gameworld.WorldTime
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64GrowableOutputStream
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64InputStream
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64Reader
|
||||
import net.torvald.terrarum.tail
|
||||
import net.torvald.terrarum.utils.*
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
@@ -47,7 +48,6 @@ object Common {
|
||||
init {
|
||||
// BigInteger
|
||||
jsoner.setSerializer(BigInteger::class.java, object : Json.Serializer<BigInteger> {
|
||||
|
||||
override fun write(json: Json, obj: BigInteger?, knownType: Class<*>?) {
|
||||
json.writeValue(obj?.toString())
|
||||
}
|
||||
@@ -56,9 +56,18 @@ object Common {
|
||||
return BigInteger(jsonData.asString())
|
||||
}
|
||||
})
|
||||
// ZipCodedStr
|
||||
jsoner.setSerializer(ZipCodedStr::class.java, object : Json.Serializer<ZipCodedStr> {
|
||||
override fun write(json: Json, obj: ZipCodedStr, knownType: Class<*>?) {
|
||||
json.writeValue(zipStrAndEnascii(obj.doc))
|
||||
}
|
||||
|
||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): ZipCodedStr {
|
||||
return ZipCodedStr(unasciiAndUnzipStr(jsonData.asString()))
|
||||
}
|
||||
})
|
||||
// BlockLayer
|
||||
jsoner.setSerializer(BlockLayer::class.java, object : Json.Serializer<BlockLayer> {
|
||||
|
||||
override fun write(json: Json, obj: BlockLayer, knownType: Class<*>?) {
|
||||
digester.reset()
|
||||
obj.bytesIterator().forEachRemaining { digester.update(it) }
|
||||
@@ -66,9 +75,6 @@ object Common {
|
||||
|
||||
val layer = LayerInfo(hash, blockLayerToStr(obj), obj.width, obj.height)
|
||||
|
||||
// printdbg(this, "pre: ${(0L..1023L).map { obj.ptr[it].tostr() }.joinToString(" ")}")
|
||||
|
||||
|
||||
json.writeValue(layer)
|
||||
}
|
||||
|
||||
@@ -270,4 +276,16 @@ object Common {
|
||||
|
||||
return unzipdBytes
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [s] a String
|
||||
* @return UTF-8 encoded [s] which are GZip'd then Ascii85-encoded
|
||||
*/
|
||||
fun zipStrAndEnascii(s: String): String {
|
||||
return Common.bytesToZipdStr(s.toByteArray(Common.CHARSET).iterator())
|
||||
}
|
||||
|
||||
fun unasciiAndUnzipStr(s: String): String {
|
||||
return ByteArray64Reader(strToBytes(StringReader(s)), CHARSET).readText()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.terrarum.NoSuchActorWithIDException
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import java.io.InputStream
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Actor's JSON representation is expected to have "class" property on the root object, such as:
|
||||
* ```
|
||||
* "class":"net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer"
|
||||
* ```
|
||||
*
|
||||
* Created by minjaesong on 2021-08-27.
|
||||
*/
|
||||
class ReadActor(val ingame: TerrarumIngame) {
|
||||
|
||||
open fun invoke(worldDataStream: InputStream) {
|
||||
postRead(Common.jsoner.fromJson(null, worldDataStream))
|
||||
}
|
||||
|
||||
open fun invoke(worldDataStream: Reader) {
|
||||
postRead(Common.jsoner.fromJson(null, worldDataStream))
|
||||
}
|
||||
|
||||
private fun postRead(actor: Actor) {
|
||||
// filling in Transients
|
||||
actor.actorValue.actor = actor
|
||||
|
||||
if (actor is Pocketed)
|
||||
actor.inventory.actor = actor
|
||||
|
||||
if (actor is ActorWithBody) {
|
||||
actor.sprite = SpriteAnimation(actor)
|
||||
|
||||
if (actor is HasAssembledSprite) {
|
||||
if (actor.animDescPathGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
||||
actor.reassembleSprite(actor.sprite!!, actor.spriteGlow)
|
||||
}
|
||||
}
|
||||
// replace existing player
|
||||
val oldPlayerID = ingame.actorNowPlaying?.referenceID
|
||||
try {
|
||||
ingame.forceRemoveActor(ingame.getActorByID(actor.referenceID))
|
||||
}
|
||||
catch (e: NoSuchActorWithIDException) { /* no actor to delete, you may proceed */ }
|
||||
ingame.addNewActor(actor)
|
||||
|
||||
if (actor.referenceID == oldPlayerID)
|
||||
ingame.actorNowPlaying = actor as ActorHumanoid
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import java.io.InputStream
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-08-25.
|
||||
*/
|
||||
open class ReadWorld(val ingame: TerrarumIngame) {
|
||||
|
||||
open fun invoke(worldDataStream: InputStream) {
|
||||
postRead(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||
}
|
||||
|
||||
open fun invoke(worldDataStream: Reader) {
|
||||
postRead(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||
}
|
||||
|
||||
private fun postRead(world: GameWorld) {
|
||||
world.postLoad()
|
||||
|
||||
ingame.world = world
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
|
||||
|
||||
object SavegameLedger {
|
||||
|
||||
private val SAVE_DIRECTORY = File(AppLoader.defaultSaveDir)
|
||||
|
||||
fun hasSavegameDirectory() = SAVE_DIRECTORY.exists() && SAVE_DIRECTORY.isDirectory
|
||||
|
||||
private fun peekFewBytes(file: File, length: Int): ByteArray {
|
||||
val buffer = ByteArray(length)
|
||||
val `is` = FileInputStream(file)
|
||||
if (`is`.read(buffer) != buffer.size) {
|
||||
throw InternalError()
|
||||
}
|
||||
`is`.close()
|
||||
return buffer
|
||||
}
|
||||
private val MAGIC_TEVD = "TEVd".toByteArray()
|
||||
|
||||
fun getSavefileList(): List<File>? {
|
||||
return if (!hasSavegameDirectory()) null
|
||||
else SAVE_DIRECTORY.listFiles().filter { it.isFile && peekFewBytes(it, 4) contentEquals MAGIC_TEVD }
|
||||
}
|
||||
|
||||
fun getSavefileCount() = getSavefileList()?.count() ?: 0
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-10-03.
|
||||
*/
|
||||
object SavegameReader {
|
||||
|
||||
// TODO read TEVd, load necessary shits
|
||||
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.spriteanimation.HasAssembledSprite
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.terrarum.NoSuchActorWithIDException
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64Writer
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-08-24.
|
||||
@@ -23,4 +31,54 @@ object WriteActor {
|
||||
return baw.toByteArray64()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Actor's JSON representation is expected to have "class" property on the root object, such as:
|
||||
* ```
|
||||
* "class":"net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer"
|
||||
* ```
|
||||
*
|
||||
* Created by minjaesong on 2021-08-27.
|
||||
*/
|
||||
object ReadActor {
|
||||
|
||||
fun readActorOnly(worldDataStream: Reader): Actor =
|
||||
Common.jsoner.fromJson(null, worldDataStream)
|
||||
|
||||
operator fun invoke(ingame: TerrarumIngame, worldDataStream: Reader): Actor =
|
||||
postRead(ingame, readActorOnly(worldDataStream))
|
||||
|
||||
private fun postRead(ingame: TerrarumIngame, actor: Actor): Actor {
|
||||
// filling in Transients
|
||||
actor.actorValue.actor = actor
|
||||
|
||||
if (actor is Pocketed)
|
||||
actor.inventory.actor = actor
|
||||
|
||||
if (actor is ActorWithBody) {
|
||||
actor.sprite = SpriteAnimation(actor)
|
||||
|
||||
if (actor is HasAssembledSprite) {
|
||||
if (actor.animDescPathGlow != null) actor.spriteGlow = SpriteAnimation(actor)
|
||||
actor.reassembleSprite(actor.sprite!!, actor.spriteGlow)
|
||||
}
|
||||
}
|
||||
// replace existing player
|
||||
val oldPlayerID = ingame.actorNowPlaying?.referenceID
|
||||
try {
|
||||
ingame.forceRemoveActor(ingame.getActorByID(actor.referenceID))
|
||||
}
|
||||
catch (e: NoSuchActorWithIDException) { /* no actor to delete, you may proceed */ }
|
||||
ingame.addNewActor(actor)
|
||||
|
||||
if (actor.referenceID == oldPlayerID)
|
||||
ingame.actorNowPlaying = actor as ActorHumanoid
|
||||
|
||||
|
||||
return actor
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,17 +6,21 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64Reader
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.EntryFile
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VirtualDisk
|
||||
import net.torvald.terrarum.utils.MetaModuleCSVPair
|
||||
import net.torvald.terrarum.utils.ZipCodedStr
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
import java.io.StringReader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-08-23.
|
||||
*/
|
||||
open class WriteMeta(val ingame: TerrarumIngame) {
|
||||
object WriteMeta {
|
||||
|
||||
open fun invoke(): String {
|
||||
operator fun invoke(ingame: TerrarumIngame, currentPlayTime_t: Long): String {
|
||||
val world = ingame.world
|
||||
|
||||
|
||||
val meta = WorldMeta(
|
||||
genver = Common.GENVER,
|
||||
savename = world.worldName,
|
||||
@@ -28,34 +32,26 @@ open class WriteMeta(val ingame: TerrarumIngame) {
|
||||
playerid = ingame.actorGamer.referenceID,
|
||||
creation_t = world.creationTime,
|
||||
lastplay_t = world.lastPlayTime,
|
||||
playtime_t = world.totalPlayTime,
|
||||
blocks = StringBuilder().let {
|
||||
ModMgr.getFilesFromEveryMod("blocks/blocks.csv").forEach { (modname, file) ->
|
||||
it.append(modnameToOrnamentalHeader(modname))
|
||||
it.append(file.readText())
|
||||
}
|
||||
zipStrAndEnascii(it.toString())
|
||||
playtime_t = world.totalPlayTime + currentPlayTime_t,
|
||||
blocks = ModMgr.getFilesFromEveryMod("blocks/blocks.csv").fold(MetaModuleCSVPair()) {
|
||||
map, (modname, file) ->
|
||||
map[modname] = ZipCodedStr(file.readText ())
|
||||
/*return*/map
|
||||
},
|
||||
items = StringBuilder().let {
|
||||
ModMgr.getFilesFromEveryMod("items/itemid.csv").forEach { (modname, file) ->
|
||||
it.append(modnameToOrnamentalHeader(modname))
|
||||
it.append(file.readText())
|
||||
}
|
||||
zipStrAndEnascii(it.toString())
|
||||
items = ModMgr.getFilesFromEveryMod("items/itemid.csv").fold(MetaModuleCSVPair()) {
|
||||
map, (modname, file) ->
|
||||
map[modname] = ZipCodedStr(file.readText ())
|
||||
/*return*/map
|
||||
},
|
||||
wires = StringBuilder().let {
|
||||
ModMgr.getFilesFromEveryMod("wires/wires.csv").forEach { (modname, file) ->
|
||||
it.append(modnameToOrnamentalHeader(modname))
|
||||
it.append(file.readText())
|
||||
}
|
||||
zipStrAndEnascii(it.toString())
|
||||
wires = ModMgr.getFilesFromEveryMod("wires/wires.csv").fold(MetaModuleCSVPair()) {
|
||||
map, (modname, file) ->
|
||||
map[modname] = ZipCodedStr(file.readText ())
|
||||
/*return*/map
|
||||
},
|
||||
materials = StringBuilder().let {
|
||||
ModMgr.getFilesFromEveryMod("materials/materials.csv").forEach { (modname, file) ->
|
||||
it.append(modnameToOrnamentalHeader(modname))
|
||||
it.append(file.readText())
|
||||
}
|
||||
zipStrAndEnascii(it.toString())
|
||||
materials = ModMgr.getFilesFromEveryMod("materials/materials.csv").fold(MetaModuleCSVPair()) {
|
||||
map, (modname, file) ->
|
||||
map[modname] = ZipCodedStr(file.readText ())
|
||||
/*return*/map
|
||||
},
|
||||
loadorder = ModMgr.loadOrder.toTypedArray(),
|
||||
worlds = ingame.gameworldIndices.toTypedArray()
|
||||
@@ -64,9 +60,9 @@ open class WriteMeta(val ingame: TerrarumIngame) {
|
||||
return Common.jsoner.toJson(meta)
|
||||
}
|
||||
|
||||
fun encodeToByteArray64(): ByteArray64 {
|
||||
fun encodeToByteArray64(ingame: TerrarumIngame, currentPlayTime_t: Long): ByteArray64 {
|
||||
val ba = ByteArray64()
|
||||
this.invoke().toByteArray(Common.CHARSET).forEach { ba.add(it) }
|
||||
this.invoke(ingame, currentPlayTime_t).toByteArray(Common.CHARSET).forEach { ba.add(it) }
|
||||
return ba
|
||||
}
|
||||
|
||||
@@ -82,10 +78,10 @@ open class WriteMeta(val ingame: TerrarumIngame) {
|
||||
val creation_t: Long = 0,
|
||||
val lastplay_t: Long = 0,
|
||||
val playtime_t: Long = 0,
|
||||
val blocks: String = "",
|
||||
val items: String = "",
|
||||
val wires: String = "",
|
||||
val materials: String = "",
|
||||
val blocks: MetaModuleCSVPair = MetaModuleCSVPair(),
|
||||
val items: MetaModuleCSVPair = MetaModuleCSVPair(),
|
||||
val wires: MetaModuleCSVPair = MetaModuleCSVPair(),
|
||||
val materials: MetaModuleCSVPair = MetaModuleCSVPair(),
|
||||
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
|
||||
) {
|
||||
@@ -94,23 +90,22 @@ open class WriteMeta(val ingame: TerrarumIngame) {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun modnameToOrnamentalHeader(s: String) =
|
||||
"\n\n${"#".repeat(16 + s.length)}\n" +
|
||||
"## module: $s ##\n" +
|
||||
"${"#".repeat(16 + s.length)}\n\n"
|
||||
|
||||
/**
|
||||
* @param [s] a String
|
||||
* @return UTF-8 encoded [s] which are GZip'd then Ascii85-encoded
|
||||
*/
|
||||
fun zipStrAndEnascii(s: String): String {
|
||||
return Common.bytesToZipdStr(s.toByteArray(Common.CHARSET).iterator())
|
||||
}
|
||||
|
||||
fun unasciiAndUnzipStr(s: String): String {
|
||||
return ByteArray64Reader(Common.strToBytes(StringReader(s)), Common.CHARSET).readText()
|
||||
}
|
||||
}
|
||||
private fun modnameToOrnamentalHeader(s: String) =
|
||||
"\n\n${"#".repeat(16 + s.length)}\n" +
|
||||
"## module: $s ##\n" +
|
||||
"${"#".repeat(16 + s.length)}\n\n"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-09-03.
|
||||
*/
|
||||
object ReadMeta {
|
||||
|
||||
operator fun invoke(savefile: VirtualDisk): WriteMeta.WorldMeta {
|
||||
val metaFile = savefile.entries[-1]!!
|
||||
val metaReader = ByteArray64Reader((metaFile.contents as EntryFile).getContent(), Common.CHARSET)
|
||||
return Common.jsoner.fromJson(WriteMeta.WorldMeta::class.java, metaReader)
|
||||
}
|
||||
|
||||
}
|
||||
98
src/net/torvald/terrarum/serialise/WriteSavegame.kt
Normal file
98
src/net/torvald/terrarum/serialise/WriteSavegame.kt
Normal file
@@ -0,0 +1,98 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.*
|
||||
import net.torvald.terrarum.serialise.WriteWorld.actorAcceptable
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* 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(disk: VirtualDisk, outFile: File, ingame: TerrarumIngame) {
|
||||
val creation_t = ingame.world.creationTime
|
||||
val time_t = AppLoader.getTIME_T()
|
||||
val currentPlayTime_t = time_t - ingame.loadedTime_t
|
||||
|
||||
|
||||
// Write Meta //
|
||||
val metaContent = EntryFile(WriteMeta.encodeToByteArray64(ingame, currentPlayTime_t))
|
||||
val meta = DiskEntry(-1, 0, "savegame".toByteArray(), creation_t, time_t, metaContent)
|
||||
addFile(disk, meta)
|
||||
|
||||
// Write World //
|
||||
val worldNum = ingame.world.worldIndex
|
||||
val worldContent = EntryFile(WriteWorld.encodeToByteArray64(ingame))
|
||||
val world = DiskEntry(worldNum, 0, "world${worldNum}".toByteArray(), creation_t, time_t, worldContent)
|
||||
addFile(disk, world)
|
||||
|
||||
// Write Actors //
|
||||
listOf(ingame.actorContainerActive, ingame.actorContainerInactive).forEach { actors ->
|
||||
actors.forEach {
|
||||
if (actorAcceptable(it)) {
|
||||
val actorContent = EntryFile(WriteActor.encodeToByteArray64(it))
|
||||
val actor = DiskEntry(it.referenceID, 0, "actor${it.referenceID}".toByteArray(), creation_t, time_t, actorContent)
|
||||
addFile(disk, actor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disk.capacity = 0
|
||||
VDUtil.dumpToRealMachine(disk, outFile)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
operator fun invoke(disk: VirtualDisk) {
|
||||
val meta = ReadMeta(disk)
|
||||
val player = ReadActor.readActorOnly(
|
||||
ByteArray64Reader(VDUtil.getAsNormalFile(disk, 9545698).getContent(), Common.CHARSET)
|
||||
) as IngamePlayer
|
||||
val world = ReadWorld.readWorldOnly(
|
||||
ByteArray64Reader(VDUtil.getAsNormalFile(disk, player.worldCurrentlyPlaying).getContent(), Common.CHARSET)
|
||||
)
|
||||
val actors = world.actors.map {
|
||||
ReadActor.readActorOnly(ByteArray64Reader(VDUtil.getAsNormalFile(disk, it).getContent(), Common.CHARSET))
|
||||
}
|
||||
|
||||
val ingame = TerrarumIngame(AppLoader.batch)
|
||||
val worldParam = meta
|
||||
ingame.world = world
|
||||
ingame.gameLoadInfoPayload = worldParam
|
||||
ingame.gameLoadMode = TerrarumIngame.GameLoadMode.LOAD_FROM
|
||||
ingame.savegameArchive = disk
|
||||
actors.forEach { ingame.addNewActor(it) }
|
||||
ingame.actorNowPlaying = player
|
||||
|
||||
Terrarum.setCurrentIngameInstance(ingame)
|
||||
val loadScreen = SanicLoadScreen
|
||||
AppLoader.setLoadScreen(loadScreen)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,69 @@
|
||||
package net.torvald.terrarum.serialise
|
||||
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
import net.torvald.terrarum.ReferencingRanges
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.ByteArray64Writer
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-08-23.
|
||||
*/
|
||||
open class WriteWorld(val ingame: TerrarumIngame) {
|
||||
object WriteWorld {
|
||||
|
||||
open fun invoke(): String {
|
||||
val world = ingame.world
|
||||
world.genver = Common.GENVER
|
||||
world.comp = Common.COMP_GZIP
|
||||
return Common.jsoner.toJson(world)
|
||||
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)
|
||||
}
|
||||
|
||||
fun encodeToByteArray64(): ByteArray64 {
|
||||
private fun preWrite(ingame: TerrarumIngame): GameWorld {
|
||||
val world = ingame.world
|
||||
world.genver = Common.GENVER
|
||||
world.comp = Common.COMP_GZIP
|
||||
ingame.actorContainerActive.filter { actorAcceptable(it) }.forEach { world.actors.add(it.referenceID) }
|
||||
ingame.actorContainerInactive.filter { actorAcceptable(it) }.forEach { world.actors.add(it.referenceID) }
|
||||
|
||||
return world
|
||||
}
|
||||
|
||||
operator fun invoke(ingame: TerrarumIngame): String {
|
||||
return Common.jsoner.toJson(preWrite(ingame))
|
||||
}
|
||||
|
||||
fun encodeToByteArray64(ingame: TerrarumIngame): ByteArray64 {
|
||||
val baw = ByteArray64Writer(Common.CHARSET)
|
||||
|
||||
Common.jsoner.toJson(world, baw)
|
||||
Common.jsoner.toJson(preWrite(ingame), baw)
|
||||
baw.flush(); baw.close()
|
||||
|
||||
return baw.toByteArray64()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-08-25.
|
||||
*/
|
||||
object ReadWorld {
|
||||
|
||||
fun readWorldOnly(worldDataStream: Reader): GameWorld =
|
||||
Common.jsoner.fromJson(GameWorld::class.java, worldDataStream)
|
||||
|
||||
operator fun invoke(ingame: TerrarumIngame, worldDataStream: Reader): GameWorld =
|
||||
postRead(ingame, readWorldOnly(worldDataStream))
|
||||
|
||||
private fun postRead(ingame: TerrarumIngame, world: GameWorld): GameWorld {
|
||||
world.postLoad()
|
||||
ingame.world = world
|
||||
|
||||
return world
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user