mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
payloadutil and unhelpful commit message
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
114
src/net/torvald/terrarum/serialise/PayloadUtil.kt
Normal file
114
src/net/torvald/terrarum/serialise/PayloadUtil.kt
Normal 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
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user