Implement World.getVoxelsInSphere
This commit is contained in:
parent
33e942f517
commit
9aab2b1adc
8 changed files with 42 additions and 23 deletions
|
@ -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<ServerListInfoRequestEvent> { event ->
|
||||
event.response = ServerListInfo("1.16.4", 754, TextComponent of "Test", 10, 0, emptyList())
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<Voxel> {
|
||||
fun getVoxelsInCuboid(cornerA: VoxelLocation, cornerB: VoxelLocation, hollow: Boolean = false): List<Voxel> {
|
||||
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<Voxel> {
|
||||
// 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) {
|
||||
|
|
|
@ -12,7 +12,14 @@ import space.uranos.net.packet.IncomingPacketCodec
|
|||
object IncomingPlayerPositionPacketCodec :
|
||||
IncomingPacketCodec<IncomingPlayerPositionPacket>(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()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ import space.uranos.net.packet.IncomingPacketCodec
|
|||
object PlayerOrientationPacketCodec :
|
||||
IncomingPacketCodec<PlayerOrientationPacket>(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()
|
||||
)
|
||||
|
|
|
@ -23,7 +23,7 @@ class PacketsAdapter(val session: UranosSession) {
|
|||
private val packetsForNextTick = ArrayList<OutgoingPacket>()
|
||||
|
||||
suspend fun tick() {
|
||||
packetsForNextTick.forEach { send(it) }
|
||||
packetsForNextTick.forEach { send(it) } // TODO: Fix ConcurrentModificationException
|
||||
packetsForNextTick.clear()
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue