From 9aab2b1adcd9c6db7eb2e3951174f5e5377a9b21 Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Fri, 8 Jan 2021 17:46:56 +0100 Subject: [PATCH] Implement World.getVoxelsInSphere --- .../space/uranos/testplugin/TestPlugin.kt | 5 ++- .../uranos/testplugin/anvil/AnvilVoxel.kt | 6 ++-- .../src/main/kotlin/space/uranos/Vector.kt | 7 ++++- .../uranos/util/UntilPossiblyNegative.kt | 2 +- .../main/kotlin/space/uranos/world/World.kt | 31 ++++++++++++------- .../play/IncomingPlayerPositionPacketCodec.kt | 9 +++++- .../play/PlayerOrientationPacketCodec.kt | 3 +- .../kotlin/space/uranos/net/PacketsAdapter.kt | 2 +- 8 files changed, 42 insertions(+), 23 deletions(-) diff --git a/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt b/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt index 57be41d..09720d8 100644 --- a/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt +++ b/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt @@ -17,7 +17,6 @@ import space.uranos.testplugin.anvil.AnvilWorld import space.uranos.util.secondsToTicks import space.uranos.world.Dimension import space.uranos.world.VoxelLocation -import space.uranos.world.block.CraftingTableBlock import space.uranos.world.block.GreenWoolBlock import space.uranos.world.block.RedWoolBlock @@ -33,11 +32,11 @@ class TestPlugin: Plugin("Test", "1.0.0") { Uranos.dimensionRegistry.register(dimension) val world = AnvilWorld(dimension, true) - world.getVoxelsInCube(VoxelLocation.of(16, 0, 16), VoxelLocation.of(-16, 0, -16)).forEach { + world.getVoxelsInCuboid(VoxelLocation.of(16, 0, 16), VoxelLocation.of(-16, 0, -16)).forEach { it.block = if (it.location.x % 16 == 0 || it.location.z % 16 == 0) GreenWoolBlock() else RedWoolBlock() } - world.getVoxel(VoxelLocation.of(-1, 2, -1)).block = CraftingTableBlock() + world.getVoxelsInSphere(VoxelLocation.of(20, 50, 20), 40.0).forEach { it.block = RedWoolBlock() } Uranos.eventBus.on { event -> event.response = ServerListInfo("1.16.4", 754, TextComponent of "Test", 10, 0, emptyList()) diff --git a/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilVoxel.kt b/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilVoxel.kt index cf63934..de635c9 100644 --- a/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilVoxel.kt +++ b/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilVoxel.kt @@ -15,7 +15,7 @@ class AnvilVoxel( override val world: AnvilWorld ) : Voxel() { private val chunkX: Int - private val chunkY: UByte = location.y + private val sectionY: Int = location.y.toInt() % Chunk.SECTION_HEIGHT private val chunkZ: Int init { @@ -24,8 +24,8 @@ class AnvilVoxel( chunkZ = z } - private val sectionIndex = chunkY.toInt() / Chunk.SECTION_HEIGHT - private val index = chunkY.toInt() * Chunk.AREA + chunkZ * Chunk.LENGTH + chunkX + private val sectionIndex = location.y.toInt() / Chunk.SECTION_HEIGHT + private val index = sectionY * Chunk.AREA + chunkZ * Chunk.LENGTH + chunkX override var block: Block get() = (chunk as AnvilChunk).sections[sectionIndex].blocks[index] diff --git a/uranos-api/src/main/kotlin/space/uranos/Vector.kt b/uranos-api/src/main/kotlin/space/uranos/Vector.kt index 23840e4..8bab087 100644 --- a/uranos-api/src/main/kotlin/space/uranos/Vector.kt +++ b/uranos-api/src/main/kotlin/space/uranos/Vector.kt @@ -25,6 +25,11 @@ data class Vector(val x: Double, val y: Double, val z: Double) { operator fun div(other: Vector) = Vector(x / other.x, y / other.y, z / other.z) operator fun times(other: Vector) = Vector(x * other.x, y * other.y, z * other.z) + fun plus(x: Double, y: Double, z: Double) = Vector(this.x + x, this.y + y, this.z + z) + fun minus(x: Double, y: Double, z: Double) = Vector(this.x - x, this.y - y, this.z - z) + fun div(x: Double, y: Double, z: Double) = Vector(this.x / x, this.y / y, this.z / z) + fun times(x: Double, y: Double, z: Double) = Vector(this.x * x, this.y * y, this.z * z) + operator fun get(part: CoordinatePart): Double = when (part) { CoordinatePart.X -> x CoordinatePart.Y -> y @@ -48,7 +53,7 @@ data class Vector(val x: Double, val y: Double, val z: Double) { fun distanceBetween(a: Vector, b: Vector): Double { val (x, y, z) = abs(a - b) - return sqrt(sqrt(x.pow(2) + y.pow(2)) + z.pow(2)) + return sqrt(x.pow(2) + y.pow(2) + z.pow(2)) } val ZERO = Vector(0.0, 0.0, 0.0) diff --git a/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt b/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt index a8c571d..c23965d 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt @@ -5,5 +5,5 @@ package space.uranos.util -infix fun Int.untilPossiblyNegative(other: Int) = +infix fun Int.untilPossiblyLower(other: Int) = IntProgression.fromClosedRange(this, other, if (this > other) -1 else 1) diff --git a/uranos-api/src/main/kotlin/space/uranos/world/World.kt b/uranos-api/src/main/kotlin/space/uranos/world/World.kt index c3d1cce..1a64adb 100644 --- a/uranos-api/src/main/kotlin/space/uranos/world/World.kt +++ b/uranos-api/src/main/kotlin/space/uranos/world/World.kt @@ -10,10 +10,11 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import space.uranos.Uranos +import space.uranos.Vector import space.uranos.entity.Entity import space.uranos.util.newSingleThreadDispatcher import space.uranos.util.supervisorChild -import space.uranos.util.untilPossiblyNegative +import space.uranos.util.untilPossiblyLower import java.util.* import java.util.concurrent.CopyOnWriteArraySet import kotlin.coroutines.CoroutineContext @@ -65,19 +66,19 @@ abstract class World(val uuid: UUID) { fun getVoxel(location: VoxelLocation): Voxel = getChunk(location).getVoxel(location) /** - * Returns all voxels in the cube with the corner points [cornerA] and [cornerB]. + * Returns all voxels in the cuboid with the corner points [cornerA] and [cornerB]. * - * @param hollow Whether the cube is hollow + * @param hollow Whether the cuboid is hollow */ - fun getVoxelsInCube(cornerA: VoxelLocation, cornerB: VoxelLocation, hollow: Boolean = false): List { + fun getVoxelsInCuboid(cornerA: VoxelLocation, cornerB: VoxelLocation, hollow: Boolean = false): List { fun getList(a: Int, b: Int) = if (hollow) listOf(a, b).distinct() - else (a untilPossiblyNegative b).toList() + else (a untilPossiblyLower b).toList() return buildList { - for(x in getList(cornerA.x, cornerB.x)) { - for(y in getList(cornerA.y.toInt(), cornerB.y.toInt())) { - for(z in getList(cornerA.z, cornerB.z)) { + for (x in getList(cornerA.x, cornerB.x)) { + for (y in getList(cornerA.y.toInt(), cornerB.y.toInt())) { + for (z in getList(cornerA.z, cornerB.z)) { add(getVoxel(VoxelLocation(x, y.toUByte(), z))) } } @@ -90,11 +91,17 @@ abstract class World(val uuid: UUID) { */ fun getVoxelsInSphere( center: VoxelLocation, - radius: Int, - hollow: Boolean + radius: Double, + wallWidth: Int = Int.MAX_VALUE ): List { - // Implementation example: https://git.io/JLysq - TODO() + val centerVector = center.asVector() + return getVoxelsInCuboid( + centerVector.plus(radius, radius, radius).toVoxelLocation(), + centerVector.minus(radius, radius, radius).toVoxelLocation() + ).filter { + val distance = Vector.distanceBetween(it.location.asVector(), centerVector) + distance < radius && distance > radius - 0.5 - wallWidth + } } suspend fun destroy() = withContext(coroutineContext) { diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketCodec.kt index 88ad8a1..0875c25 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketCodec.kt @@ -12,7 +12,14 @@ import space.uranos.net.packet.IncomingPacketCodec object IncomingPlayerPositionPacketCodec : IncomingPacketCodec(0x13, IncomingPlayerPositionPacket::class) { override fun decode(msg: ByteBuf): IncomingPlayerPositionPacket = IncomingPlayerPositionPacket( - Position(msg.readDouble(), msg.readDouble(), msg.readDouble(), (360 - msg.readFloat()) % 360, msg.readFloat()), + Position( + msg.readDouble(), + msg.readDouble(), + msg.readDouble(), + Math.floorMod((360 - msg.readFloat()).toInt(), 360) + .toFloat(), // TODO: Higher precision (do not use Math.floorMod) + msg.readFloat() + ), msg.readBoolean() ) } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketCodec.kt index e186200..9e42ee5 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketCodec.kt @@ -11,7 +11,8 @@ import space.uranos.net.packet.IncomingPacketCodec object PlayerOrientationPacketCodec : IncomingPacketCodec(0x14, PlayerOrientationPacket::class) { override fun decode(msg: ByteBuf): PlayerOrientationPacket = PlayerOrientationPacket( - (360 - msg.readFloat()) % 360, + Math.floorMod((360 - msg.readFloat()).toInt(), 360) + .toFloat(), // TODO: Higher precision (do not use Math.floorMod), msg.readFloat(), msg.readBoolean() ) diff --git a/uranos-server/src/main/kotlin/space/uranos/net/PacketsAdapter.kt b/uranos-server/src/main/kotlin/space/uranos/net/PacketsAdapter.kt index ece96dd..f6739c8 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/PacketsAdapter.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/PacketsAdapter.kt @@ -23,7 +23,7 @@ class PacketsAdapter(val session: UranosSession) { private val packetsForNextTick = ArrayList() suspend fun tick() { - packetsForNextTick.forEach { send(it) } + packetsForNextTick.forEach { send(it) } // TODO: Fix ConcurrentModificationException packetsForNextTick.clear() }