Archived
1
0
Fork 0

Implement World.getVoxelsInSphere

This commit is contained in:
Moritz Ruth 2021-01-08 17:46:56 +01:00
parent 33e942f517
commit 9aab2b1adc
No known key found for this signature in database
GPG key ID: AFD57E23E753841B
8 changed files with 42 additions and 23 deletions

View file

@ -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())

View file

@ -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]

View file

@ -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)

View file

@ -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)

View file

@ -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) {

View file

@ -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()
)
}

View file

@ -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()
)

View file

@ -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()
}