mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 18:14:06 +09:00
able to load chunked world save
This commit is contained in:
@@ -97,12 +97,12 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun checkNullPtr(index: Long) { // ignore what IDEA says and do inline this
|
private inline fun checkNullPtr(index: Long) { // ignore what IDEA says and do inline this
|
||||||
//// commenting out because of the suspected (or minor?) performance impact.
|
// commenting out because of the suspected (or minor?) performance impact.
|
||||||
//// You may break the glass and use this tool when some fucking incomprehensible bugs ("vittujen vitun bugit")
|
// You may break the glass and use this tool when some fucking incomprehensible bugs ("vittujen vitun bugit")
|
||||||
//// appear (e.g. getting garbage values when it fucking shouldn't)
|
// appear (e.g. getting garbage values when it fucking shouldn't)
|
||||||
|
|
||||||
//assert(!destroyed) { throw NullPointerException("The pointer is already destroyed ($this)") }
|
// assert(!destroyed) { throw NullPointerException("The pointer is already destroyed ($this)") }
|
||||||
//if (index !in 0 until size) throw IndexOutOfBoundsException("Index: $index; alloc size: $size")
|
// if (index !in 0 until size) throw IndexOutOfBoundsException("Index: $index; alloc size: $size")
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(index: Long): Byte {
|
operator fun get(index: Long): Byte {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import net.torvald.terrarum.modulebasegame.IngameRenderer
|
|||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
||||||
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.serialise.ReadWorld
|
import net.torvald.terrarum.serialise.ReadWorld
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.weather.WeatherMixer
|
import net.torvald.terrarum.weather.WeatherMixer
|
||||||
@@ -125,12 +126,12 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
try {
|
try {
|
||||||
val reader = java.io.FileReader(ModMgr.getFile("basegame", "demoworld"))
|
val reader = java.io.FileReader(ModMgr.getFile("basegame", "demoworld"))
|
||||||
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||||
val world = ReadWorld.invoke(reader)
|
val world = ReadWorld.readLayerFormat(reader)
|
||||||
demoWorld = world
|
demoWorld = world
|
||||||
printdbg(this, "Demo world loaded")
|
printdbg(this, "Demo world loaded")
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
demoWorld = GameWorld(1, 64, 64, 0L, 0L, 0)
|
demoWorld = GameWorld(1, LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L, 0)
|
||||||
printdbg(this, "Demo world not found, using empty world")
|
printdbg(this, "Demo world not found, using empty world")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,14 @@ open class BlockLayer(val width: Int, val height: Int) : Disposable {
|
|||||||
val msb = tile.ushr(8).and(0xff).toByte()
|
val msb = tile.ushr(8).and(0xff).toByte()
|
||||||
|
|
||||||
|
|
||||||
ptr[offset] = lsb
|
// try {
|
||||||
ptr[offset + 1] = msb
|
ptr[offset] = lsb
|
||||||
|
ptr[offset + 1] = msb
|
||||||
|
// }
|
||||||
|
// catch (e: IndexOutOfBoundsException) {
|
||||||
|
// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset")
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,7 +18,15 @@ import kotlin.math.absoluteValue
|
|||||||
|
|
||||||
typealias BlockAddress = Long
|
typealias BlockAddress = Long
|
||||||
|
|
||||||
class GameWorld() : Disposable {
|
/**
|
||||||
|
* Special version of GameWorld where layer data are not transient
|
||||||
|
*/
|
||||||
|
class GameWorldTitleScreen : GameWorld() {
|
||||||
|
override lateinit var layerWall: BlockLayer
|
||||||
|
override lateinit var layerTerrain: BlockLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
open class GameWorld() : Disposable {
|
||||||
|
|
||||||
var worldName: String = "New World"
|
var worldName: String = "New World"
|
||||||
/** Index start at 1 */
|
/** Index start at 1 */
|
||||||
@@ -43,8 +51,8 @@ class GameWorld() : Disposable {
|
|||||||
internal set
|
internal set
|
||||||
|
|
||||||
//layers
|
//layers
|
||||||
lateinit var layerWall: BlockLayer
|
@Transient lateinit open var layerWall: BlockLayer
|
||||||
lateinit var layerTerrain: BlockLayer
|
@Transient lateinit open var layerTerrain: BlockLayer
|
||||||
|
|
||||||
//val layerThermal: MapLayerHalfFloat // in Kelvins
|
//val layerThermal: MapLayerHalfFloat // in Kelvins
|
||||||
//val layerFluidPressure: MapLayerHalfFloat // (milibar - 1000)
|
//val layerFluidPressure: MapLayerHalfFloat // (milibar - 1000)
|
||||||
@@ -185,6 +193,12 @@ class GameWorld() : Disposable {
|
|||||||
//val wireArray: ByteArray
|
//val wireArray: ByteArray
|
||||||
// get() = layerWire.data
|
// get() = layerWire.data
|
||||||
|
|
||||||
|
fun getLayer(index: Int) = when(index) {
|
||||||
|
0 -> layerTerrain
|
||||||
|
1 -> layerWall
|
||||||
|
else -> throw IllegalArgumentException("Unknown layer index: $index")
|
||||||
|
}
|
||||||
|
|
||||||
fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1))
|
fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ import net.torvald.terrarum.modulebasegame.ui.*
|
|||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldgenParams
|
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldgenParams
|
||||||
import net.torvald.terrarum.tvda.VDUtil
|
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.serialise.WriteMeta
|
import net.torvald.terrarum.serialise.WriteMeta
|
||||||
|
import net.torvald.terrarum.tvda.VDUtil
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.weather.WeatherMixer
|
import net.torvald.terrarum.weather.WeatherMixer
|
||||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||||
@@ -296,6 +296,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
|||||||
// init map as chosen size
|
// init map as chosen size
|
||||||
val timeNow = App.getTIME_T()
|
val timeNow = App.getTIME_T()
|
||||||
world = GameWorld(1, worldParams.width, worldParams.height, timeNow, timeNow, 0) // new game, so the creation time is right now
|
world = GameWorld(1, worldParams.width, worldParams.height, timeNow, timeNow, 0) // new game, so the creation time is right now
|
||||||
|
world.generatorSeed = worldParams.worldGenSeed
|
||||||
gameworldIndices.add(world.worldIndex)
|
gameworldIndices.add(world.worldIndex)
|
||||||
world.extraFields["basegame.economy"] = GameEconomy()
|
world.extraFields["basegame.economy"] = GameEconomy()
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.ui
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Camera
|
import com.badlogic.gdx.graphics.Camera
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import net.torvald.random.HQRNG
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.Second
|
import net.torvald.terrarum.Second
|
||||||
@@ -37,8 +38,8 @@ class UIProxyNewRandomGame : UICanvas() {
|
|||||||
|
|
||||||
|
|
||||||
val ingame = TerrarumIngame(App.batch)
|
val ingame = TerrarumIngame(App.batch)
|
||||||
// val worldParam = TerrarumIngame.NewWorldParameters(2880, 1344, HQRNG().nextLong())
|
val worldParam = TerrarumIngame.NewWorldParameters(2880, 1350, HQRNG().nextLong())
|
||||||
val worldParam = TerrarumIngame.NewWorldParameters(2880, 1350, 0x51621D)
|
// val worldParam = TerrarumIngame.NewWorldParameters(2880, 1350, 0x51621D)
|
||||||
|
|
||||||
//val worldParam = TerrarumIngame.NewWorldParameters(6000, 1800, 0x51621DL) // small
|
//val worldParam = TerrarumIngame.NewWorldParameters(6000, 1800, 0x51621DL) // small
|
||||||
// val worldParam = TerrarumIngame.NewWorldParameters(9000, 2250, 0x51621DL) // normal
|
// val worldParam = TerrarumIngame.NewWorldParameters(9000, 2250, 0x51621DL) // normal
|
||||||
|
|||||||
@@ -75,9 +75,6 @@ object Common {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayer {
|
override fun read(json: Json, jsonData: JsonValue, type: Class<*>): BlockLayer {
|
||||||
// full auto
|
|
||||||
//return strToBlockLayer(json.fromJson(type, jsonData.toJson(JsonWriter.OutputType.minimal)) as LayerInfo)
|
|
||||||
|
|
||||||
// full manual
|
// full manual
|
||||||
try {
|
try {
|
||||||
return strToBlockLayer(LayerInfo(
|
return strToBlockLayer(LayerInfo(
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ object WriteMeta {
|
|||||||
val meta = WorldMeta(
|
val meta = WorldMeta(
|
||||||
genver = Common.GENVER,
|
genver = Common.GENVER,
|
||||||
savename = world.worldName,
|
savename = world.worldName,
|
||||||
terrseed = world.generatorSeed,
|
|
||||||
randseed0 = RoguelikeRandomiser.RNG.state0,
|
randseed0 = RoguelikeRandomiser.RNG.state0,
|
||||||
randseed1 = RoguelikeRandomiser.RNG.state1,
|
randseed1 = RoguelikeRandomiser.RNG.state1,
|
||||||
weatseed0 = WeatherMixer.RNG.state0,
|
weatseed0 = WeatherMixer.RNG.state0,
|
||||||
@@ -46,7 +45,6 @@ object WriteMeta {
|
|||||||
data class WorldMeta(
|
data class WorldMeta(
|
||||||
val genver: Int = -1,
|
val genver: Int = -1,
|
||||||
val savename: String = "",
|
val savename: String = "",
|
||||||
val terrseed: Long = 0,
|
|
||||||
val randseed0: Long = 0,
|
val randseed0: Long = 0,
|
||||||
val randseed1: Long = 0,
|
val randseed1: Long = 0,
|
||||||
val weatseed0: Long = 0,
|
val weatseed0: Long = 0,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import net.torvald.gdx.graphics.PixmapIO2
|
|||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.console.Echo
|
import net.torvald.terrarum.console.Echo
|
||||||
|
import net.torvald.terrarum.gameworld.BlockLayer
|
||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
@@ -97,11 +98,11 @@ object WriteSavegame {
|
|||||||
|
|
||||||
// Write World //
|
// Write World //
|
||||||
val worldNum = ingame.world.worldIndex
|
val worldNum = ingame.world.worldIndex
|
||||||
/*val worldContent = EntryFile(WriteWorld.encodeToByteArray64(ingame))
|
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame))
|
||||||
val world = DiskEntry(worldNum.toLong(), 0, "world${worldNum}".toByteArray(Common.CHARSET), creation_t, time_t, worldContent)
|
val world = DiskEntry(worldNum.toLong(), 0, creation_t, time_t, worldMeta)
|
||||||
addFile(disk, world)*/
|
addFile(disk, world)
|
||||||
|
|
||||||
val layers = arrayOf(ingame.world.layerTerrain, ingame.world.layerWall)
|
val layers = intArrayOf(0,1).map { ingame.world.getLayer(it) }
|
||||||
val cw = ingame.world.width / LandUtil.CHUNK_W
|
val cw = ingame.world.width / LandUtil.CHUNK_W
|
||||||
val ch = ingame.world.height / LandUtil.CHUNK_H
|
val ch = ingame.world.height / LandUtil.CHUNK_H
|
||||||
for (layer in layers.indices) {
|
for (layer in layers.indices) {
|
||||||
@@ -119,8 +120,6 @@ object WriteSavegame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO save worldinfo
|
|
||||||
|
|
||||||
|
|
||||||
// Write Actors //
|
// Write Actors //
|
||||||
listOf(ingame.actorContainerActive, ingame.actorContainerInactive).forEach { actors ->
|
listOf(ingame.actorContainerActive, ingame.actorContainerInactive).forEach { actors ->
|
||||||
@@ -174,12 +173,31 @@ object LoadSavegame {
|
|||||||
// val faction = Common.jsoner.fromJson(FactionCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -20)))
|
// val faction = Common.jsoner.fromJson(FactionCodex.javaClass, getUnzipInputStream(getFileBytes(disk, -20)))
|
||||||
val apocryphas = Common.jsoner.fromJson(Apocryphas.javaClass, getUnzipInputStream(getFileBytes(disk, -1024)))
|
val apocryphas = Common.jsoner.fromJson(Apocryphas.javaClass, getUnzipInputStream(getFileBytes(disk, -1024)))
|
||||||
|
|
||||||
|
// set lateinit vars on the gameworld
|
||||||
|
world.layerTerrain = BlockLayer(world.width, world.height)
|
||||||
|
world.layerWall = BlockLayer(world.width, world.height)
|
||||||
|
|
||||||
val worldParam = TerrarumIngame.Codices(meta, item, apocryphas)
|
val worldParam = TerrarumIngame.Codices(meta, item, apocryphas)
|
||||||
newIngame.world = world
|
newIngame.world = world
|
||||||
newIngame.gameLoadInfoPayload = worldParam
|
newIngame.gameLoadInfoPayload = worldParam
|
||||||
newIngame.gameLoadMode = TerrarumIngame.GameLoadMode.LOAD_FROM
|
newIngame.gameLoadMode = TerrarumIngame.GameLoadMode.LOAD_FROM
|
||||||
newIngame.savegameArchive = disk
|
newIngame.savegameArchive = disk
|
||||||
|
|
||||||
|
// load all the world blocklayer chunks
|
||||||
|
val worldnum = world.worldIndex.toLong()
|
||||||
|
val cw = LandUtil.CHUNK_W; val ch = LandUtil.CHUNK_H
|
||||||
|
val chunksX = world.width / cw
|
||||||
|
for (layer in 0L..1L) {
|
||||||
|
val worldLayer = world.getLayer(layer.toInt())
|
||||||
|
|
||||||
|
for (chunk in 0L until (world.width * world.height) / (cw * ch)) {
|
||||||
|
val chunkFile = VDUtil.getAsNormalFile(disk, worldnum.shl(32) or layer.shl(24) or chunk)
|
||||||
|
val cx = chunk % chunksX
|
||||||
|
val cy = chunk / chunksX
|
||||||
|
ReadWorld.decodeChunkToLayer(chunkFile.getContent(), worldLayer, cx.toInt(), cy.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
actors.forEach { newIngame.addNewActor(it) }
|
actors.forEach { newIngame.addNewActor(it) }
|
||||||
|
|
||||||
// by doing this, whatever the "possession" the player had will be broken by the game load
|
// by doing this, whatever the "possession" the player had will be broken by the game load
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import net.torvald.terrarum.gameactors.ActorID
|
|||||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||||
import net.torvald.terrarum.gameworld.BlockLayer
|
import net.torvald.terrarum.gameworld.BlockLayer
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
|
import net.torvald.terrarum.gameworld.GameWorldTitleScreen
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.tvda.ByteArray64
|
import net.torvald.terrarum.tvda.ByteArray64
|
||||||
import net.torvald.terrarum.tvda.ByteArray64Writer
|
import net.torvald.terrarum.tvda.ByteArray64Writer
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,6 +76,9 @@ object WriteWorld {
|
|||||||
*/
|
*/
|
||||||
object ReadWorld {
|
object ReadWorld {
|
||||||
|
|
||||||
|
fun readLayerFormat(worldDataStream: Reader): GameWorld =
|
||||||
|
fillInDetails(Common.jsoner.fromJson(GameWorldTitleScreen::class.java, worldDataStream))
|
||||||
|
|
||||||
operator fun invoke(worldDataStream: Reader): GameWorld =
|
operator fun invoke(worldDataStream: Reader): GameWorld =
|
||||||
fillInDetails(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
fillInDetails(Common.jsoner.fromJson(GameWorld::class.java, worldDataStream))
|
||||||
|
|
||||||
@@ -87,7 +91,7 @@ object ReadWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readWorldAndSetNewWorld(ingame: TerrarumIngame, worldDataStream: Reader): GameWorld {
|
fun readWorldAndSetNewWorld(ingame: TerrarumIngame, worldDataStream: Reader): GameWorld {
|
||||||
val world = invoke(worldDataStream)
|
val world = readLayerFormat(worldDataStream)
|
||||||
ingame.world = world
|
ingame.world = world
|
||||||
return world
|
return world
|
||||||
}
|
}
|
||||||
@@ -95,7 +99,7 @@ object ReadWorld {
|
|||||||
private val cw = LandUtil.CHUNK_W
|
private val cw = LandUtil.CHUNK_W
|
||||||
private val ch = LandUtil.CHUNK_H
|
private val ch = LandUtil.CHUNK_H
|
||||||
|
|
||||||
fun decodeToLayer(chunk: ByteArray64, targetLayer: BlockLayer, cx: Int, cy: Int) {
|
fun decodeChunkToLayer(chunk: ByteArray64, targetLayer: BlockLayer, cx: Int, cy: Int) {
|
||||||
val bytes = Common.unzip(chunk)
|
val bytes = Common.unzip(chunk)
|
||||||
if (bytes.size != cw * ch * 2L)
|
if (bytes.size != cw * ch * 2L)
|
||||||
throw UnsupportedOperationException("Chunk size mismatch: decoded chunk size is ${bytes.size} bytes " +
|
throw UnsupportedOperationException("Chunk size mismatch: decoded chunk size is ${bytes.size} bytes " +
|
||||||
@@ -105,7 +109,14 @@ object ReadWorld {
|
|||||||
val tilenum = bytes[2L*k].toUint().shl(8) or bytes[2L*k + 1].toUint()
|
val tilenum = bytes[2L*k].toUint().shl(8) or bytes[2L*k + 1].toUint()
|
||||||
val offx = k % cw
|
val offx = k % cw
|
||||||
val offy = k / cw
|
val offy = k / cw
|
||||||
targetLayer.unsafeSetTile(cx * cw + offx, cy * ch * offy, tilenum)
|
|
||||||
|
// try {
|
||||||
|
targetLayer.unsafeSetTile(cx * cw + offx, cy * ch + offy, tilenum)
|
||||||
|
// }
|
||||||
|
// catch (e: IndexOutOfBoundsException) {
|
||||||
|
// printdbgerr(this, "IndexOutOfBoundsException, cx = $cx, cy = $cy, k = $k, offx = $offx, offy = $offy")
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user