diff --git a/common/src/main/scala/hexacraft/util/SmartArray.scala b/common/src/main/scala/hexacraft/util/SmartArray.scala index 750289aa..c0975907 100644 --- a/common/src/main/scala/hexacraft/util/SmartArray.scala +++ b/common/src/main/scala/hexacraft/util/SmartArray.scala @@ -1,5 +1,6 @@ package hexacraft.util +import java.util import scala.collection.mutable class SmartArray[@specialized(Byte) T](size: Int, default: T, builder: Int => Array[T]) extends mutable.IndexedSeq[T] { @@ -16,8 +17,11 @@ class SmartArray[@specialized(Byte) T](size: Int, default: T, builder: Int => Ar def update(idx: Int, value: T): Unit = { if arr == null && value != default then { arr = builder(size) - for i <- 0 until size do { + + var i = 0 + while i < size do { arr(i) = default + i += 1 } } diff --git a/game/src/main/scala/hexacraft/world/HexBox.scala b/game/src/main/scala/hexacraft/world/HexBox.scala index 68b18ca7..f3ba6f11 100644 --- a/game/src/main/scala/hexacraft/world/HexBox.scala +++ b/game/src/main/scala/hexacraft/world/HexBox.scala @@ -7,6 +7,7 @@ import hexacraft.world.coord.{BlockCoords, BlockRelWorld, CoordUtils, CylCoords} import org.joml.Vector3dc import scala.annotation.tailrec +import scala.collection.mutable /** radius is the big radius of the hexagon */ class HexBox(val radius: Float, val bottom: Float, val top: Float) { @@ -26,17 +27,22 @@ class HexBox(val radius: Float, val bottom: Float, val top: Float) { } def vertices: IndexedSeq[CylCoords.Offset] = { - // val ints = Seq(1, 2, 0, 3, 5, 4) - - for { - s <- 0 to 1 - i <- 0 until 6 - } yield { - val v = i * Math.PI / 3 - val x = Math.cos(v).toFloat - val z = Math.sin(v).toFloat - CylCoords.Offset(x * radius, (1 - s) * (top - bottom) + bottom, z * radius) + val result = new mutable.ArrayBuffer[CylCoords.Offset](12) + + var s = 0 + while s < 2 do { + var i = 0 + while i < 6 do { + val v = i * Math.PI / 3 + val x = Math.cos(v).toFloat + val z = Math.sin(v).toFloat + + result += CylCoords.Offset(x * radius, (1 - s) * (top - bottom) + bottom, z * radius) + i += 1 + } + s += 1 } + result.toIndexedSeq } /** Returns all blocks spaces that would intersect with this HexBox when placed at the given position */ @@ -44,16 +50,25 @@ class HexBox(val radius: Float, val bottom: Float, val top: Float) { val yLo = math.floor((pos.y + this.bottom) * 2).toInt val yHi = math.floor((pos.y + this.top) * 2).toInt - // TODO: improve this implementation to be more correct (the HexBox radius might be too big) - for { - y <- yLo to yHi - dx <- -1 to 1 - dz <- -1 to 1 - if dx * dz != 1 // remove corners - } yield { - val origin = pos.toBlockCoords.offset(dx, 0, dz) - CoordUtils.getEnclosingBlock(BlockCoords(origin.x, y, origin.z))._1 + val result = mutable.ArrayBuffer.empty[BlockRelWorld] + + var y = yLo + while y <= yHi do { + // TODO: improve this implementation to be more correct (the HexBox radius might be too big) + var i = 0 + while i < 9 do { + val dx = (i % 3) - 1 + val dz = (i / 3) - 1 + + if dx * dz != 1 then { // remove corners + val origin = pos.toBlockCoords.offset(dx, 0, dz) + result += CoordUtils.getEnclosingBlock(BlockCoords(origin.x, y, origin.z))._1 + } + i += 1 + } + y += 1 } + result.toSeq } } diff --git a/game/src/main/scala/hexacraft/world/LightPropagator.scala b/game/src/main/scala/hexacraft/world/LightPropagator.scala index 68e27e54..907e8e43 100644 --- a/game/src/main/scala/hexacraft/world/LightPropagator.scala +++ b/game/src/main/scala/hexacraft/world/LightPropagator.scala @@ -3,7 +3,7 @@ package hexacraft.world import hexacraft.math.MathUtils.oppositeSide import hexacraft.world.block.BlockState import hexacraft.world.chunk.{Chunk, LocalBlockState} -import hexacraft.world.coord.{BlockRelChunk, BlockRelWorld, ChunkRelWorld, NeighborOffsets} +import hexacraft.world.coord.{BlockRelChunk, BlockRelWorld, ChunkRelWorld} import scala.collection.mutable @@ -13,31 +13,33 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = def initBrightnesses(chunkCoords: ChunkRelWorld, chunk: Chunk): Unit = { chunkCache.clearCache() - val lights = mutable.HashMap.empty[BlockRelChunk, BlockState] - - for - LocalBlockState(c, b) <- chunk.blocks - if b.blockType.lightEmitted != 0 - do lights(c) = b - val queueTorch = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)] val queueSun15 = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)] val queueSunFromNeighbor = mutable.Queue.empty[(BlockRelChunk, ChunkRelWorld, Chunk)] - for ((c, b) <- lights) { - chunk.lighting.setTorchlight(c, b.blockType.lightEmitted) - queueTorch += ((c, chunkCoords, chunk)) + val blocks = chunk.blocks + var cIdx = 0 + while cIdx < blocks.length do { + val LocalBlockState(c, b) = blocks(cIdx) + + if b.blockType.lightEmitted != 0 then { + chunk.lighting.setTorchlight(c, b.blockType.lightEmitted) + queueTorch += ((c, chunkCoords, chunk)) + } + cIdx += 1 } def shouldEnqueueSunlight(coords: BlockRelChunk, neighCoords: ChunkRelWorld, neigh: Chunk) = { val block = neigh.getBlock(coords) val neighCol = world.getColumn(neighCoords.getColumnRelWorld).get if neighCoords.Y.toInt * 16 + coords.cy > neighCol.terrainHeight.getHeight(coords.cx, coords.cz) - then + then { val transparentTop = !block.blockType.isCovering(block.metadata, 0) || block.blockType.isTransmissive val transparentBottom = !block.blockType.isCovering(block.metadata, 1) || block.blockType.isTransmissive transparentTop && transparentBottom - else false + } else { + false + } } def handleEdge(x: Int, y: Int, z: Int) = { @@ -70,15 +72,19 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = } } - for s <- -1 to 16 do { - for t <- -1 to 16 do { + var s = -1 + while s <= 16 do { + var t = -1 + while t <= 16 do { handleEdge(-1, s, t) handleEdge(16, s, t) handleEdge(s, -1, t) handleEdge(s, 16, t) handleEdge(s, t, -1) handleEdge(s, t, 16) + t += 1 } + s += 1 } propagateTorchlight(queueTorch) @@ -119,7 +125,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunksNeedingRenderUpdate += chunkCoords - for s <- NeighborOffsets.indices do { + var s = 0 + while s < 8 do { val c2w = here.globalNeighbor(s, chunkCoords) val c2 = c2w.getBlockRelChunk val neighCoords = c2w.getChunkRelWorld @@ -137,6 +144,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue } } + s += 1 } } @@ -155,7 +163,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunksNeedingRenderUpdate += chunkCoords - for s <- NeighborOffsets.indices do { + var s = 0 + while s < 8 do { val c2w = here.globalNeighbor(s, chunkCoords) val c2 = c2w.getBlockRelChunk val neighCoords = c2w.getChunkRelWorld @@ -173,6 +182,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue } } + s += 1 } } @@ -191,7 +201,8 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = if nextLevel > 0 then { chunksNeedingRenderUpdate += chunkCoords - for s <- NeighborOffsets.indices do { + var s = 0 + while s < 8 do { val c2w = here.globalNeighbor(s, chunkCoords) val c2 = c2w.getBlockRelChunk val neighCoords = c2w.getChunkRelWorld @@ -208,6 +219,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunksNeedingRenderUpdate += neighCoords // the if-case above gets handled later since it's in the queue } } + s += 1 } } } @@ -231,7 +243,9 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = val thisQueue = chunksToProcess.remove(chunkCoords).get val map = propagateSunlightInChunk(chunkCoords, chunk, thisQueue) - for chunkCoords <- map.keysIterator do { + val cIt = map.keysIterator + while cIt.hasNext do { + val chunkCoords = cIt.next() chunksToProcess.getOrElseUpdate(chunkCoords, mutable.Queue.empty).enqueueAll(map(chunkCoords)) chunksNeedingRenderUpdate += chunkCoords } @@ -245,7 +259,7 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = chunkCoords: ChunkRelWorld, chunk: Chunk, queue: mutable.Queue[Int] - ): Map[ChunkRelWorld, Seq[Int]] = { + ): collection.Map[ChunkRelWorld, Seq[Int]] = { val neighborMap: mutable.Map[ChunkRelWorld, mutable.ArrayBuffer[Int]] = mutable.Map.empty val inQueue: java.util.BitSet = new java.util.BitSet(16 * 16 * 16) @@ -305,6 +319,12 @@ class LightPropagator(world: BlocksInWorld, requestRenderUpdate: ChunkRelWorld = } } - neighborMap.view.mapValues(_.toSeq).toMap + val result = mutable.HashMap.empty[ChunkRelWorld, Seq[Int]] + val kIt = neighborMap.iterator + while kIt.hasNext do { + val (coords, blocks) = kIt.next() + result += coords -> blocks.toSeq + } + result } } diff --git a/game/src/main/scala/hexacraft/world/chunk/storage.scala b/game/src/main/scala/hexacraft/world/chunk/storage.scala index ac4428ae..b7d334c8 100644 --- a/game/src/main/scala/hexacraft/world/chunk/storage.scala +++ b/game/src/main/scala/hexacraft/world/chunk/storage.scala @@ -65,11 +65,13 @@ final class DenseChunkStorage extends ChunkStorage { def allBlocks: Array[LocalBlockState] = { val arr = Array.ofDim[LocalBlockState](_numBlocks) var idx = 0 - for i <- blockTypes.indices do { + var i = 0 + while i < blockTypes.length do { if blockTypes(i) != 0 then { arr(idx) = LocalBlockState(BlockRelChunk(i), new BlockState(Block.byId(blockTypes(i)), metadata(i))) idx += 1 } + i += 1 } arr }