diff --git a/src/net/torvald/terrarum/serialise/ReadLayerData.kt b/src/net/torvald/terrarum/serialise/ReadLayerData.kt index 2d48c8357..5ab358e0b 100644 --- a/src/net/torvald/terrarum/serialise/ReadLayerData.kt +++ b/src/net/torvald/terrarum/serialise/ReadLayerData.kt @@ -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) \ No newline at end of file +fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this) + +const val WORLD_GENERATOR_VERSION = 1 diff --git a/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt b/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt index 38a36fd16..46e632f95 100644 --- a/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt +++ b/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt @@ -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 diff --git a/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt b/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt index 43eeeaf5c..9041c5daf 100644 --- a/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt +++ b/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt @@ -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 diff --git a/src/net/torvald/terrarum/serialise/WriteLayerData.kt b/src/net/torvald/terrarum/serialise/WriteLayerData.kt index b978b27dc..1c4b758f6 100644 --- a/src/net/torvald/terrarum/serialise/WriteLayerData.kt +++ b/src/net/torvald/terrarum/serialise/WriteLayerData.kt @@ -88,3 +88,5 @@ internal object WriteLayerData { } + +const val WORLD_WRITER_FORMAT_VERSION = 3 \ No newline at end of file diff --git a/src/net/torvald/terrarum/serialise/WriteLayerDataLzma.kt b/src/net/torvald/terrarum/serialise/WriteLayerDataLzma.kt index 4bc8329e9..1afd0addb 100644 --- a/src/net/torvald/terrarum/serialise/WriteLayerDataLzma.kt +++ b/src/net/torvald/terrarum/serialise/WriteLayerDataLzma.kt @@ -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) diff --git a/src/net/torvald/terrarum/serialise/WriteLayerDataZip.kt b/src/net/torvald/terrarum/serialise/WriteLayerDataZip.kt index ee21b4115..12c35ef46 100644 --- a/src/net/torvald/terrarum/serialise/WriteLayerDataZip.kt +++ b/src/net/torvald/terrarum/serialise/WriteLayerDataZip.kt @@ -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) diff --git a/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt b/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt index 847f762b8..593e6abb5 100644 --- a/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt +++ b/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt @@ -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() diff --git a/work_files/DataFormats/Map data format.txt b/work_files/DataFormats/Map data format.txt index a135052d4..54c162966 100644 --- a/work_files/DataFormats/Map data format.txt +++ b/work_files/DataFormats/Map data format.txt @@ -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