From 83906e7930d7bc0ae77c38c6df93ef28a3a7a8b2 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 22 Oct 2024 22:49:47 +0900 Subject: [PATCH] setTile on ChunkPool --- .../torvald/terrarum/gameworld/BlockLayer.kt | 4 +- .../gameworld/BlockLayerGenericI16.kt | 68 ++++--------------- .../torvald/terrarum/gameworld/ChunkPool.kt | 39 ++++++++++- 3 files changed, 53 insertions(+), 58 deletions(-) diff --git a/src/net/torvald/terrarum/gameworld/BlockLayer.kt b/src/net/torvald/terrarum/gameworld/BlockLayer.kt index 1051ebf4b..7bd639685 100644 --- a/src/net/torvald/terrarum/gameworld/BlockLayer.kt +++ b/src/net/torvald/terrarum/gameworld/BlockLayer.kt @@ -16,6 +16,6 @@ abstract class BlockLayer : Disposable { } -inline fun BlockLayer.getOffset(x: Int, y: Int): Long { +/*inline fun BlockLayer.getOffset(x: Int, y: Int): Long { return this.bytesPerBlock * (y * this.width + x) -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/BlockLayerGenericI16.kt b/src/net/torvald/terrarum/gameworld/BlockLayerGenericI16.kt index 8ffd29bc9..d6d2e99b6 100644 --- a/src/net/torvald/terrarum/gameworld/BlockLayerGenericI16.kt +++ b/src/net/torvald/terrarum/gameworld/BlockLayerGenericI16.kt @@ -61,70 +61,29 @@ class BlockLayerGenericI16: BlockLayer { }) } - override val bytesPerBlock = BYTES_PER_BLOCK - internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * bytesPerBlock) - - val ptrDestroyed: Boolean - get() = ptr.destroyed - - init { - ptr.fillWith(-1) - } - - /** - * Returns an iterator over stored bytes. - * - * @return an Iterator. - */ - fun bytesIterator(): Iterator { - return object : Iterator { - private var iteratorCount = 0L - override fun hasNext(): Boolean { - return iteratorCount < width * height * bytesPerBlock - } - override fun next(): Byte { - iteratorCount += 1 - return ptr[iteratorCount - 1] - } - } - } - override fun unsafeGetTile(x: Int, y: Int): Int { - val offset = getOffset(x, y) - val lsb = ptr[offset] - val msb = ptr[offset + 1] - - return lsb.toUint() or msb.toUint().shl(8) + val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) + return chunkPool.getTileI16(chunk, ox, oy) } override fun unsafeToBytes(x: Int, y: Int): ByteArray { - val offset = getOffset(x, y) - return byteArrayOf(ptr[offset + 1], ptr[offset + 0]) + val bytes = unsafeGetTile(x, y) + return byteArrayOf( + ((bytes ushr 8) and 255).toByte(), + (bytes and 255).toByte() + ) } internal fun unsafeSetTile(x: Int, y: Int, tile: Int) { - val offset = getOffset(x, y) - - val lsb = tile.and(0xff).toByte() - val msb = tile.ushr(8).and(0xff).toByte() - - -// try { - ptr[offset] = lsb - ptr[offset + 1] = msb -// } -// catch (e: IndexOutOfBoundsException) { -// printdbgerr(this, "IndexOutOfBoundsException: x = $x, y = $y; offset = $offset") -// throw e -// } + val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) + chunkPool.setTileRaw(chunk, ox, oy, tile) } override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) { - val offset = getOffset(x, y) - ptr[offset] = bytes[1] - ptr[offset + 1] = bytes[0] + val tile = (0..3).fold(0) { acc, i -> acc or (bytes[i].toUint()).shl(8*i) } + unsafeSetTile(x, y, tile) } /** @@ -143,11 +102,10 @@ class BlockLayerGenericI16: BlockLayer { fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height) override fun dispose() { - ptr.destroy() - printdbg(this, "BlockLayerI16 with ptr ($ptr) successfully freed") + chunkPool.dispose() } - override fun toString(): String = ptr.toString("BlockLayerI16") + override fun toString(): String = "BlockLayerI16 (${width}x$height)" companion object { @Transient val BYTES_PER_BLOCK = 2L diff --git a/src/net/torvald/terrarum/gameworld/ChunkPool.kt b/src/net/torvald/terrarum/gameworld/ChunkPool.kt index 31a8b2870..b34fef851 100644 --- a/src/net/torvald/terrarum/gameworld/ChunkPool.kt +++ b/src/net/torvald/terrarum/gameworld/ChunkPool.kt @@ -103,6 +103,9 @@ open class ChunkPool { return UnsafePtr(baseAddr, chunkSize) } + /** + * Returns a pointer and the offset from the pointer. The offset is given in bytes, but always word-aligned (if block offset is `(2, 0)`, the returning offset will be `8`, assuming word size of 4) + */ private fun createPointerViewOfChunk(chunkNumber: Long, offsetX: Int, offsetY: Int): Pair { val baseAddr = pointers[chunkNumber]!! return UnsafePtr(baseAddr, chunkSize) to wordSizeInBytes * (offsetY * CHUNK_W + offsetX) @@ -264,6 +267,19 @@ open class ChunkPool { return out } + fun worldXYChunkNumAndOffset(worldx: Int, worldy: Int): Triple { + val chunkX = worldx / CHUNK_W + val chunkY = worldy / CHUNK_H + val chunkOx = worldx % CHUNK_W + val chunkOy = worldy % CHUNK_H + + val chunkNum = LandUtil.chunkXYtoChunkNum(world, chunkX, chunkY) + return Triple(chunkNum, chunkOx, chunkOy) + } + + private fun updateAccessTime(chunkNumber: Long) { + allocMap.find { it?.chunkNumber == chunkNumber }!!.let { it.lastAccessTime = System.nanoTime() } + } /** * Given the word-aligned byte sequence of `[B0, B1, B2, B3, ...]`, @@ -274,7 +290,7 @@ open class ChunkPool { */ fun getTileRaw(chunkNumber: Long, offX: Int, offY: Int): Int { checkForChunk(chunkNumber) - allocMap.find { it?.chunkNumber == chunkNumber }!!.let { it.lastAccessTime = System.nanoTime() } + updateAccessTime(chunkNumber) val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY) val numIn = (0 until wordSizeInBytes.toInt()).fold(0) { acc, off -> acc or (ptr[ptrOff].toUint().shl(8 * off)) @@ -282,6 +298,23 @@ open class ChunkPool { return numIn } + /** + * Given the bytes of Int `B3_B2_B1_B0` + * Saved as: + * - word size is 4: `[B0, B1, B2, B3]` + * - word size is 3: `[B0, B1, B2]` (B3 is ignored) + * - word size is 2: `[B0, B1]` (B2 and B3 are ignored) + */ + fun setTileRaw(chunkNumber: Long, offX: Int, offY: Int, bytes: Int) { + checkForChunk(chunkNumber) + updateAccessTime(chunkNumber) + val (ptr, ptrOff) = createPointerViewOfChunk(chunkNumber, offX, offY) + for (i in 0 until wordSizeInBytes.toInt()) { + val b = bytes.ushr(8*i).and(255) + ptr[ptrOff + i] = b.toByte() + } + } + /** * Given the word-aligned byte sequence of `[B0, B1, B2, B3, ...]`, * Return format: @@ -319,6 +352,10 @@ open class ChunkPool { return ibits to jbits } + fun dispose() { + + } + companion object { fun chunkNumToFileNum(layerNum: Int, chunkNum: Long): String { val entryID = Common.layerAndChunkNumToEntryID(layerNum, chunkNum)