payloadutil and unhelpful commit message

This commit is contained in:
minjaesong
2019-02-20 22:43:35 +09:00
parent c9ac844e75
commit 1906cff519
8 changed files with 200 additions and 92 deletions

View File

@@ -21,6 +21,11 @@ data class Point2d(var x: Double, var y: Double) : Cloneable {
this.y = other.y
}
fun setCoerceIn(start: Point2d, endInclusive: Point2d) {
x = x.coerceIn(start.x, endInclusive.x)
y = y.coerceIn(start.y, endInclusive.y)
}
/**
* Rotate transform this point, with pivot (0, 0)
* @return new Point2d that is rotated

View File

@@ -45,13 +45,13 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double, var suppress
/**
* @return bottom-centered point of hitbox.
*/
val canonicalY: Double
get() = hitboxEnd.y
inline val canonicalY: Double
get() = endY
val endX: Double
get() = hitboxEnd.x
get() = hitboxStart.x + width
val endY: Double
get() = hitboxEnd.y
get() = hitboxStart.y + height
/**
* Set to the point top left
@@ -131,10 +131,10 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double, var suppress
get() = hitboxStart.y
val centeredX: Double
get() = (hitboxStart.x + hitboxEnd.x) * 0.5
get() = hitboxStart.x + width * 0.5
val centeredY: Double
get() = (hitboxStart.y + hitboxEnd.y) * 0.5
get() = hitboxStart.y + height * 0.5
infix fun intersects(position: Point2d) =
(position.x >= startX && position.x <= startX + width) &&

View File

@@ -17,12 +17,21 @@ import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
import net.torvald.terrarum.modulebasegame.ui.Notification
import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.serialise.WriteLayerDataZip.FILE_FOOTER
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_FOOTER
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_HEADER
import net.torvald.terrarum.serialise.toLittle
import net.torvald.terrarum.serialise.toLittleShort
import net.torvald.terrarum.serialise.toULittle48
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UINSMenu
import net.torvald.terrarum.worlddrawer.FeaturesDrawer.TILE_SIZE
import net.torvald.terrarum.worlddrawer.LightmapRenderer
import net.torvald.terrarum.worlddrawer.WorldCamera
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.io.File
import java.io.FileOutputStream
/**
* Created by minjaesong on 2018-07-06.
@@ -74,8 +83,15 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
println("[BuildingMaker] Generating builder world...")
for (y in 0 until gameWorld.height) {
gameWorld.setTileWall(0, y, Block.ILLUMINATOR_RED)
gameWorld.setTileWall(gameWorld.width - 1, y, Block.ILLUMINATOR_RED)
gameWorld.setTileTerrain(0, y, Block.ILLUMINATOR_RED_OFF)
gameWorld.setTileTerrain(gameWorld.width - 1, y, Block.ILLUMINATOR_RED_OFF)
}
for (y in 150 until gameWorld.height) {
for (x in 0 until gameWorld.width) {
for (x in 1 until gameWorld.width - 1) {
// wall layer
gameWorld.setTileWall(x, y, Block.DIRT)
@@ -91,7 +107,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
}
override var actorNowPlaying: ActorHumanoid? = MovableWorldCamera()
override var actorNowPlaying: ActorHumanoid? = MovableWorldCamera(this)
val uiToolbox = UINSMenu("Menu", 100, menuYaml)
val notifier = Notification()
@@ -439,7 +455,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
return selection.last() - selection.first()
}
private fun serialiseSelection() {
private fun serialiseSelection(outfile: File) {
// save format: sparse list encoded in following binary format:
/*
Header: TEaT0bLD -- magic: Terrarum Attachment
@@ -451,12 +467,37 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
The rest: payloads defined in the map data format
Payloads: array of (Int48 tileAddress, UInt16 blockID)
Payload names: TerL, WalL, WirL for Terrain, Wall and Wire respectively
Footer: EndAtC \xFF\xFE -- magic: end of attachment with BOM
Footer: EndTEM \xFF\xFE -- magic: end of attachment with BOM
Endian: LITTLE
*/
// proc:
// translate boxes so that leftmost point is (0,0)
// write to the list using translated coords
val payloads = arrayOf("WalL", "TerL", "WirL")
val selectionDim = getSelectionTotalDimension()
val fos = FileOutputStream(outfile)
// write header
fos.write("TEaT0bLD".toByteArray())
fos.write(byteArrayOf(1,3,3,1))
fos.write(selectionDim.x.toLittleShort())
// write wall -> terrain -> wire (order defined in GameWorld.TERRAIN/WALL/WIRE)
payloads.forEachIndexed { index, it ->
fos.write(PAYLOAD_HEADER); fos.write(it.toByteArray())
selection.forEach {
val tile = world.getTileFrom(index, it.x, it.y)!!
val addr = LandUtil.getBlockAddr(world, it.x - selectionDim.x, it.y - selectionDim.y)
fos.write(addr.toULittle48())
fos.write(tile.toLittle())
}
fos.write(PAYLOAD_FOOTER)
}
fos.write(FILE_FOOTER)
fos.close()
}
}
@@ -503,7 +544,7 @@ class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() {
}
}
class MovableWorldCamera : ActorHumanoid(0, usePhysics = false) {
class MovableWorldCamera(val parent: BuildingMaker) : ActorHumanoid(0, usePhysics = false) {
init {
referenceID = Terrarum.PLAYER_REF_ID
@@ -520,6 +561,22 @@ class MovableWorldCamera : ActorHumanoid(0, usePhysics = false) {
actorValue[AVKey.FRICTIONMULT] = 4.0
}
// TODO resize-aware
private var coerceInStart = Point2d(
(Terrarum.WIDTH - hitbox.width) / 2.0,
(Terrarum.HEIGHT - hitbox.height) / 2.0
)
private var coerceInEnd = Point2d(
parent.world.width * TILE_SIZE - (Terrarum.WIDTH - hitbox.width) / 2.0,
parent.world.height * TILE_SIZE - (Terrarum.HEIGHT - hitbox.height) / 2.0
)
override fun update(delta: Float) {
super.update(delta)
// confine the camera so it won't wrap
this.hitbox.hitboxStart.setCoerceIn(coerceInStart, coerceInEnd)
}
override fun drawBody(batch: SpriteBatch) {
}

View File

@@ -0,0 +1,114 @@
package net.torvald.terrarum.serialise
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.serialise.WriteLayerDataZip.FILE_FOOTER
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_FOOTER
import net.torvald.terrarum.toHex
import java.nio.charset.Charset
import java.util.*
/**
* Created by minjaesong on 2019-02-20.
*/
object PayloadUtil {
/**
* InputStream must be located manually at the payload begin
*
* For the actual use case, take a look at the source of the [ReadLayerDataZip].
*/
fun readAll(inputStream: MarkableFileInputStream, footer: ByteArray = FILE_FOOTER): HashMap<String, TEMzPayload> {
val pldBuffer4 = ByteArray(4)
val pldBuffer6 = ByteArray(6)
val pldBuffer8 = ByteArray(8)
val payloads = HashMap<String, TEMzPayload>()
var pldCnt = 1
while (true) {
// read header and get payload's name
inputStream.read(pldBuffer8)
// check if end of payload reached
if (pldBuffer8.contentEquals(footer)) {
break
}
val payloadName = pldBuffer8.copyOfRange(4, 8).toString(Charset.forName("US-ASCII"))
AppLoader.printdbg(this, "Payload $pldCnt name: $payloadName") // maybe maybe related with buffer things?
// get uncompressed size
inputStream.read(pldBuffer6)
val uncompressedSize = pldBuffer6.toLittleInt48()
// get deflated size
inputStream.mark(2147483647) // FIXME deflated stream cannot be larger than 2 GB
// creep forward until we hit the PAYLOAD_FOOTER
var compressedSize: Int = 0 // FIXME deflated stream cannot be larger than 2 GB
// loop init
inputStream.read(pldBuffer8)
// loop main
while (!pldBuffer8.contentEquals(PAYLOAD_FOOTER)) {
val aByte = inputStream.read(); compressedSize += 1
if (aByte == -1) throw InternalError("Unexpected end-of-file at payload $pldCnt")
pldBuffer8.shiftLeftBy(1, aByte.toByte())
}
// at this point, we should have correct size of deflated bytestream
AppLoader.printdbg(this, "Payload $pldCnt compressed size: $compressedSize")
val compressedBytes = ByteArray(compressedSize) // FIXME deflated stream cannot be larger than 2 GB
inputStream.reset() // go back to marked spot
inputStream.read(compressedBytes)
// PRO Debug tip: every deflated bytes must begin with 0x789C or 0x78DA
// Thus, \0pLd + [10] must be either of these.
// put constructed payload into a container
payloads.put(payloadName, TEMzPayload(uncompressedSize, compressedBytes))
// skip over to be aligned with the next payload
inputStream.skip(8)
pldCnt += 1
}
return payloads
}
private fun ByteArray.shiftLeftBy(size: Int, fill: Byte = 0.toByte()) {
if (size == 0) {
return
}
else if (size < 0) {
throw IllegalArgumentException("This won't shift to right (size = $size)")
}
else if (size >= this.size) {
Arrays.fill(this, 0.toByte())
}
else {
for (c in size..this.lastIndex) {
this[c - size] = this[c]
}
for (c in (this.size - size)..this.lastIndex) {
this[c] = fill
}
}
}
private fun ByteArray.toByteString(): String {
val sb = StringBuilder()
this.forEach {
sb.append(it.toUint().toHex().takeLast(2))
sb.append(' ')
}
sb.deleteCharAt(sb.lastIndex)
return sb.toString()
}
data class TEMzPayload(val uncompressedSize: Long, val bytes: ByteArray) // FIXME deflated stream cannot be larger than 2 GB
}

View File

@@ -8,9 +8,7 @@ import net.torvald.terrarum.gameworld.MapLayer
import net.torvald.terrarum.gameworld.PairedMapLayer
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.collections.HashMap
@@ -60,7 +58,8 @@ internal object ReadLayerDataLzma {
// read payloads
val pldBuffer4 = ByteArray(4)
val payloads = PayloadUtil.readAll(inputStream)
/*val pldBuffer4 = ByteArray(4)
val pldBuffer6 = ByteArray(6)
val pldBuffer8 = ByteArray(8)
@@ -121,7 +120,7 @@ internal object ReadLayerDataLzma {
// test for EOF
inputStream.read(pldBuffer8)
if (!pldBuffer8.contentEquals(WriteLayerDataZip.FILE_FOOTER))
throw InternalError("Expected end-of-file, got not-so-end-of-file")
throw InternalError("Expected end-of-file, got not-so-end-of-file")*/
//////////////////////
@@ -199,8 +198,6 @@ internal object ReadLayerDataLzma {
)
}
private data class TEMzPayload(val uncompressedSize: Long, val bytes: ByteArray) // FIXME deflated stream cannot be larger than 2 GB
/**
* Immediately deployable, a part of the gameworld
*/
@@ -221,27 +218,6 @@ internal object ReadLayerDataLzma {
val fluidFills: HashMap<BlockAddress, Float>
)
private fun ByteArray.shiftLeftBy(size: Int, fill: Byte = 0.toByte()) {
if (size == 0) {
return
}
else if (size < 0) {
throw IllegalArgumentException("This won't shift to right (size = $size)")
}
else if (size >= this.size) {
Arrays.fill(this, 0.toByte())
}
else {
for (c in size..this.lastIndex) {
this[c - size] = this[c]
}
for (c in (this.size - size)..this.lastIndex) {
this[c] = fill
}
}
}
internal fun InputStream.readRelative(b: ByteArray, off: Int, len: Int): Int {
if (b == null) {
throw NullPointerException()
@@ -272,14 +248,4 @@ internal object ReadLayerDataLzma {
return i
}
fun ByteArray.toByteString(): String {
val sb = StringBuilder()
this.forEach {
sb.append(it.toUint().toHex().takeLast(2))
sb.append(' ')
}
sb.deleteCharAt(sb.lastIndex)
return sb.toString()
}
}

View File

@@ -6,12 +6,10 @@ import net.torvald.terrarum.gameworld.MapLayer
import net.torvald.terrarum.gameworld.PairedMapLayer
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.DiskSkimmer.Companion.read
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.toHex
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.collections.HashMap
@@ -62,7 +60,8 @@ internal object ReadLayerDataZip {
// read payloads
val pldBuffer4 = ByteArray(4)
val payloads = PayloadUtil.readAll(inputStream)
/*val pldBuffer4 = ByteArray(4)
val pldBuffer6 = ByteArray(6)
val pldBuffer8 = ByteArray(8)
@@ -123,7 +122,7 @@ internal object ReadLayerDataZip {
// test for EOF
inputStream.read(pldBuffer8)
if (!pldBuffer8.contentEquals(WriteLayerDataZip.FILE_FOOTER))
throw InternalError("Expected end-of-file, got not-so-end-of-file")
throw InternalError("Expected end-of-file, got not-so-end-of-file")*/
//////////////////////
@@ -194,8 +193,6 @@ internal object ReadLayerDataZip {
)
}
private data class TEMzPayload(val uncompressedSize: Long, val bytes: ByteArray) // FIXME deflated stream cannot be larger than 2 GB
/**
* Immediately deployable, a part of the gameworld
*/
@@ -214,27 +211,6 @@ internal object ReadLayerDataZip {
val terrainDamages: HashMap<BlockAddress, Float>
)
private fun ByteArray.shiftLeftBy(size: Int, fill: Byte = 0.toByte()) {
if (size == 0) {
return
}
else if (size < 0) {
throw IllegalArgumentException("This won't shift to right (size = $size)")
}
else if (size >= this.size) {
Arrays.fill(this, 0.toByte())
}
else {
for (c in size..this.lastIndex) {
this[c - size] = this[c]
}
for (c in (this.size - size)..this.lastIndex) {
this[c] = fill
}
}
}
internal fun InputStream.readRelative(b: ByteArray, off: Int, len: Int): Int {
if (b == null) {
throw NullPointerException()
@@ -265,14 +241,4 @@ internal object ReadLayerDataZip {
return i
}
fun ByteArray.toByteString(): String {
val sb = StringBuilder()
this.forEach {
sb.append(it.toUint().toHex().takeLast(2))
sb.append(' ')
}
sb.deleteCharAt(sb.lastIndex)
return sb.toString()
}
}
}

View File

@@ -4,6 +4,9 @@ import com.badlogic.gdx.utils.compression.Lzma
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.realestate.LandUtil
import net.torvald.terrarum.serialise.WriteLayerDataZip.FILE_FOOTER
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_FOOTER
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_HEADER
import java.io.*
import java.util.zip.DeflaterOutputStream
@@ -35,9 +38,6 @@ internal object WriteLayerDataLzma {
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)
//val NULL: Byte = 0

View File

@@ -40,9 +40,9 @@ internal object WriteLayerDataZip {
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)
val PAYLOAD_HEADER = byteArrayOf(0, 0x70, 0x4C, 0x64) // \0pLd
val PAYLOAD_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x50, 0x59, 0x4C, 0x64, -1) // EndPYLd\xFF
val FILE_FOOTER = byteArrayOf(0x45, 0x6E, 0x64, 0x54, 0x45, 0x4D, -1, -2) // EndTEM with BOM
//val NULL: Byte = 0