map data format adds world generator version and fluids

This commit is contained in:
minjaesong
2019-01-14 19:11:04 +09:00
parent edda3b9ff9
commit a7ec3e77b1
8 changed files with 127 additions and 41 deletions

View File

@@ -1,10 +1,8 @@
package net.torvald.terrarum.serialise
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import java.io.IOException
import java.io.InputStream
import java.lang.IllegalArgumentException
import java.util.*
/**
@@ -123,6 +121,16 @@ fun Int.toLittle() = byteArrayOf(
this.ushr(16).and(0xFF).toByte(),
this.ushr(24).and(0xFF).toByte()
)
/** Converts int as 2-byte array, discarding the sign.*/
fun Int.toULittleShort() = byteArrayOf(
this.and(0xFF).toByte(),
this.ushr(8).and(0xFF).toByte()
)
/** Converts int as 2-byte array, preserving the sign. In other words, it converts int to short. */
fun Int.toLittleShort() = byteArrayOf(
this.and(0xFF).toByte(),
this.shr(8).and(0xFF).toByte()
)
fun Long.toLittle() = byteArrayOf(
this.and(0xFF).toByte(),
this.ushr(8).and(0xFF).toByte(),
@@ -133,7 +141,8 @@ fun Long.toLittle() = byteArrayOf(
this.ushr(48).and(0xFF).toByte(),
this.ushr(56).and(0xFF).toByte()
)
fun Long.toLittle48() = byteArrayOf(
/** Converts long as 6-byte array, discarding the sign. */
fun Long.toULittle48() = byteArrayOf(
this.and(0xFF).toByte(),
this.ushr(8).and(0xFF).toByte(),
this.ushr(16).and(0xFF).toByte(),
@@ -150,6 +159,14 @@ fun ByteArray.toLittleInt() =
this[1].toUint().shl(8) or
this[2].toUint().shl(16) or
this[3].toUint().shl(24)
fun ByteArray.toULittleShort() =
if (this.size != 4) throw Error("Array not in size of 2")
else this[0].toUint() or
this[1].toUint().shl(8)
fun ByteArray.toLittleShort() =
if (this.size != 4) throw Error("Array not in size of 2")
else this[0].toUint() or
this[1].toInt().shl(8)
fun ByteArray.toLittleLong() =
if (this.size != 8) throw Error("Array not in size of 8")
else this[0].toUlong() or
@@ -171,4 +188,6 @@ 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)
const val WORLD_GENERATOR_VERSION = 1

View File

@@ -6,13 +6,12 @@ import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.FluidType
import net.torvald.terrarum.gameworld.MapLayer
import net.torvald.terrarum.gameworld.PairedMapLayer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.DiskSkimmer.Companion.read
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.toHex
import java.io.*
import java.nio.charset.Charset
import java.util.*
import kotlin.IllegalArgumentException
import kotlin.collections.HashMap
/**
@@ -45,6 +44,7 @@ internal object ReadLayerDataLzma {
val layerCount = inputStream.read(1)[0].toUint()
val payloadCount = inputStream.read(1)[0].toUint()
val compression = inputStream.read(1)[0].toUint()
val generatorVer = inputStream.read(2).toULittleShort()
val width = inputStream.read(4).toLittleInt()
val height = inputStream.read(4).toLittleInt()
val spawnAddress = inputStream.read(6).toLittleInt48()
@@ -55,6 +55,7 @@ internal object ReadLayerDataLzma {
printdbg(this, "Layers count: $layerCount")
printdbg(this, "Payloads count: $payloadCount")
printdbg(this, "Compression: $compression")
printdbg(this, "World generator version: $generatorVer")
printdbg(this, "Dimension: ${width}x$height")
// read payloads

View File

@@ -4,14 +4,16 @@ import net.torvald.terrarum.AppLoader.printdbg
import net.torvald.terrarum.gameworld.BlockAddress
import net.torvald.terrarum.gameworld.MapLayer
import net.torvald.terrarum.gameworld.PairedMapLayer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.DiskSkimmer.Companion.read
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.toHex
import java.io.*
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.util.*
import java.util.zip.Inflater
import kotlin.IllegalArgumentException
import kotlin.collections.HashMap
/**
@@ -44,6 +46,7 @@ internal object ReadLayerDataZip {
val layerCount = inputStream.read(1)[0].toUint()
val payloadCount = inputStream.read(1)[0].toUint()
val compression = inputStream.read(1)[0].toUint()
val generatorVer = inputStream.read(2).toULittleShort()
val width = inputStream.read(4).toLittleInt()
val height = inputStream.read(4).toLittleInt()
val spawnAddress = inputStream.read(6).toLittleInt48()
@@ -54,6 +57,7 @@ internal object ReadLayerDataZip {
printdbg(this, "Layers count: $layerCount")
printdbg(this, "Payloads count: $payloadCount")
printdbg(this, "Compression: $compression")
printdbg(this, "World generator version: $generatorVer")
printdbg(this, "Dimension: ${width}x$height")
// read payloads

View File

@@ -88,3 +88,5 @@ internal object WriteLayerData {
}
const val WORLD_WRITER_FORMAT_VERSION = 3

View File

@@ -2,12 +2,9 @@ package net.torvald.terrarum.serialise
import com.badlogic.gdx.utils.compression.Lzma
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.EchoError
import net.torvald.terrarum.realestate.LandUtil
import java.io.*
import java.nio.charset.Charset
import java.util.zip.DeflaterOutputStream
/**
@@ -33,10 +30,11 @@ internal object WriteLayerDataLzma {
val LAYERS_FILENAME = "world"
val MAGIC = byteArrayOf(0x54, 0x45, 0x4D, 0x7A)
val VERSION_NUMBER = 3.toByte()
val VERSION_NUMBER = WORLD_WRITER_FORMAT_VERSION.toByte()
val NUMBER_OF_LAYERS = 3.toByte()
val NUMBER_OF_PAYLOADS = 5.toByte()
val COMPRESSION_ALGORITHM = 2.toByte()
val GENERATOR_VERSION = WORLD_GENERATOR_VERSION.toULittleShort()
val PAYLOAD_HEADER = byteArrayOf(0, 0x70, 0x4C, 0x64)
val PAYLOAD_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x50, 0x59, 0x4C, 0x64, -1)
val FILE_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x54, 0x45, 0x4D, -1, -2)
@@ -77,7 +75,7 @@ internal object WriteLayerDataLzma {
fun wb(byte: Byte) { outputStream.write(byte.toInt()) }
//fun wb(byte: Int) { outputStream.write(byte) }
fun wi32(int: Int) { wb(int.toLittle()) }
fun wi48(long: Long) { wb(long.toLittle48()) }
fun wi48(long: Long) { wb(long.toULittle48()) }
fun wi64(long: Long) { wb(long.toLittle()) }
fun wf32(float: Float) { wi32(float.toRawBits()) }
@@ -88,7 +86,7 @@ internal object WriteLayerDataLzma {
// all the necessary headers
wb(MAGIC); wb(VERSION_NUMBER); wb(NUMBER_OF_LAYERS); wb(NUMBER_OF_PAYLOADS); wb(COMPRESSION_ALGORITHM)
wb(MAGIC); wb(VERSION_NUMBER); wb(NUMBER_OF_LAYERS); wb(NUMBER_OF_PAYLOADS); wb(COMPRESSION_ALGORITHM); wb(GENERATOR_VERSION)
// world width, height, and spawn point
wi32(world.width); wi32(world.height)
@@ -122,11 +120,11 @@ internal object WriteLayerDataLzma {
// TdMG payload
wb(PAYLOAD_HEADER); wb("TdMG".toByteArray())
wi48(world.terrainDamages.size.toLong())
wi48(world.terrainDamages.size * 10L)
world.terrainDamages.forEach { t, u ->
Lzma.compress(ByteArrayInputStream(t.toLittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(t.toULittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(u.toRawBits().toLittle()), outputStream)
}
@@ -134,16 +132,42 @@ internal object WriteLayerDataLzma {
// WdMG payload
wb(PAYLOAD_HEADER); wb("WdMG".toByteArray())
wi48(world.wallDamages.size.toLong())
wi48(world.wallDamages.size * 10L)
world.wallDamages.forEach { t, u ->
Lzma.compress(ByteArrayInputStream(t.toLittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(t.toULittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(u.toRawBits().toLittle()), outputStream)
}
wb(PAYLOAD_FOOTER)
// FlTP payload
wb(PAYLOAD_HEADER); wb("FlTP".toByteArray())
wi48(world.fluidTypes.size * 8L)
world.fluidTypes.forEach { t, u ->
Lzma.compress(ByteArrayInputStream(t.toULittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(u.value.toLittleShort()), outputStream)
}
wb(PAYLOAD_FOOTER)
// FlFL payload
wb(PAYLOAD_HEADER); wb("FlFL".toByteArray())
wi48(world.fluidFills.size * 10L)
world.fluidFills.forEach { t, u ->
Lzma.compress(ByteArrayInputStream(t.toULittle48()), outputStream)
Lzma.compress(ByteArrayInputStream(u.toRawBits().toLittle()), outputStream)
}
wb(PAYLOAD_FOOTER)
// write footer
wb(FILE_FOOTER)

View File

@@ -1,18 +1,14 @@
package net.torvald.terrarum.serialise
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.EchoError
import net.torvald.terrarum.realestate.LandUtil
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.charset.Charset
import java.util.zip.Deflater
import java.util.zip.DeflaterOutputStream
import java.util.zip.GZIPOutputStream
/**
* This object only writes a file named 'worldinfo1'.
@@ -39,10 +35,11 @@ internal object WriteLayerDataZip {
val LAYERS_FILENAME = "world"
val MAGIC = byteArrayOf(0x54, 0x45, 0x4D, 0x7A)
val VERSION_NUMBER = 3.toByte()
val VERSION_NUMBER = WORLD_WRITER_FORMAT_VERSION.toByte()
val NUMBER_OF_LAYERS = 3.toByte()
val NUMBER_OF_PAYLOADS = 5.toByte()
val COMPRESSION_ALGORITHM = 1.toByte()
val GENERATOR_VERSION = WORLD_GENERATOR_VERSION.toULittleShort()
val PAYLOAD_HEADER = byteArrayOf(0, 0x70, 0x4C, 0x64)
val PAYLOAD_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x50, 0x59, 0x4C, 0x64, -1)
val FILE_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x54, 0x45, 0x4D, -1, -2)
@@ -83,7 +80,7 @@ internal object WriteLayerDataZip {
fun wb(byte: Byte) { outputStream.write(byte.toInt()) }
//fun wb(byte: Int) { outputStream.write(byte) }
fun wi32(int: Int) { wb(int.toLittle()) }
fun wi48(long: Long) { wb(long.toLittle48()) }
fun wi48(long: Long) { wb(long.toULittle48()) }
fun wi64(long: Long) { wb(long.toLittle()) }
fun wf32(float: Float) { wi32(float.toRawBits()) }
@@ -94,7 +91,7 @@ internal object WriteLayerDataZip {
// all the necessary headers
wb(MAGIC); wb(VERSION_NUMBER); wb(NUMBER_OF_LAYERS); wb(NUMBER_OF_PAYLOADS); wb(COMPRESSION_ALGORITHM)
wb(MAGIC); wb(VERSION_NUMBER); wb(NUMBER_OF_LAYERS); wb(NUMBER_OF_PAYLOADS); wb(COMPRESSION_ALGORITHM); wb(GENERATOR_VERSION)
// world width, height, and spawn point
wi32(world.width); wi32(world.height)
@@ -134,12 +131,12 @@ internal object WriteLayerDataZip {
// TdMG payload
wb(PAYLOAD_HEADER); wb("TdMG".toByteArray())
wi48(world.terrainDamages.size.toLong())
wi48(world.terrainDamages.size * 10L)
deflater = DeflaterOutputStream(outputStream, Deflater(Deflater.BEST_COMPRESSION), true)
world.terrainDamages.forEach { t, u ->
deflater.write(t.toLittle48())
deflater.write(t.toULittle48())
deflater.write(u.toRawBits().toLittle())
}
@@ -148,18 +145,49 @@ internal object WriteLayerDataZip {
// WdMG payload
wb(PAYLOAD_HEADER); wb("WdMG".toByteArray())
wi48(world.wallDamages.size.toLong())
wi48(world.wallDamages.size * 10L)
deflater = DeflaterOutputStream(outputStream, Deflater(Deflater.BEST_COMPRESSION), true)
world.wallDamages.forEach { t, u ->
deflater.write(t.toLittle48())
deflater.write(t.toULittle48())
deflater.write(u.toRawBits().toLittle())
}
deflater.finish()
wb(PAYLOAD_FOOTER)
// FlTP payload
wb(PAYLOAD_HEADER); wb("FlTP".toByteArray())
wi48(world.fluidTypes.size * 8L)
deflater = DeflaterOutputStream(outputStream, Deflater(Deflater.BEST_COMPRESSION), true)
world.fluidTypes.forEach { t, u ->
deflater.write(t.toULittle48())
deflater.write(u.value.toLittleShort())
}
deflater.finish()
wb(PAYLOAD_FOOTER)
// FlFL payload
wb(PAYLOAD_HEADER); wb("FlFL".toByteArray())
wi48(world.fluidFills.size * 10L)
deflater = DeflaterOutputStream(outputStream, Deflater(Deflater.BEST_COMPRESSION), true)
world.fluidFills.forEach { t, u ->
deflater.write(t.toULittle48())
deflater.write(u.toRawBits().toLittle())
}
deflater.finish()
wb(PAYLOAD_FOOTER)
// write footer
wb(FILE_FOOTER)

View File

@@ -1,10 +1,8 @@
package net.torvald.terrarum.serialise
import com.badlogic.gdx.Gdx
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.modulebasegame.gameactors.PlayerBuilder
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
@@ -101,11 +99,11 @@ object WriteWorldInfo {
metaOut.write((world as GameWorldExtension).time.TIME_T.toLittle())
// creation time (real world time)
metaOut.write(world.creationTime.toLittle48())
metaOut.write(world.creationTime.toULittle48())
// time at save (real world time)
val timeNow = System.currentTimeMillis() / 1000L
metaOut.write(timeNow.toLittle48())
metaOut.write(timeNow.toULittle48())
// get playtime and save it
val timeToAdd = (timeNow - world.loadTime).toInt()

View File

@@ -8,7 +8,7 @@ Ord Hex Description
02 4D M
03 7A z # 'z' because it's compressed
04 03 Version revision number (unreleased numbers also count)
04 03 Version revision number of this format (unreleased numbers also count)
05 03 Number of layers, NOT the number of payload
@@ -17,22 +17,25 @@ Ord Hex Description
07 01 Compression algorithm, 0 for none, 1 for DEFLATE, 2 for LZMA, otherwise undefined (maybe LZMA2 for the future?)
Value of 01 (DEFLATE) is recommended for its faster compression
08 World width
09 World width
08 World generator version. If the generator adds new feature (e.g. new ores, new buildings)
09 this number must be incremented by one.
0A World width
0B World width
0C World width
0D World width
0C World height
0D World height
0E World height
0F World height
10 World height
11 World height
10 Default spawn coord in Absolute Tile Number
11 Default spawn coord in Absolute Tile Number
12 Default spawn coord in Absolute Tile Number
13 Default spawn coord in Absolute Tile Number
14 Default spawn coord in Absolute Tile Number
15 Default spawn coord in Absolute Tile Number
16 Default spawn coord in Absolute Tile Number
17 Default spawn coord in Absolute Tile Number
# Payload
#
@@ -62,6 +65,13 @@ Payload "TdMG" -- world terrain damage data, array of: (Int48 tileAddress, Float
Payload "WdMG" -- world walls damage data, array of: (Int48 tileAddress, Float32 damage)
Uncompressed size will be arbitrary (multiple of tens)
Payload "FlTP" -- world fluid types, array of: (Int48 tileAddress, Signed Int16 type)
Uncompressed size will be arbitrary (multiple of eights)
Payload "FlFL" -- world fluid fills, array of: (Int48 tileAddress, Float32 amount)
Uncompressed size will be arbitrary (multiple of tens)
If the 'amount' < 0.0001f (WorldSimulator.FLUID_MIN_MASS), the entry must be discarded
EOF 45 E
EOF 6E n
EOF 64 d