From 4c9db1ef60ee33330b9f5159322665a4bff32aeb Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 25 Oct 2024 11:30:50 +0900 Subject: [PATCH] more chunkpool stuffs --- .../gameworld/BlockLayerFluidI16F16.kt | 89 +++++------------- .../terrarum/gameworld/BlockLayerOresI16I8.kt | 92 ++++--------------- .../torvald/terrarum/gameworld/ChunkPool.kt | 25 ++++- 3 files changed, 63 insertions(+), 143 deletions(-) diff --git a/src/net/torvald/terrarum/gameworld/BlockLayerFluidI16F16.kt b/src/net/torvald/terrarum/gameworld/BlockLayerFluidI16F16.kt index 852b5cd12..d5035d020 100644 --- a/src/net/torvald/terrarum/gameworld/BlockLayerFluidI16F16.kt +++ b/src/net/torvald/terrarum/gameworld/BlockLayerFluidI16F16.kt @@ -38,7 +38,7 @@ class BlockLayerFluidI16F16 : BlockLayer { this.width = width this.height = height - chunkPool = ChunkPool(disk, layerNum, BlockLayerGenericI16.BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world)) + chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world)) } constructor( @@ -51,87 +51,41 @@ class BlockLayerFluidI16F16 : BlockLayer { this.width = width this.height = height - chunkPool = ChunkPool(disk, layerNum, BlockLayerGenericI16.BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world)) + chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, -1, ChunkPool.getRenameFunFluids(world)) } 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) + return unsafeGetTile1(x, y).first } internal fun unsafeGetTile1(x: Int, y: Int): Pair { - val offset = getOffset(x, y) - val lsb = ptr[offset] - val msb = ptr[offset + 1] - val hbits = (ptr[offset + 2].toUint() or ptr[offset + 3].toUint().shl(8)).toShort() - val fill = Float16.toFloat(hbits) - - return lsb.toUint() or msb.toUint().shl(8) to fill + val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) + return chunkPool.getTileI16F16(chunk, ox, oy) } override fun unsafeToBytes(x: Int, y: Int): ByteArray { - val offset = getOffset(x, y) - return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 3], ptr[offset + 2]) + val (tile, fill0) = unsafeGetTile1(x, y) + val fill = Float16.fromFloat(fill0).toUint() + return byteArrayOf( + ((tile ushr 8) and 255).toByte(), + (tile and 255).toByte(), + ((fill ushr 8) and 255).toByte(), + (fill and 255).toByte(), ) } internal fun unsafeSetTile(x: Int, y: Int, tile0: Int, fill: Float) { - val offset = getOffset(x, y) - val hbits = Float16.fromFloat(fill).toInt().and(0xFFFF) - - val tile = if (fill < FLUID_MIN_MASS) 0 else tile0 - - val lsb = tile.and(0xff).toByte() - val msb = tile.ushr(8).and(0xff).toByte() - - val hlsb = hbits.and(0xff).toByte() - val hmsb = hbits.ushr(8).and(0xff).toByte() - - ptr[offset] = lsb - ptr[offset + 1] = msb - ptr[offset + 2] = hlsb - ptr[offset + 3] = hmsb - + val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) + val fill = Float16.fromFloat(fill).toUint() + chunkPool.setTileRaw(chunk, ox, oy, tile0.and(65535) or fill.shl(16)) } override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) { - val offset = getOffset(x, y) - ptr[offset] = bytes[1] - ptr[offset + 1] = bytes[0] - ptr[offset + 2] = bytes[3] - ptr[offset + 3] = bytes[2] + val tile = bytes[1].toUint().shl(8) or bytes[0].toUint() + val fill = Float16.toFloat((bytes[3].toUint().shl(8) or bytes[2].toUint()).toShort()) + unsafeSetTile(x, y, tile, fill) } /** @@ -150,13 +104,14 @@ class BlockLayerFluidI16F16 : BlockLayer { fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height) override fun dispose() { - ptr.destroy() - App.printdbg(this, "BlockLayerI16F16 with ptr ($ptr) successfully freed") + chunkPool.dispose() } - override fun toString(): String = ptr.toString("BlockLayerI16F16") + override fun toString(): String = "BlockLayerI16F16 (${width}x$height)" companion object { @Transient val BYTES_PER_BLOCK = 4L + + private fun Short.toUint() = this.toInt().and(65535) } } diff --git a/src/net/torvald/terrarum/gameworld/BlockLayerOresI16I8.kt b/src/net/torvald/terrarum/gameworld/BlockLayerOresI16I8.kt index 0552d47f0..bb15b2aed 100644 --- a/src/net/torvald/terrarum/gameworld/BlockLayerOresI16I8.kt +++ b/src/net/torvald/terrarum/gameworld/BlockLayerOresI16I8.kt @@ -34,7 +34,7 @@ class BlockLayerOresI16I8 : BlockLayer { this.width = width this.height = height - chunkPool = ChunkPool(disk, layerNum, BlockLayerGenericI16.BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world)) + chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world)) } constructor( @@ -47,95 +47,44 @@ class BlockLayerOresI16I8 : BlockLayer { this.width = width this.height = height - chunkPool = ChunkPool(disk, layerNum, BlockLayerGenericI16.BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world)) + chunkPool = ChunkPool(disk, layerNum, BYTES_PER_BLOCK, world, 0, ChunkPool.getRenameFunOres(world)) } override val bytesPerBlock = BYTES_PER_BLOCK - internal val ptr: UnsafePtr = UnsafeHelper.allocate(width * height * bytesPerBlock) - - val ptrDestroyed: Boolean - get() = ptr.destroyed - - init { - ptr.fillWith(0) // there is no NOT-GENERATED for ores, keep it as 0 - } - - /** - * 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] - val placement = ptr[offset + 2] - - return lsb.toUint() + msb.toUint().shl(8) + return unsafeGetTile1(x, y).first } internal fun unsafeGetTile1(x: Int, y: Int): Pair { - val offset = getOffset(x, y) - val lsb = ptr[offset] - val msb = ptr[offset + 1] - val placement = ptr[offset + 2] - - return lsb.toUint() or msb.toUint().shl(8) to placement.toUint() + val (chunk, ox, oy) = chunkPool.worldXYChunkNumAndOffset(x, y) + return chunkPool.getTileI16I8(chunk, ox, oy) } override fun unsafeToBytes(x: Int, y: Int): ByteArray { - val offset = getOffset(x, y) - return byteArrayOf(ptr[offset + 1], ptr[offset + 0], ptr[offset + 2]) + val (tile, fill) = unsafeGetTile1(x, y) + return byteArrayOf( + ((tile ushr 8) and 255).toByte(), + (tile and 255).toByte(), + (fill and 255).toByte() + ) } internal fun unsafeSetTile(x: Int, y: Int, tile: Int, placement: 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 - ptr[offset + 2] = placement.toByte() -// } -// 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 or placement.shl(16)) } override fun unsafeSetTile(x: Int, y: Int, bytes: ByteArray) { - val offset = getOffset(x, y) - ptr[offset] = bytes[1] - ptr[offset + 1] = bytes[0] - ptr[offset + 2] = bytes[2] + val tile = bytes[1].toUint().shl(8) or bytes[0].toUint() + val placement = bytes[2].toUint() + unsafeSetTile(x, y, tile, placement) } internal fun unsafeSetTileKeepPlacement(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() - - ptr[offset] = lsb - ptr[offset + 1] = msb + val oldPlacement = unsafeGetTile1(x, y).second + unsafeSetTile(x, y, tile, oldPlacement) } /** @@ -154,11 +103,10 @@ class BlockLayerOresI16I8 : BlockLayer { fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height) override fun dispose() { - ptr.destroy() - App.printdbg(this, "BlockLayerI16I8 with ptr ($ptr) successfully freed") + chunkPool.dispose() } - override fun toString(): String = ptr.toString("BlockLayerI16I8") + override fun toString(): String = "BlockLayerI16I8 (${width}x$height)" companion object { @Transient val BYTES_PER_BLOCK = 3L diff --git a/src/net/torvald/terrarum/gameworld/ChunkPool.kt b/src/net/torvald/terrarum/gameworld/ChunkPool.kt index b34fef851..a9cd1a9d7 100644 --- a/src/net/torvald/terrarum/gameworld/ChunkPool.kt +++ b/src/net/torvald/terrarum/gameworld/ChunkPool.kt @@ -210,12 +210,17 @@ open class ChunkPool { } } - private fun fetchFromDisk(chunkNumber: Long) { + /** + * @return `unit` if IO operation was successful, `null` if failed (e.g. file not exists) + */ + private fun fetchFromDisk(chunkNumber: Long): Unit? { val fileName = chunkNumToFileNum(layerIndex, chunkNumber) // read data from the disk - if (disk is ClusteredFormatDOM) { + return if (disk is ClusteredFormatDOM) { Clustfile(disk, fileName).let { + if (!it.exists()) return@let null + val bytes = Common.unzip(it.readBytes()) val ptr = allocate(chunkNumber) UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size) @@ -224,13 +229,25 @@ open class ChunkPool { } else if (disk is DiskSkimmer) { val fileID = fileName.toLong() - disk.getFile(fileID)!!.let { + disk.getFile(fileID).let { + if (it == null) return@let null + val bytes = Common.unzip(it.bytes) val ptr = allocate(chunkNumber) UnsafeHelper.memcpyFromArrToPtr(bytes, 0, ptr.ptr, bytes.size) renumber(ptr) } } + else { + throw IllegalStateException() + } + } + + /** + * @return `unit` if IO operation was successful, `null` if failed (e.g. file not exists) + */ + private fun createNewChunkFile(chunkNumber: Long): Unit? { + TODO() } private fun storeToDisk(chunkNumber: Long) { @@ -256,7 +273,7 @@ open class ChunkPool { private fun checkForChunk(chunkNumber: Long) { if (!pointers.containsKey(chunkNumber)) { - fetchFromDisk(chunkNumber) + fetchFromDisk(chunkNumber) ?: createNewChunkFile(chunkNumber) ?: TODO("handle IO error") } }