diff --git a/.idea/misc.xml b/.idea/misc.xml index 8f825fd..6f45ef7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,4 +2,7 @@ + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index 86cb589..07005a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Moritz Ruth and the Uranos contributors +Copyright (c) 2020-2021 Moritz Ruth and the Uranos contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index dc67270..3e753bf 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,18 @@ running the `Optimize Imports` action, you need to disable automatic wildcard im ### KDoc -1. If the name of the target is already sufficient for understanding what it does or what it's value represents, you - should **not** add a comment. If you want to provide additional information however, you should start the comment - with a short description nevertheless. -2. The name of the return type, property type or type of the enclosing class should **not** be wrapped in square - brackets. +1. If the name of the target is already sufficient for understanding what it does or what it's value represents, you should **not** add a comment. If you want + to provide additional information however, you should start the comment with a short description nevertheless. +2. The name of the return type, property type or type of the enclosing class should **not** be wrapped in square brackets. 3. If a comment only consists of the `@returns` block tag, the latter should be replaced with a sentence starting with `Returns `. -### Code +### Packets -1. If a member function of a class creates an instance of another class which represents the same value, the function’s name should be `as`. If the new instance does not exactly represent the value of the original instance (for example because it is rounded), the name should be `to`. +1. Outgoing packets should not use classes purely used as data containers such as Location. Enums are allowed. + +### Other + +1. If a member function of a class creates an instance of another class which represents the same value, the function’s name should + be `as`. If the new instance does not exactly represent the value of the original instance (for example because it is rounded), the + name should be `to`. 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 8a1b056..870fa0a 100644 --- a/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt +++ b/test-plugin/src/main/kotlin/space/uranos/testplugin/TestPlugin.kt @@ -5,15 +5,14 @@ package space.uranos.testplugin -import space.uranos.Position import space.uranos.Uranos import space.uranos.chat.ChatColor import space.uranos.chat.TextComponent -import space.uranos.entity.CowEntity +import space.uranos.entity.MinecartEntity +import space.uranos.entity.Position import space.uranos.net.ServerListInfo import space.uranos.net.event.ServerListInfoRequestEvent import space.uranos.net.event.SessionAfterLoginEvent -import space.uranos.net.packet.play.EntityHeadYawPacket import space.uranos.player.GameMode import space.uranos.plugin.Plugin import space.uranos.testplugin.anvil.AnvilWorld @@ -23,11 +22,41 @@ import space.uranos.util.secondsToTicks import space.uranos.world.* import space.uranos.world.block.GreenWoolBlock import space.uranos.world.block.RedWoolBlock -import kotlin.random.Random -import kotlin.random.nextUBytes class TestPlugin : Plugin("Test", "1.0.0") { + fun enableOptifineFix() { + Uranos.biomeRegistry.register( + Biome( + "minecraft:swamp", + Biome.Precipitation.NONE, + RGBColor(12), + RGBColor(1), + RGBColor(1), + RGBColor(1), + Biome.MoodSound(0, 0.0, "minecraft:entity.pig.ambient", 0), + 0f, + 0f + ) + ) + + Uranos.biomeRegistry.register( + Biome( + "minecraft:swamp_hills", + Biome.Precipitation.NONE, + RGBColor(12), + RGBColor(1), + RGBColor(1), + RGBColor(1), + Biome.MoodSound(0, 0.0, "minecraft:entity.pig.ambient", 0), + 0f, + 0f + ) + ) + } + override suspend fun onEnable() { + enableOptifineFix() + val dimension = Dimension( "test:test", true, @@ -64,10 +93,6 @@ class TestPlugin : Plugin("Test", "1.0.0") { event.response = ServerListInfo("1.16.4", 754, TextComponent of "Test", 10, 0, emptyList()) } - val entity = Uranos.create() - entity.position = Position(0.5, 10.0, 0.5, 0f, 0f) - entity.setWorld(world) - Uranos.eventBus.on { event -> event.gameMode = GameMode.CREATIVE event.canFly = true @@ -75,7 +100,6 @@ class TestPlugin : Plugin("Test", "1.0.0") { event.initialWorldAndLocation = VoxelLocation .of(0, 2, 0) .atTopCenter() - .withRotation(0f, 0f) .inside(world) Uranos.scheduler.executeRepeating(secondsToTicks(1)) { @@ -85,20 +109,23 @@ class TestPlugin : Plugin("Test", "1.0.0") { } } - var x = 1.0 - Uranos.scheduler.executeRepeating(20) { - x += 0.2 + // Not showing up yet because no metadata is sent + val entity = Uranos.create() + entity.position = Position(0.0, 4.0, 0.0) + entity.setWorld(world) + + var x = 0f + var y = -90f + Uranos.scheduler.executeRepeating(1) { runInServerThread { - Uranos.players.forEach { - it.session.send( - EntityHeadYawPacket( - entity.numericID, - Random.nextUBytes(1)[0] - ) - ) - } + entity.yaw = x + entity.pitch = y } - if (x >= 10.0) x = 0.0 + + x += 5f + y += 5f + if (x == 360f) x = 0f + if (y == 90f) y = -90f } } } diff --git a/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilChunk.kt b/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilChunk.kt index 30d5b02..3380814 100644 --- a/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilChunk.kt +++ b/test-plugin/src/main/kotlin/space/uranos/testplugin/anvil/AnvilChunk.kt @@ -7,7 +7,7 @@ package space.uranos.testplugin.anvil import com.google.common.cache.LoadingCache import space.uranos.player.Player -import space.uranos.util.createWeakValuesLoadingCache +import space.uranos.util.collections.createWeakValuesLoadingCache import space.uranos.world.* import space.uranos.world.block.AirBlock diff --git a/uranos-api/src/main/kotlin/space/uranos/CoordinatePart.kt b/uranos-api/src/main/kotlin/space/uranos/CoordinatePart.kt index 983446b..8f2b905 100644 --- a/uranos-api/src/main/kotlin/space/uranos/CoordinatePart.kt +++ b/uranos-api/src/main/kotlin/space/uranos/CoordinatePart.kt @@ -10,19 +10,3 @@ enum class CoordinatePart { Y, Z } - -data class CoordinatePartOrder(val first: CoordinatePart, val second: CoordinatePart, val third: CoordinatePart) { - init { - val values = arrayOf(first, second, third) - if (values.distinct().size != values.size) - throw IllegalArgumentException("first, second and third must have different values") - } - - companion object { - val DEFAULT = CoordinatePartOrder( - CoordinatePart.X, - CoordinatePart.Y, - CoordinatePart.Z - ) - } -} diff --git a/uranos-api/src/main/kotlin/space/uranos/Position.kt b/uranos-api/src/main/kotlin/space/uranos/Position.kt deleted file mode 100644 index f2b49ba..0000000 --- a/uranos-api/src/main/kotlin/space/uranos/Position.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020-2021 Moritz Ruth and Uranos contributors - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file - */ - -package space.uranos - -import space.uranos.world.VoxelLocation -import space.uranos.world.World -import kotlin.math.roundToInt - -/** - * A combination of x, y and z coordinates and an orientation (yaw and pitch). - * - * @param yaw The yaw rotation in degrees. Must be in `[0; 360[`. - * @param headPitch The pitch rotation of the head as a value between -90 (up) and 90 (down). - */ -data class Position(val x: Double, val y: Double, val z: Double, val yaw: Float, val headPitch: Float) { - init { - if (yaw >= 360) throw IllegalArgumentException("yaw must be lower than 360") - if (yaw < 0) throw IllegalArgumentException("yaw must not be negative") - } - - /** - * Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt], - * in contrast to [roundToBlock] which uses [Double.roundToInt]. - */ - fun toVoxelLocation(): VoxelLocation = VoxelLocation(x.toInt(), y.toInt().toUByte(), z.toInt()) - - /** - * Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt], - * in contrast to [toVoxelLocation] which uses [Double.toInt]. - */ - fun roundToBlock(): VoxelLocation = VoxelLocation(x.roundToInt(), y.roundToInt().toUByte(), z.roundToInt()) - - fun toLocation(): Location = Location(x, y, z) - fun toVector() = Vector(x, y, z) - infix fun inside(world: World): Pair = world to this - - val yawIn256Steps: UByte get() = ((yaw / 360) * 256).toInt().toUByte() - val headPitchIn256Steps: UByte get() = ((yaw / 360) * 256).toInt().toUByte() - - operator fun get(part: CoordinatePart): Double = when (part) { - CoordinatePart.X -> x - CoordinatePart.Y -> y - CoordinatePart.Z -> z - } - - companion object { - val ZERO = Position(0.0, 0.0, 0.0, 0f, 0f) - } -} diff --git a/uranos-api/src/main/kotlin/space/uranos/Vector.kt b/uranos-api/src/main/kotlin/space/uranos/Vector.kt index 8bab087..c353b6d 100644 --- a/uranos-api/src/main/kotlin/space/uranos/Vector.kt +++ b/uranos-api/src/main/kotlin/space/uranos/Vector.kt @@ -5,7 +5,8 @@ package space.uranos -import space.uranos.util.clamp +import space.uranos.entity.Position +import space.uranos.util.numbers.clamp import space.uranos.world.VoxelLocation import kotlin.math.abs import kotlin.math.pow @@ -18,7 +19,7 @@ data class Vector(val x: Double, val y: Double, val z: Double) { */ fun toVoxelLocation() = VoxelLocation(x.toInt(), y.toInt().clamp(0..255).toUByte(), z.toInt()) fun roundToBlock() = VoxelLocation(x.roundToInt(), y.toInt().clamp(0..255).toUByte(), z.roundToInt()) - fun asLocation() = Location(x, y, z) + fun asPosition() = Position(x, y, z) operator fun plus(other: Vector) = Vector(x + other.x, y + other.y, z + other.z) operator fun minus(other: Vector) = Vector(x - other.x, y - other.y, z - other.z) diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/Entity.kt b/uranos-api/src/main/kotlin/space/uranos/entity/Entity.kt index b5c53ca..32b4205 100644 --- a/uranos-api/src/main/kotlin/space/uranos/entity/Entity.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/Entity.kt @@ -40,7 +40,7 @@ interface Entity { suspend fun setWorld(world: World?) /** - * If players should be added to [viewers] when they join. + * If players should be added to [viewers] when they enter [world]. */ var visibleToNewPlayers: Boolean } diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/HasMovableHead.kt b/uranos-api/src/main/kotlin/space/uranos/entity/HasMovableHead.kt new file mode 100644 index 0000000..48dc29d --- /dev/null +++ b/uranos-api/src/main/kotlin/space/uranos/entity/HasMovableHead.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity + +interface HasMovableHead : Mobile, Entity { + /** + * Must be `-90..90`. + */ + var headPitch: Float + + /** + * Must be not negative and lower than 360. + */ + var headYaw: Float +} diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/LivingEntity.kt b/uranos-api/src/main/kotlin/space/uranos/entity/LivingEntity.kt index c9238f2..774a7b5 100644 --- a/uranos-api/src/main/kotlin/space/uranos/entity/LivingEntity.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/LivingEntity.kt @@ -5,4 +5,5 @@ package space.uranos.entity -interface LivingEntity : Entity, Mobile +interface LivingEntity : Entity, Mobile { +} diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt b/uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt index e7d5381..e56f120 100644 --- a/uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt @@ -5,7 +5,6 @@ package space.uranos.entity -import space.uranos.Position import space.uranos.Vector interface Mobile { diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/PaintingEntity.kt b/uranos-api/src/main/kotlin/space/uranos/entity/PaintingEntity.kt index 529686c..d6f60ad 100644 --- a/uranos-api/src/main/kotlin/space/uranos/entity/PaintingEntity.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/PaintingEntity.kt @@ -18,8 +18,7 @@ interface PaintingEntity : Entity { companion object Type : AreaEffectCloudEntityType() } -val PaintingEntity.centerLocation - get() = topLeftLocation.copy( - x = max(0, motive.width / 2) + topLeftLocation.x, - z = motive.height / 2 + topLeftLocation.z - ) +fun PaintingEntity.calculateCenterLocation() = topLeftLocation.copy( + x = max(0, motive.width / 2) + topLeftLocation.x, + z = motive.height / 2 + topLeftLocation.z +) diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/UranosCowEntity.kt b/uranos-api/src/main/kotlin/space/uranos/entity/PitchRotatable.kt similarity index 62% rename from uranos-server/src/main/kotlin/space/uranos/entity/UranosCowEntity.kt rename to uranos-api/src/main/kotlin/space/uranos/entity/PitchRotatable.kt index ed57538..1e16e1a 100644 --- a/uranos-server/src/main/kotlin/space/uranos/entity/UranosCowEntity.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/PitchRotatable.kt @@ -5,6 +5,6 @@ package space.uranos.entity -import space.uranos.UranosServer - -class UranosCowEntity(server: UranosServer) : UranosLivingEntity(server), CowEntity +interface PitchRotatable { + var pitch: Float +} diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/PlayerEntity.kt b/uranos-api/src/main/kotlin/space/uranos/entity/PlayerEntity.kt index ccb5e5b..6c2ace2 100644 --- a/uranos-api/src/main/kotlin/space/uranos/entity/PlayerEntity.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/PlayerEntity.kt @@ -8,7 +8,7 @@ package space.uranos.entity import space.uranos.player.Player import space.uranos.world.World -interface PlayerEntity : LivingEntity { +interface PlayerEntity : LivingEntity, HasMovableHead { val player: Player companion object Type : PlayerEntityType() diff --git a/uranos-api/src/main/kotlin/space/uranos/Location.kt b/uranos-api/src/main/kotlin/space/uranos/entity/Position.kt similarity index 68% rename from uranos-api/src/main/kotlin/space/uranos/Location.kt rename to uranos-api/src/main/kotlin/space/uranos/entity/Position.kt index 89ae63a..4037c51 100644 --- a/uranos-api/src/main/kotlin/space/uranos/Location.kt +++ b/uranos-api/src/main/kotlin/space/uranos/entity/Position.kt @@ -3,36 +3,40 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos +package space.uranos.entity +import space.uranos.CoordinatePart +import space.uranos.Vector import space.uranos.world.VoxelLocation import space.uranos.world.World import kotlin.math.roundToInt /** - * Represents a combination of x, y and z coordinates. + * A combination of x, y and z coordinates. */ -data class Location(val x: Double, val y: Double, val z: Double) { +data class Position(val x: Double, val y: Double, val z: Double) { /** - * Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt], + * Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt], * in contrast to [roundToBlock] which uses [Double.roundToInt]. */ fun toVoxelLocation(): VoxelLocation = VoxelLocation(x.toInt(), y.toInt().toUByte(), z.toInt()) /** - * Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt], + * Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt], * in contrast to [toVoxelLocation] which uses [Double.toInt]. */ fun roundToBlock(): VoxelLocation = VoxelLocation(x.roundToInt(), y.roundToInt().toUByte(), z.roundToInt()) - fun withRotation(yaw: Float, pitch: Float) = Position(x, y, z, yaw, pitch) fun asVector() = Vector(x, y, z) - - infix fun inside(world: World): Pair = world to this + infix fun inside(world: World): Pair = world to this operator fun get(part: CoordinatePart): Double = when (part) { CoordinatePart.X -> x CoordinatePart.Y -> y CoordinatePart.Z -> z } + + companion object { + val ZERO = Position(0.0, 0.0, 0.0) + } } diff --git a/uranos-api/src/main/kotlin/space/uranos/entity/YawRotatable.kt b/uranos-api/src/main/kotlin/space/uranos/entity/YawRotatable.kt new file mode 100644 index 0000000..a7c1c6c --- /dev/null +++ b/uranos-api/src/main/kotlin/space/uranos/entity/YawRotatable.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity + +interface YawRotatable { + var yaw: Float +} diff --git a/uranos-api/src/main/kotlin/space/uranos/net/Session.kt b/uranos-api/src/main/kotlin/space/uranos/net/Session.kt index af54a2b..9b5d8b2 100644 --- a/uranos-api/src/main/kotlin/space/uranos/net/Session.kt +++ b/uranos-api/src/main/kotlin/space/uranos/net/Session.kt @@ -8,9 +8,9 @@ package space.uranos.net import io.netty.buffer.ByteBuf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob -import space.uranos.Position import space.uranos.Uranos import space.uranos.chat.TextComponent +import space.uranos.entity.Position import space.uranos.event.EventBusWrapper import space.uranos.net.packet.OutgoingPacket import space.uranos.net.packet.Protocol @@ -77,6 +77,7 @@ abstract class Session { val gameMode: GameMode, val world: World, val position: Position, + val headYaw: Float, val headPitch: Float, val invulnerable: Boolean, val reducedDebugInfo: Boolean, @@ -123,6 +124,8 @@ abstract class Session { */ abstract fun send(packet: OutgoingPacket) + fun send(packets: Iterable) = packets.forEach { this.send(it) } + /** * Sends a plugin message packet. */ diff --git a/uranos-api/src/main/kotlin/space/uranos/net/event/SessionAfterLoginEvent.kt b/uranos-api/src/main/kotlin/space/uranos/net/event/SessionAfterLoginEvent.kt index 964c898..9b2a8a3 100644 --- a/uranos-api/src/main/kotlin/space/uranos/net/event/SessionAfterLoginEvent.kt +++ b/uranos-api/src/main/kotlin/space/uranos/net/event/SessionAfterLoginEvent.kt @@ -5,7 +5,7 @@ package space.uranos.net.event -import space.uranos.Position +import space.uranos.entity.Position import space.uranos.event.Cancellable import space.uranos.net.Session import space.uranos.player.GameMode @@ -30,6 +30,7 @@ class SessionAfterLoginEvent(override val target: Session) : SessionEvent(), Can */ var initialWorldAndLocation: Pair? = null + var headYaw: Float = 0f var headPitch: Float = 0f var maxViewDistance: Int = 32 diff --git a/uranos-api/src/main/kotlin/space/uranos/player/event/PlayerReadyEvent.kt b/uranos-api/src/main/kotlin/space/uranos/player/event/PlayerReadyEvent.kt new file mode 100644 index 0000000..513ea1e --- /dev/null +++ b/uranos-api/src/main/kotlin/space/uranos/player/event/PlayerReadyEvent.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.player.event + +import space.uranos.player.Player + +class PlayerReadyEvent(player: Player) : PlayerEvent(player) diff --git a/uranos-api/src/main/kotlin/space/uranos/util/CoroutineContextSupervisorChild.kt b/uranos-api/src/main/kotlin/space/uranos/util/CoroutineContextSupervisorChild.kt deleted file mode 100644 index 729f559..0000000 --- a/uranos-api/src/main/kotlin/space/uranos/util/CoroutineContextSupervisorChild.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2020-2021 Moritz Ruth and Uranos contributors - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file - */ - -package space.uranos.util - -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.job -import kotlin.coroutines.CoroutineContext - -fun CoroutineContext.supervisorChild(name: String) = this + CoroutineName(name) + SupervisorJob(this.job) diff --git a/uranos-api/src/main/kotlin/space/uranos/util/TickSynchronizationContainer.kt b/uranos-api/src/main/kotlin/space/uranos/util/TickSynchronizationContainer.kt index 9a18bdc..7b2ffdb 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/TickSynchronizationContainer.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/TickSynchronizationContainer.kt @@ -10,8 +10,8 @@ import kotlinx.coroutines.launch import java.lang.ref.WeakReference import kotlin.reflect.KProperty -// If it is too resource-intensive to create a new object for every property, one instance could be used per TickSynchronizationContainer class TickSynchronizationContainer { + // If it is too resource-intensive to create a new object for every property, one instance could be used per TickSynchronizationContainer private val delegates = mutableSetOf>() suspend fun tick() { diff --git a/uranos-api/src/main/kotlin/space/uranos/util/CreateWeakValuesLoadingCache.kt b/uranos-api/src/main/kotlin/space/uranos/util/collections/CreateWeakValuesLoadingCache.kt similarity index 94% rename from uranos-api/src/main/kotlin/space/uranos/util/CreateWeakValuesLoadingCache.kt rename to uranos-api/src/main/kotlin/space/uranos/util/collections/CreateWeakValuesLoadingCache.kt index 5d9d389..b1c092e 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/CreateWeakValuesLoadingCache.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/collections/CreateWeakValuesLoadingCache.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.collections import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader diff --git a/uranos-api/src/main/kotlin/space/uranos/util/KClassToInstanceMap.kt b/uranos-api/src/main/kotlin/space/uranos/util/collections/KClassToInstanceMap.kt similarity index 95% rename from uranos-api/src/main/kotlin/space/uranos/util/KClassToInstanceMap.kt rename to uranos-api/src/main/kotlin/space/uranos/util/collections/KClassToInstanceMap.kt index d91ba9f..6f60678 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/KClassToInstanceMap.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/collections/KClassToInstanceMap.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.collections import kotlin.reflect.KClass diff --git a/uranos-api/src/main/kotlin/space/uranos/util/WatchableSet.kt b/uranos-api/src/main/kotlin/space/uranos/util/collections/WatchableSet.kt similarity index 98% rename from uranos-api/src/main/kotlin/space/uranos/util/WatchableSet.kt rename to uranos-api/src/main/kotlin/space/uranos/util/collections/WatchableSet.kt index 9dd1499..b918b68 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/WatchableSet.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/collections/WatchableSet.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.collections import java.util.Spliterator import java.util.function.Predicate diff --git a/uranos-api/src/main/kotlin/space/uranos/util/Bits.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/Bits.kt similarity index 96% rename from uranos-api/src/main/kotlin/space/uranos/util/Bits.kt rename to uranos-api/src/main/kotlin/space/uranos/util/numbers/Bits.kt index cecd8c2..46bd293 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/Bits.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/Bits.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.numbers import kotlin.experimental.and import kotlin.experimental.inv diff --git a/uranos-api/src/main/kotlin/space/uranos/util/Clamp.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/Clamp.kt similarity index 54% rename from uranos-api/src/main/kotlin/space/uranos/util/Clamp.kt rename to uranos-api/src/main/kotlin/space/uranos/util/numbers/Clamp.kt index ae451a1..cf2ed96 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/Clamp.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/Clamp.kt @@ -3,10 +3,14 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.numbers fun Int.clamp(range: IntRange) = maxOf(minOf(range.first, range.last), minOf(maxOf(range.first, range.last), this)) -fun clampArgument(name: String, range: IntRange, actualValue: Int) { +fun validateParameterIsInRange(name: String, range: IntRange, actualValue: Int) { if (!range.contains(actualValue)) throw IllegalArgumentException("$name must be in $range") } + +fun validateParameterIsInRange(name: String, range: IntRange, actualValue: Float) { + if (range.first > actualValue || range.last < actualValue) throw IllegalArgumentException("$name must be in $range") +} diff --git a/uranos-api/src/main/kotlin/space/uranos/util/FloatFloorMod.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/FloatFloorMod.kt similarity index 92% rename from uranos-api/src/main/kotlin/space/uranos/util/FloatFloorMod.kt rename to uranos-api/src/main/kotlin/space/uranos/util/numbers/FloatFloorMod.kt index 804defc..2b2ee36 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/FloatFloorMod.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/FloatFloorMod.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.numbers fun floorMod(dividend: Float, divisor: Float): Float { if (divisor == 0f) throw ArithmeticException("divisor cannot be 0") diff --git a/uranos-api/src/main/kotlin/space/uranos/util/numbers/MapNumberRange.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/MapNumberRange.kt new file mode 100644 index 0000000..0112a7a --- /dev/null +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/MapNumberRange.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.util.numbers + +fun Float.mapToUByte(divisor: Float) = ((this / divisor) * 256).toInt().toUByte() diff --git a/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/UntilPossiblyNegative.kt similarity index 89% rename from uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt rename to uranos-api/src/main/kotlin/space/uranos/util/numbers/UntilPossiblyNegative.kt index c23965d..85835f5 100644 --- a/uranos-api/src/main/kotlin/space/uranos/util/UntilPossiblyNegative.kt +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/UntilPossiblyNegative.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.util +package space.uranos.util.numbers 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/util/numbers/ValidateOrientation.kt b/uranos-api/src/main/kotlin/space/uranos/util/numbers/ValidateOrientation.kt new file mode 100644 index 0000000..5c1139d --- /dev/null +++ b/uranos-api/src/main/kotlin/space/uranos/util/numbers/ValidateOrientation.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.util.numbers + +fun validateYaw(value: Float, name: String = "yaw") { + if (value >= 360f) throw IllegalArgumentException("$name must be lower than 360") + if (value < 0f) throw IllegalArgumentException("$name must not be negative") +} + +fun validatePitch(value: Float, name: String = "pitch") { + validateParameterIsInRange(name, -90..90, value) +} diff --git a/uranos-api/src/main/kotlin/space/uranos/world/Chunk.kt b/uranos-api/src/main/kotlin/space/uranos/world/Chunk.kt index 8254db7..cf4fe8b 100644 --- a/uranos-api/src/main/kotlin/space/uranos/world/Chunk.kt +++ b/uranos-api/src/main/kotlin/space/uranos/world/Chunk.kt @@ -7,8 +7,8 @@ package space.uranos.world import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob -import space.uranos.Position import space.uranos.Uranos +import space.uranos.entity.Position import space.uranos.player.Player import kotlin.math.floor diff --git a/uranos-api/src/main/kotlin/space/uranos/world/VoxelLocation.kt b/uranos-api/src/main/kotlin/space/uranos/world/VoxelLocation.kt index 4a92669..697dfaf 100644 --- a/uranos-api/src/main/kotlin/space/uranos/world/VoxelLocation.kt +++ b/uranos-api/src/main/kotlin/space/uranos/world/VoxelLocation.kt @@ -6,8 +6,8 @@ package space.uranos.world import space.uranos.CoordinatePart -import space.uranos.Location import space.uranos.Vector +import space.uranos.entity.Position /** * A location consisting of an x, y and z coordinate. @@ -19,7 +19,7 @@ data class VoxelLocation(val x: Int, val y: UByte, val z: Int) { /** * Converts this VoxelLocation to a Location. */ - fun asLocation(): Location = Location(x.toDouble(), y.toDouble(), z.toDouble()) + fun asPosition(): Position = Position(x.toDouble(), y.toDouble(), z.toDouble()) fun asVector(): Vector = Vector(x.toDouble(), y.toDouble(), z.toDouble()) @@ -28,14 +28,14 @@ data class VoxelLocation(val x: Int, val y: UByte, val z: Int) { * * Example: `VoxelLocation(x = 1, y = 2, z = 3)` becomes `Location(x = 1.5, y = 2.5, z = 3.5)`. */ - fun atCenter(): Location = Location(x.toDouble() + 0.5, y.toDouble() + 0.5, z.toDouble() + 0.5) + fun atCenter(): Position = Position(x.toDouble() + 0.5, y.toDouble() + 0.5, z.toDouble() + 0.5) /** * Converts this VoxelLocation to a Location **and then adds 0.5 to x and z, but not y**. * * Example: `VoxelLocation(x = 1, y = 2, z = 3)` becomes `Location(x = 1.5, y = 2, z = 3.5)`. */ - fun atTopCenter(): Location = Location(x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) + fun atTopCenter(): Position = Position(x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) /** * Returns a VoxelLocation with the maximum x, y and z values of this and [other]. @@ -54,6 +54,8 @@ data class VoxelLocation(val x: Int, val y: UByte, val z: Int) { } companion object { + val ZERO = VoxelLocation(0, 0u, 0) + fun of(x: Int, y: Int, z: Int): VoxelLocation { if (y !in 0..255) throw IllegalArgumentException("y must be in 0..255") return VoxelLocation(x, y.toUByte(), z) 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 5dfe6e0..aad073f 100644 --- a/uranos-api/src/main/kotlin/space/uranos/world/World.kt +++ b/uranos-api/src/main/kotlin/space/uranos/world/World.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext import space.uranos.Vector import space.uranos.entity.Entity -import space.uranos.util.untilPossiblyLower +import space.uranos.util.numbers.untilPossiblyLower interface World { val dispatcher: CoroutineDispatcher diff --git a/uranos-api/src/test/kotlin/space/uranos/util/FloatFloorModTest.kt b/uranos-api/src/test/kotlin/space/uranos/util/FloatFloorModTest.kt index 2f1be14..8a8543c 100644 --- a/uranos-api/src/test/kotlin/space/uranos/util/FloatFloorModTest.kt +++ b/uranos-api/src/test/kotlin/space/uranos/util/FloatFloorModTest.kt @@ -1,6 +1,7 @@ package space.uranos.util import org.junit.jupiter.api.Test +import space.uranos.util.numbers.floorMod import strikt.api.expectThat import strikt.api.expectThrows import strikt.assertions.isEqualTo diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkDataPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkDataPacketCodec.kt index ae574d2..98e60b0 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkDataPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkDataPacketCodec.kt @@ -12,7 +12,7 @@ import space.uranos.net.MinecraftProtocolDataTypes.writeNBT import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec import space.uranos.util.generateHeightmap -import space.uranos.util.setBit +import space.uranos.util.numbers.setBit import space.uranos.util.toCompactLongArray import space.uranos.world.block.AirBlock import space.uranos.world.block.CaveAirBlock diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkLightDataPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkLightDataPacketCodec.kt index 5dfbcda..d541189 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkLightDataPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ChunkLightDataPacketCodec.kt @@ -8,8 +8,8 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec -import space.uranos.util.checkBit -import space.uranos.util.setBit +import space.uranos.util.numbers.checkBit +import space.uranos.util.numbers.setBit object ChunkLightDataPacketCodec : OutgoingPacketCodec(0x23, ChunkLightDataPacket::class) { private const val OUTSIDE_SECTIONS_MASK = 0b100000000000000001 @@ -38,13 +38,13 @@ object ChunkLightDataPacketCodec : OutgoingPacketCodec(0x2 dst.writeVarInt((emptyBlockLightMask shl 1) or OUTSIDE_SECTIONS_MASK) for (sectionValues in data.skyLightValues) { - if (sectionValues === null) continue + if (sectionValues == null) continue dst.writeVarInt(2048) sectionValues.forEach { dst.writeByte(it.toInt()) } } for (sectionValues in data.blockLightValues) { - if (sectionValues === null) continue + if (sectionValues == null) continue dst.writeVarInt(2048) sectionValues.forEach { dst.writeByte(it.toInt()) } } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketCodec.kt index b68a810..f6fe735 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketCodec.kt @@ -13,7 +13,7 @@ import space.uranos.net.packet.IncomingPacketCodec import space.uranos.player.ChatMode import space.uranos.player.Hand import space.uranos.player.SkinPartsConfiguration -import space.uranos.util.checkBit +import space.uranos.util.numbers.checkBit object ClientSettingsPacketCodec : IncomingPacketCodec(0x05, ClientSettingsPacket::class) { override fun decode(msg: ByteBuf): ClientSettingsPacket { diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacketCodec.kt similarity index 62% rename from uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacketCodec.kt rename to uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacketCodec.kt index 30daa1a..9f70490 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacketCodec.kt @@ -9,11 +9,11 @@ import io.netty.buffer.ByteBuf import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec -object EntityHeadPitchPacketCodec : - OutgoingPacketCodec(0x29, EntityHeadPitchPacket::class) { - override fun EntityHeadPitchPacket.encode(dst: ByteBuf) { +object EntityOrientationPacketCodec : + OutgoingPacketCodec(0x29, EntityOrientationPacket::class) { + override fun EntityOrientationPacket.encode(dst: ByteBuf) { dst.writeVarInt(entityID) - dst.writeByte(0) // Should be yaw, but is actually ignored. Use EntityHeadYawPacket instead. + dst.writeByte(yaw.toInt()) dst.writeByte(pitch.toInt()) dst.writeBoolean(onGround) } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacketCodec.kt index c2ded60..d6fc32a 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacketCodec.kt @@ -17,7 +17,7 @@ object EntityRelativeMoveWithOrientationPacketCodec : dst.writeShort(deltaY.toInt()) dst.writeShort(deltaZ.toInt()) dst.writeByte(yaw.toInt()) - dst.writeByte(headPitch.toInt()) + dst.writeByte(pitch.toInt()) dst.writeBoolean(onGround) } } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacketCodec.kt index 70d7826..7672466 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacketCodec.kt @@ -17,7 +17,7 @@ object EntityTeleportPacketCodec : dst.writeDouble(y) dst.writeDouble(z) dst.writeByte(yaw.toInt()) - dst.writeByte(headPitch.toInt()) + dst.writeByte(pitch.toInt()) dst.writeBoolean(onGround) } } 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 ec56b75..528bc2e 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 @@ -6,9 +6,9 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf -import space.uranos.Position +import space.uranos.entity.Position import space.uranos.net.packet.IncomingPacketCodec -import space.uranos.util.floorMod +import space.uranos.util.numbers.floorMod object IncomingPlayerPositionPacketCodec : IncomingPacketCodec(0x13, IncomingPlayerPositionPacket::class) { @@ -16,10 +16,10 @@ object IncomingPlayerPositionPacketCodec : Position( msg.readDouble(), msg.readDouble(), - msg.readDouble(), - floorMod(msg.readFloat(), 360f), - msg.readFloat() + msg.readDouble() ), + floorMod(msg.readFloat(), 360f), + msg.readFloat(), msg.readBoolean() ) } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacketCodec.kt index bea01bd..06ab331 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacketCodec.kt @@ -8,17 +8,17 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec -import space.uranos.util.bitmask +import space.uranos.util.numbers.bitmask object OutgoingPlayerPositionPacketCodec : OutgoingPacketCodec(0x34, OutgoingPlayerPositionPacket::class) { override fun OutgoingPlayerPositionPacket.encode(dst: ByteBuf) { - dst.writeDouble(position.x) - dst.writeDouble(position.y) - dst.writeDouble(position.z) - dst.writeFloat(position.yaw) - dst.writeFloat(position.headPitch) - dst.writeByte(bitmask(relativeX, relativeY, relativeZ, relativeYaw, relativePitch)) + dst.writeDouble(x) + dst.writeDouble(y) + dst.writeDouble(z) + dst.writeFloat(yaw) + dst.writeFloat(pitch) + dst.writeByte(bitmask(relativeX, relativeY, relativeZ, relativeYaw, relativeHeadPitch)) dst.writeVarInt(0) // Teleport ID, I am not sure why this is needed } } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayProtocol.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayProtocol.kt index 2944ea2..a4d62b7 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayProtocol.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayProtocol.kt @@ -18,8 +18,8 @@ object PlayProtocol : Protocol( DeclareRecipesPacketCodec, DestroyEntitiesPacketCodec, DisconnectPacketCodec, - EntityHeadPitchPacketCodec, EntityHeadYawPacketCodec, + EntityOrientationPacketCodec, EntityRelativeMovePacketCodec, EntityRelativeMoveWithOrientationPacketCodec, EntityTeleportPacketCodec, diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerAbilitiesPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerAbilitiesPacketCodec.kt index ba0af6c..75d0fd8 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerAbilitiesPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerAbilitiesPacketCodec.kt @@ -7,7 +7,7 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf import space.uranos.net.packet.OutgoingPacketCodec -import space.uranos.util.bitmask +import space.uranos.util.numbers.bitmask object PlayerAbilitiesPacketCodec : OutgoingPacketCodec(0x30, PlayerAbilitiesPacket::class) { override fun PlayerAbilitiesPacket.encode(dst: ByteBuf) { diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketCodec.kt index 2d579ff..0c3c502 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketCodec.kt @@ -6,13 +6,13 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf -import space.uranos.Location +import space.uranos.entity.Position import space.uranos.net.packet.IncomingPacketCodec object PlayerLocationPacketCodec : - IncomingPacketCodec(0x12, PlayerLocationPacket::class) { - override fun decode(msg: ByteBuf): PlayerLocationPacket = PlayerLocationPacket( - Location(msg.readDouble(), msg.readDouble(), msg.readDouble()), + IncomingPacketCodec(0x12, PlayerPositionPacket::class) { + override fun decode(msg: ByteBuf): PlayerPositionPacket = PlayerPositionPacket( + Position(msg.readDouble(), msg.readDouble(), msg.readDouble()), 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 a0186eb..fcfb583 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 @@ -7,7 +7,7 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf import space.uranos.net.packet.IncomingPacketCodec -import space.uranos.util.floorMod +import space.uranos.util.numbers.floorMod object PlayerOrientationPacketCodec : IncomingPacketCodec(0x14, PlayerOrientationPacket::class) { diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacketCodec.kt index b1f56a3..e8d912e 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacketCodec.kt @@ -6,16 +6,15 @@ package space.uranos.net.packet.play import io.netty.buffer.ByteBuf -import space.uranos.Difficulty import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec object SpawnExperienceOrbPacketCodec : OutgoingPacketCodec(0x01, SpawnExperienceOrbPacket::class) { override fun SpawnExperienceOrbPacket.encode(dst: ByteBuf) { dst.writeVarInt(entityID) - dst.writeDouble(location.x) - dst.writeDouble(location.y) - dst.writeDouble(location.z) + dst.writeDouble(x) + dst.writeDouble(y) + dst.writeDouble(z) dst.writeShort(amount.toInt()) } } diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacketCodec.kt index 284e25a..7b6196f 100644 --- a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacketCodec.kt +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacketCodec.kt @@ -9,9 +9,9 @@ import io.netty.buffer.ByteBuf import space.uranos.net.MinecraftProtocolDataTypes.writeUUID import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt import space.uranos.net.packet.OutgoingPacketCodec +import space.uranos.util.numbers.mapToUByte object SpawnLivingEntityPacketCodec : OutgoingPacketCodec(0x02, SpawnLivingEntityPacket::class) { - @Suppress("DuplicatedCode") override fun SpawnLivingEntityPacket.encode(dst: ByteBuf) { dst.writeVarInt(entityID) dst.writeUUID(uuid) @@ -19,9 +19,12 @@ object SpawnLivingEntityPacketCodec : OutgoingPacketCodec(0x00, SpawnObjectEntityPacket::class) { - @Suppress("DuplicatedCode") override fun SpawnObjectEntityPacket.encode(dst: ByteBuf) { dst.writeVarInt(entityID) dst.writeUUID(uuid) - dst.writeVarInt(type.numericID) - dst.writeDouble(position.x) - dst.writeDouble(position.y) - dst.writeDouble(position.z) - dst.writeByte(position.yawIn256Steps.toInt()) - dst.writeByte(position.headPitchIn256Steps.toInt()) + dst.writeVarInt(type) + dst.writeDouble(x) + dst.writeDouble(y) + dst.writeDouble(z) + dst.writeByte(pitch.toInt()) + dst.writeByte(yaw.toInt()) dst.writeInt(data) dst.writeShort((velocity.x * 8000).toInt().toShort().toInt()) dst.writeShort((velocity.y * 8000).toInt().toShort().toInt()) diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadYawPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadYawPacket.kt index f6b37b8..0517cf6 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadYawPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadYawPacket.kt @@ -7,6 +7,7 @@ package space.uranos.net.packet.play import space.uranos.net.packet.OutgoingPacket +// Name on wiki.vg: Entity Head Look data class EntityHeadYawPacket( val entityID: Int, val yaw: UByte diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacket.kt similarity index 55% rename from uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacket.kt rename to uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacket.kt index fe29c82..40f0162 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityHeadPitchPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityOrientationPacket.kt @@ -7,8 +7,14 @@ package space.uranos.net.packet.play import space.uranos.net.packet.OutgoingPacket -data class EntityHeadPitchPacket( +data class EntityOrientationPacket( val entityID: Int, + /** + * Ignored for entities implementing [HasMovableHead][space.uranos.entity.HasMovableHead]. + * + * [EntityHeadYawPacket][space.uranos.net.packet.play.EntityHeadYawPacket] must be used instead. + */ + val yaw: UByte, val pitch: UByte, val onGround: Boolean ) : OutgoingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMovePacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMovePacket.kt index 1cb3496..0a878b3 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMovePacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMovePacket.kt @@ -7,6 +7,7 @@ package space.uranos.net.packet.play import space.uranos.net.packet.OutgoingPacket +// Name on wiki.vg: Entity Position data class EntityRelativeMovePacket( val entityID: Int, val deltaX: Short, diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacket.kt index 47b9f47..b7c6f83 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityRelativeMoveWithOrientationPacket.kt @@ -7,18 +7,22 @@ package space.uranos.net.packet.play import space.uranos.net.packet.OutgoingPacket +// Name on wiki.vg: Entity Position and Rotation data class EntityRelativeMoveWithOrientationPacket( val entityID: Int, val deltaX: Short, val deltaY: Short, val deltaZ: Short, /** - * Absolute value. + * Ignored for entities implementing [HasMovableHead][space.uranos.entity.HasMovableHead]. + * + * [EntityHeadYawPacket][space.uranos.net.packet.play.EntityHeadYawPacket] must be used instead. */ val yaw: UByte, - /** - * Absolute value. - */ - val headPitch: UByte, + val pitch: UByte, val onGround: Boolean -) : OutgoingPacket() +) : OutgoingPacket() { + companion object { + fun convertToDeltaShort(delta: Double): Short = (delta * 32 * 128).toInt().toShort() + } +} diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacket.kt index 3170f1f..6017d92 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/EntityTeleportPacket.kt @@ -5,7 +5,6 @@ package space.uranos.net.packet.play -import space.uranos.Position import space.uranos.net.packet.OutgoingPacket data class EntityTeleportPacket( @@ -13,17 +12,12 @@ data class EntityTeleportPacket( val x: Double, val y: Double, val z: Double, + /** + * Ignored for entities implementing [HasMovableHead][space.uranos.entity.HasMovableHead]. + * + * [EntityHeadYawPacket][space.uranos.net.packet.play.EntityHeadYawPacket] must be used instead. + */ val yaw: UByte, - val headPitch: UByte, + val pitch: UByte, val onGround: Boolean -) : OutgoingPacket() { - constructor(entityID: Int, position: Position, onGround: Boolean) : this( - entityID, - position.x, - position.y, - position.z, - position.yawIn256Steps, - position.headPitchIn256Steps, - onGround - ) -} +) : OutgoingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacket.kt index 30e4f4c..640ab7f 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacket.kt @@ -5,13 +5,16 @@ package space.uranos.net.packet.play -import space.uranos.Position +import space.uranos.entity.Position import space.uranos.net.packet.IncomingPacket +// Name on wiki.vg: Player Position and Rotation (serverbound) /** - * Combination of [PlayerLocationPacket] and [PlayerOrientationPacket]. + * Combination of [PlayerPositionPacket] and [PlayerOrientationPacket]. */ data class IncomingPlayerPositionPacket( val position: Position, + val yaw: Float, + val pitch: Float, val onGround: Boolean ) : IncomingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacket.kt index 48e61a6..d22991e 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/OutgoingPlayerPositionPacket.kt @@ -5,19 +5,23 @@ package space.uranos.net.packet.play -import space.uranos.Position import space.uranos.net.packet.OutgoingPacket import kotlin.random.Random +// Name on wiki.vg: Player Position and Look (clientbound) /** * Teleports the receiving player to the specified position. */ data class OutgoingPlayerPositionPacket( - val position: Position, + val x: Double, + val y: Double, + val z: Double, + val yaw: Float, + val pitch: Float, val relativeX: Boolean = false, val relativeY: Boolean = false, val relativeZ: Boolean = false, val relativeYaw: Boolean = false, - val relativePitch: Boolean = false, + val relativeHeadPitch: Boolean = false, val teleportID: Int = Random.nextInt() ) : OutgoingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacket.kt index 215c907..74dadf1 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacket.kt @@ -5,22 +5,14 @@ package space.uranos.net.packet.play -import space.uranos.Position import space.uranos.net.packet.IncomingPacket +// Name on wiki.vg: Player Rotation /** * Sent by the client to update the player's orientation on the server. - * - * @see [Position] */ data class PlayerOrientationPacket( - /** - * Yaw in degrees. - */ val yaw: Float, - /** - * Pitch in degrees. - */ val pitch: Float, val onGround: Boolean ) : IncomingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerPositionPacket.kt similarity index 74% rename from uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacket.kt rename to uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerPositionPacket.kt index 831d3d1..5c7629e 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/PlayerPositionPacket.kt @@ -5,13 +5,14 @@ package space.uranos.net.packet.play -import space.uranos.Location +import space.uranos.entity.Position import space.uranos.net.packet.IncomingPacket +// Name on wiki.vg: Player Position /** * Sent by the client to update the player's x, y and z coordinates on the server. */ -data class PlayerLocationPacket( - val location: Location, +data class PlayerPositionPacket( + val position: Position, val onGround: Boolean ) : IncomingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacket.kt index 311f696..924eb00 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnExperienceOrbPacket.kt @@ -5,20 +5,15 @@ package space.uranos.net.packet.play -import space.uranos.Location -import space.uranos.Position -import space.uranos.Vector -import space.uranos.entity.EntityType import space.uranos.net.packet.OutgoingPacket -import space.uranos.world.Chunk -import space.uranos.world.ChunkData -import java.util.* /** * Sent to spawn experience orbs. */ data class SpawnExperienceOrbPacket( val entityID: Int, - val location: Location, + val x: Double, + val y: Double, + val z: Double, val amount: Short ) : OutgoingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacket.kt index c0bff77..120c724 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnLivingEntityPacket.kt @@ -5,9 +5,9 @@ package space.uranos.net.packet.play -import space.uranos.Position import space.uranos.Vector import space.uranos.entity.EntityType +import space.uranos.entity.Position import space.uranos.net.packet.OutgoingPacket import java.util.UUID @@ -19,6 +19,9 @@ data class SpawnLivingEntityPacket( val uuid: UUID, val type: EntityType<*>, val position: Position, + val yaw: Float, + val pitch: Float, + val headYaw: Float, /** * Velocity in blocks per tick */ diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnObjectEntityPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnObjectEntityPacket.kt index a299e39..bbfcd9a 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnObjectEntityPacket.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/SpawnObjectEntityPacket.kt @@ -5,9 +5,7 @@ package space.uranos.net.packet.play -import space.uranos.Position import space.uranos.Vector -import space.uranos.entity.EntityType import space.uranos.net.packet.OutgoingPacket import java.util.UUID @@ -17,8 +15,12 @@ import java.util.UUID data class SpawnObjectEntityPacket( val entityID: Int, val uuid: UUID, - val type: EntityType<*>, - val position: Position, + val type: Int, + val x: Double, + val y: Double, + val z: Double, + val yaw: UByte, + val pitch: UByte, val data: Int, val velocity: Vector ) : OutgoingPacket() diff --git a/uranos-packets/src/main/kotlin/space/uranos/util/CreateEntityMovementPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/util/CreateEntityMovementPacket.kt deleted file mode 100644 index 0a25968..0000000 --- a/uranos-packets/src/main/kotlin/space/uranos/util/CreateEntityMovementPacket.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-2021 Moritz Ruth and Uranos contributors - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file - */ - -package space.uranos.util - -import space.uranos.Position -import space.uranos.abs -import space.uranos.net.packet.OutgoingPacket -import space.uranos.net.packet.play.EntityHeadPitchPacket -import space.uranos.net.packet.play.EntityRelativeMovePacket -import space.uranos.net.packet.play.EntityRelativeMoveWithOrientationPacket -import space.uranos.net.packet.play.EntityTeleportPacket - -fun createEntityMovementPacket(entityID: Int, oldPosition: Position, newPosition: Position): OutgoingPacket? { - val delta = abs(newPosition.toVector() - oldPosition.toVector()) - val orientationChanged = oldPosition.yaw != newPosition.yaw || oldPosition.headPitch != newPosition.headPitch - val onGround = true // TODO: Find out what onGround does - - return if (delta.x + delta.y + delta.z == 0.0) { - if (orientationChanged) EntityHeadPitchPacket( - entityID, - newPosition.headPitchIn256Steps, - onGround - ) else null - } else if (delta.x > 8 || delta.y > 8 || delta.z > 8) { - EntityTeleportPacket(entityID, newPosition, onGround) - } else { - if (orientationChanged) EntityRelativeMoveWithOrientationPacket( - entityID, - getDeltaShort(delta.x), - getDeltaShort(delta.y), - getDeltaShort(delta.z), - newPosition.yawIn256Steps, - newPosition.headPitchIn256Steps, - onGround - ) else EntityRelativeMovePacket( - entityID, - getDeltaShort(delta.x), - getDeltaShort(delta.y), - getDeltaShort(delta.z), - onGround - ) - } -} - -private fun getDeltaShort(delta: Double): Short = (delta * 32 * 128).toInt().toShort() diff --git a/uranos-packets/src/main/kotlin/space/uranos/util/SpawnEntity.kt b/uranos-packets/src/main/kotlin/space/uranos/util/SpawnEntity.kt index 8fcfcb8..98c40f0 100644 --- a/uranos-packets/src/main/kotlin/space/uranos/util/SpawnEntity.kt +++ b/uranos-packets/src/main/kotlin/space/uranos/util/SpawnEntity.kt @@ -10,20 +10,37 @@ import space.uranos.net.packet.OutgoingPacket import space.uranos.net.packet.play.SpawnLivingEntityPacket import space.uranos.net.packet.play.SpawnObjectEntityPacket import space.uranos.net.packet.play.SpawnPaintingPacket +import space.uranos.util.numbers.mapToUByte fun Entity.createSpawnPacket(): OutgoingPacket = when (this) { - is LivingEntity -> SpawnLivingEntityPacket( + is LivingEntity -> if (this is HasMovableHead) SpawnLivingEntityPacket( numericID, uuid, type, position, + headYaw, + headPitch, + headYaw, + velocity + ) else SpawnLivingEntityPacket( + numericID, + uuid, + type, + position, + if (this is YawRotatable) yaw else 0f, + if (this is PitchRotatable) pitch else 0f, + 0f, velocity ) is ObjectEntity -> SpawnObjectEntityPacket( numericID, uuid, - type, - position, + type.numericID, + position.x, + position.y, + position.z, + if (this is YawRotatable) yaw.mapToUByte(360f) else 0u, + if (this is PitchRotatable) pitch.mapToUByte(360f) else 0u, getDataValue(), velocity ) @@ -31,7 +48,7 @@ fun Entity.createSpawnPacket(): OutgoingPacket = when (this) { numericID, uuid, motive, - centerLocation, + calculateCenterLocation(), facing ) else -> throw IllegalArgumentException("Unknown entity type") @@ -39,6 +56,7 @@ fun Entity.createSpawnPacket(): OutgoingPacket = when (this) { fun ObjectEntity.getDataValue(): Int = when (this) { is ItemEntity -> 1 + is MinecartEntity -> 2 // TODO: Add remaining else -> throw IllegalArgumentException("Unknown entity type") } diff --git a/uranos-server/src/main/kotlin/space/uranos/UranosServer.kt b/uranos-server/src/main/kotlin/space/uranos/UranosServer.kt index 998591d..cf6d5fc 100644 --- a/uranos-server/src/main/kotlin/space/uranos/UranosServer.kt +++ b/uranos-server/src/main/kotlin/space/uranos/UranosServer.kt @@ -11,20 +11,17 @@ import com.sksamuel.hoplite.ConfigSource import kotlinx.coroutines.runBlocking import space.uranos.config.UranosConfig import space.uranos.entity.* -import space.uranos.entity.event.ViewingChangedEvent -import space.uranos.event.EventHandlerPosition +import space.uranos.entity.impl.* import space.uranos.event.UranosEventBus import space.uranos.event.UranosEventHandlerPositionManager import space.uranos.logging.Logger import space.uranos.logging.UranosLoggingOutputProvider import space.uranos.net.UranosSocketServer -import space.uranos.net.packet.play.DestroyEntitiesPacket import space.uranos.net.packet.play.PlayerInfoPacket import space.uranos.player.UranosPlayer import space.uranos.plugin.UranosPluginManager import space.uranos.server.Server import space.uranos.util.EncryptionUtils -import space.uranos.util.createSpawnPacket import space.uranos.util.msToTicks import space.uranos.util.runInServerThread import space.uranos.world.UranosWorldRegistry @@ -90,6 +87,9 @@ class UranosServer internal constructor() : Server() { override fun create(type: EntityType): T { val entity: UranosEntity = when (type) { CowEntity -> UranosCowEntity(this) + BatEntity -> UranosBatEntity(this) + CreeperEntity -> UranosCreeperEntity(this) + MinecartEntity -> UranosMinecartEntity(this) else -> throw IllegalArgumentException("Entities of this type cannot be created with this function") } @@ -159,12 +159,7 @@ class UranosServer internal constructor() : Server() { } private fun registerListeners() { - eventBus.on(EventHandlerPosition.LAST) { event -> - if (event.target == event.player.entity) return@on - - if (event.viewing) event.player.session.send(event.target.createSpawnPacket()) - else event.player.session.send(DestroyEntitiesPacket(arrayOf(event.target.numericID))) - } + // Nothing } companion object { diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/UranosEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/UranosEntity.kt index cbd642f..a5684c5 100644 --- a/uranos-server/src/main/kotlin/space/uranos/entity/UranosEntity.kt +++ b/uranos-server/src/main/kotlin/space/uranos/entity/UranosEntity.kt @@ -10,11 +10,15 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import space.uranos.* import space.uranos.entity.event.ViewingChangedEvent +import space.uranos.entity.impl.UranosPlayerEntity +import space.uranos.net.packet.OutgoingPacket +import space.uranos.net.packet.play.* import space.uranos.player.Player -import space.uranos.util.TickSynchronizationContainer -import space.uranos.util.WatchableSet -import space.uranos.util.createEntityMovementPacket -import space.uranos.util.memoized +import space.uranos.util.* +import space.uranos.util.collections.WatchableSet +import space.uranos.util.numbers.mapToUByte +import space.uranos.util.numbers.validatePitch +import space.uranos.util.numbers.validateYaw import space.uranos.world.Chunk import space.uranos.world.VoxelLocation import space.uranos.world.World @@ -24,38 +28,16 @@ import java.util.UUID import java.util.WeakHashMap sealed class UranosEntity(server: UranosServer) : Entity { - abstract val chunkKey: Chunk.Key - override fun belongsToChunk(key: Chunk.Key): Boolean = key == chunkKey override val numericID: Int = server.claimEntityID() override val uuid: UUID = UUID.randomUUID() - override val viewers: MutableSet = object : WatchableSet(Collections.newSetFromMap(WeakHashMap())) { - override fun beforeAdd(element: Player) { - if ((this@UranosEntity as? UranosPlayerEntity)?.let { it.player == element } == true) - throw IllegalArgumentException("A player cannot be a viewer of it's own entity") - } - - override fun onAdd(element: Player) { - Uranos.scope.launch { Uranos.eventBus.emit(ViewingChangedEvent(this@UranosEntity, element, true)) } - } - - override fun onRemove(element: Player) { - Uranos.scope.launch { Uranos.eventBus.emit(ViewingChangedEvent(this@UranosEntity, element, false)) } - } - } - - /** - * If players should be added to [viewers] when they join. - */ override var visibleToNewPlayers: Boolean = true private val worldMutex = Mutex() final override var world: World? = null; private set - protected val container = TickSynchronizationContainer() - override suspend fun setWorld(world: World?) { if (world == null && this is PlayerEntity) throw IllegalArgumentException("You cannot set the world of a PlayerEntity to null") @@ -69,41 +51,189 @@ sealed class UranosEntity(server: UranosServer) : Entity { } } - open suspend fun tick() { - container.tick() + protected val addedViewers = mutableSetOf() + protected val removedViewers = mutableSetOf() + + override val viewers: MutableSet = object : WatchableSet(Collections.newSetFromMap(WeakHashMap())) { + override fun beforeAdd(element: Player) { + if ((this@UranosEntity as? UranosPlayerEntity)?.let { it.player == element } == true) + throw IllegalArgumentException("A player cannot be a viewer of it's own entity") + } + + override fun onAdd(element: Player) { + removedViewers.remove(element) + addedViewers.add(element) + Uranos.scope.launch { Uranos.eventBus.emit(ViewingChangedEvent(this@UranosEntity, element, true)) } + } + + override fun onRemove(element: Player) { + addedViewers.remove(element) + removedViewers.add(element) + Uranos.scope.launch { Uranos.eventBus.emit(ViewingChangedEvent(this@UranosEntity, element, false)) } + } + } + + abstract suspend fun tick() + abstract val chunkKey: Chunk.Key + + protected val container = TickSynchronizationContainer() + + protected fun sendSpawnAndDestroyPackets() { + if (addedViewers.isNotEmpty()) createSpawnPacket().let { packet -> addedViewers.forEach { it.session.send(packet) } } + if (removedViewers.isNotEmpty()) DestroyEntitiesPacket(arrayOf(numericID)).let { packet -> removedViewers.forEach { it.session.send(packet) } } + } + + protected fun finishTick() { + addedViewers.clear() + removedViewers.clear() } } -abstract class UranosLivingEntity(server: UranosServer) : UranosEntity(server), LivingEntity { +sealed class UranosLivingEntity(server: UranosServer) : UranosEntity(server), LivingEntity { override var velocity: Vector = Vector.ZERO + override var position: Position = Position.ZERO + override val chunkKey: Chunk.Key by memoized({ position }) { Chunk.Key.from(position) } +} + +abstract class UranosNotHasMovableHeadLivingEntity(server: UranosServer) : UranosLivingEntity(server) { + override var velocity: Vector = Vector.ZERO + override var position: Position = Position.ZERO + + override val chunkKey: Chunk.Key by memoized({ position }) { Chunk.Key.from(position) } private var lastSentPosition: Position = Position.ZERO - override var position: Position by container.ifChanged(Position.ZERO) { value -> - if (viewers.isNotEmpty()) createEntityMovementPacket(numericID, lastSentPosition, value)?.let { - for (viewer in viewers) { - viewer.session.send(it) + private var lastSentYaw: Float = 0f + private var lastSentPitch: Float = 0f + + final override suspend fun tick() { + container.tick() + + val viewersWithoutAdded = viewers.subtract(addedViewers) + if (viewersWithoutAdded.isNotEmpty()) { + val packet = createMovementPacket() + if (packet != null) { + viewersWithoutAdded.forEach { it.session.send(packet) } } } - lastSentPosition = value + if (this is PitchRotatable) lastSentPitch = pitch + if (this is YawRotatable) lastSentYaw = yaw + + sendSpawnAndDestroyPackets() + finishTick() } - override val chunkKey: Chunk.Key by memoized({ position }) { Chunk.Key.from(position) } + private fun createMovementPacket(): OutgoingPacket? = createNotHasMovableHeadMovementPacket(position, lastSentPosition, lastSentYaw, lastSentPitch) +} + +abstract class UranosHasMovableHeadLivingEntity(server: UranosServer) : UranosLivingEntity(server), HasMovableHead { + override var headYaw: Float = 0f + set(value) { + validateYaw(value, "headYaw"); field = value + } + + override var headPitch: Float = 0f + set(value) { + validatePitch(value, "headPitch"); field = value + } + + final override suspend fun tick() { + container.tick() + + val viewersWithoutAdded = viewers.subtract(addedViewers) + if (viewersWithoutAdded.isNotEmpty()) { + val packets = createMovementPackets() + if (packets.isNotEmpty()) { + viewersWithoutAdded.forEach { it.session.send(packets) } + } + } + + oldPosition = position + oldHeadPitch = headPitch + oldHeadYaw = headYaw + + sendSpawnAndDestroyPackets() + finishTick() + } + + private var oldPosition: Position = Position.ZERO + private var oldHeadYaw: Float = 0f + private var oldHeadPitch: Float = 0f + + private fun createMovementPackets(): ArrayList { + val packets = ArrayList(2) + + val delta = position.asVector() - oldPosition.asVector() + val absoluteDelta = abs(delta) + val onGround = true + + val oldHeadPitchUByte = oldHeadPitch.mapToUByte(90f) + val newHeadPitchUByte = headPitch.mapToUByte(90f) + val oldHeadYawUByte = oldHeadYaw.mapToUByte(360f) + val newHeadYawUByte = headYaw.mapToUByte(360f) + + if (absoluteDelta.x + absoluteDelta.y + absoluteDelta.z == 0.0) { + if (oldHeadPitchUByte != newHeadPitchUByte) packets += EntityOrientationPacket( + numericID, + 0u, + newHeadPitchUByte, + onGround + ) + } else if (absoluteDelta.x > 8 || absoluteDelta.y > 8 || absoluteDelta.z > 8) { + packets += EntityTeleportPacket(numericID, position.x, position.y, position.z, 0u, newHeadPitchUByte, onGround) + } else { + packets += if (oldHeadPitchUByte != newHeadPitchUByte) EntityRelativeMoveWithOrientationPacket( + numericID, + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.x), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.y), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.z), + 0u, + newHeadPitchUByte, + onGround + ) else EntityRelativeMovePacket( + numericID, + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.x), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.y), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.z), + onGround + ) + } + + if (oldHeadYawUByte != newHeadYawUByte) packets += EntityHeadYawPacket(numericID, newHeadYawUByte) + + return packets + } } abstract class UranosObjectEntity(server: UranosServer) : UranosEntity(server), ObjectEntity { override var velocity: Vector = Vector.ZERO - - private var lastSentPosition: Position = Position.ZERO - override var position: Position by container.ifChanged(Position.ZERO) { value -> - createEntityMovementPacket(numericID, lastSentPosition, value)?.let { - for (viewer in viewers) { - viewer.session.send(it) - } - } - } + override var position: Position = Position.ZERO override val chunkKey: Chunk.Key by memoized({ position }) { Chunk.Key.from(position) } + + private var lastSentPosition: Position = Position.ZERO + private var lastSentYaw: Float = 0f + private var lastSentPitch: Float = 0f + + final override suspend fun tick() { + container.tick() + + val viewersWithoutAdded = viewers.subtract(addedViewers) + if (viewersWithoutAdded.isNotEmpty()) { + val packet = createMovementPacket() + if (packet != null) { + viewersWithoutAdded.forEach { it.session.send(packet) } + } + } + + if (this is PitchRotatable) lastSentPitch = pitch + if (this is YawRotatable) lastSentYaw = yaw + + sendSpawnAndDestroyPackets() + finishTick() + } + + private fun createMovementPacket(): OutgoingPacket? = createNotHasMovableHeadMovementPacket(position, lastSentPosition, lastSentYaw, lastSentPitch) } class UranosPaintingEntity( @@ -113,4 +243,76 @@ class UranosPaintingEntity( override val motive: PaintingMotive ) : UranosEntity(server), PaintingEntity { override val chunkKey: Chunk.Key get() = Chunk.Key.from(topLeftLocation) + + private var lastSentTopLeftLocation: VoxelLocation = topLeftLocation + + override suspend fun tick() { + container.tick() + + if (lastSentTopLeftLocation != topLeftLocation) { + val viewersWithoutAdded = viewers.subtract(addedViewers) + if (viewersWithoutAdded.isNotEmpty()) { + val centerLocation = calculateCenterLocation() + val packet = EntityTeleportPacket( + numericID, + centerLocation.x.toDouble(), + centerLocation.y.toDouble(), + centerLocation.z.toDouble(), + 0u, + 0u, + true + ) + + viewersWithoutAdded.forEach { it.session.send(packet) } + } + } + + lastSentTopLeftLocation = topLeftLocation + + sendSpawnAndDestroyPackets() + finishTick() + } +} + +fun UranosEntity.createNotHasMovableHeadMovementPacket( + position: Position, + lastSentPosition: Position, + lastSentYaw: Float, + lastSentPitch: Float +): OutgoingPacket? { + val delta = position.asVector() - lastSentPosition.asVector() + val absoluteDelta = abs(delta) + val onGround = true + + val oldPitchUByte = lastSentPitch.mapToUByte(90f) + val newPitchUByte = if (this is PitchRotatable) pitch.mapToUByte(90f) else 0u + val oldYawUByte = lastSentYaw.mapToUByte(360f) + val newYawUByte = if (this is YawRotatable) yaw.mapToUByte(360f) else 0u + + return if (absoluteDelta.x + absoluteDelta.y + absoluteDelta.z == 0.0) { + if (oldPitchUByte != newPitchUByte || oldYawUByte != newYawUByte) EntityOrientationPacket( + numericID, + newYawUByte, + newPitchUByte, + onGround + ) else null + } else if (absoluteDelta.x > 8 || absoluteDelta.y > 8 || absoluteDelta.z > 8) { + EntityTeleportPacket(numericID, position.x, position.y, position.z, newYawUByte, newPitchUByte, onGround) + } else { + if (oldPitchUByte != newPitchUByte || oldYawUByte != newYawUByte) EntityRelativeMoveWithOrientationPacket( + numericID, + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.x), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.y), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.z), + newYawUByte, + newPitchUByte, + onGround + ) else EntityRelativeMovePacket( + numericID, + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.x), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.y), + EntityRelativeMoveWithOrientationPacket.convertToDeltaShort(delta.z), + onGround + ) + } } diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosBatEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosBatEntity.kt new file mode 100644 index 0000000..853821f --- /dev/null +++ b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosBatEntity.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity.impl + +import space.uranos.UranosServer +import space.uranos.entity.BatEntity +import space.uranos.entity.UranosHasMovableHeadLivingEntity + +class UranosBatEntity(server: UranosServer) : UranosHasMovableHeadLivingEntity(server), BatEntity diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCowEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCowEntity.kt new file mode 100644 index 0000000..76f2a53 --- /dev/null +++ b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCowEntity.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity.impl + +import space.uranos.UranosServer +import space.uranos.entity.CowEntity +import space.uranos.entity.UranosHasMovableHeadLivingEntity + +class UranosCowEntity(server: UranosServer) : UranosHasMovableHeadLivingEntity(server), CowEntity diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCreeperEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCreeperEntity.kt new file mode 100644 index 0000000..1ec17dc --- /dev/null +++ b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosCreeperEntity.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity.impl + +import space.uranos.UranosServer +import space.uranos.entity.CreeperEntity +import space.uranos.entity.UranosHasMovableHeadLivingEntity + +class UranosCreeperEntity(server: UranosServer) : UranosHasMovableHeadLivingEntity(server), CreeperEntity diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosMinecartEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosMinecartEntity.kt new file mode 100644 index 0000000..e29c4a9 --- /dev/null +++ b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosMinecartEntity.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2020-2021 Moritz Ruth and Uranos contributors + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file + */ + +package space.uranos.entity.impl + +import space.uranos.UranosServer +import space.uranos.entity.MinecartEntity +import space.uranos.entity.UranosObjectEntity +import space.uranos.util.numbers.validatePitch +import space.uranos.util.numbers.validateYaw + +class UranosMinecartEntity(server: UranosServer) : UranosObjectEntity(server), MinecartEntity { + override var yaw: Float = 0f + set(value) { + validateYaw(value); field = value + } + + override var pitch: Float = 0f + set(value) { + validatePitch(value); field = value + } +} diff --git a/uranos-server/src/main/kotlin/space/uranos/entity/UranosPlayerEntity.kt b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosPlayerEntity.kt similarity index 66% rename from uranos-server/src/main/kotlin/space/uranos/entity/UranosPlayerEntity.kt rename to uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosPlayerEntity.kt index cecaa40..f51f7a0 100644 --- a/uranos-server/src/main/kotlin/space/uranos/entity/UranosPlayerEntity.kt +++ b/uranos-server/src/main/kotlin/space/uranos/entity/impl/UranosPlayerEntity.kt @@ -3,15 +3,17 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file */ -package space.uranos.entity +package space.uranos.entity.impl import space.uranos.UranosServer +import space.uranos.entity.PlayerEntity +import space.uranos.entity.UranosHasMovableHeadLivingEntity import space.uranos.player.Player import java.util.UUID class UranosPlayerEntity( server: UranosServer, override val player: Player -) : UranosLivingEntity(server), PlayerEntity { +) : UranosHasMovableHeadLivingEntity(server), PlayerEntity { override val uuid: UUID = player.uuid } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt b/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt index ea1e4f0..74c25e9 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt @@ -17,6 +17,7 @@ import space.uranos.net.event.SessionAfterLoginEvent import space.uranos.net.packet.login.* import space.uranos.net.packet.play.* import space.uranos.player.UranosPlayer +import space.uranos.player.event.PlayerReadyEvent import space.uranos.tag.TagRegistry import space.uranos.util.AuthenticationHelper import space.uranos.util.EncryptionUtils @@ -134,6 +135,7 @@ class LoginAndJoinProcedure(val session: UranosSession) { event.gameMode, initialWorldAndLocation.first, initialWorldAndLocation.second, + event.headYaw, event.headPitch, event.invulnerable, event.reducedDebugInfo, @@ -160,8 +162,6 @@ class LoginAndJoinProcedure(val session: UranosSession) { state.uuid, state.gameMode, settings, - state.position, - state.headPitch, state.reducedDebugInfo, state.fieldOfView, state.canFly, @@ -182,7 +182,7 @@ class LoginAndJoinProcedure(val session: UranosSession) { // session.send(DeclareCommandsPacket(session.server.commandRegistry.items.values)) // UnlockRecipes - session.sendNow(OutgoingPlayerPositionPacket(state.position)) + session.sendNow(OutgoingPlayerPositionPacket(state.position.x, state.position.y, state.position.z, state.headYaw, state.headPitch)) session.sendNow(PlayerInfoPacket(PlayerInfoPacket.Action.AddPlayer((session.server.players + player).map { it.uuid to PlayerInfoPacket.Action.AddPlayer.Data( @@ -209,6 +209,8 @@ class LoginAndJoinProcedure(val session: UranosSession) { player.spawnInitially(state.world) session.state = Session.State.Playing(player) + session.server.eventBus.emit(PlayerReadyEvent(session.player!!)) + // WorldBorder session.send(CompassTargetPacket(player.compassTarget)) } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketHandler.kt index fbcb44a..ab0d2ba 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/IncomingPlayerPositionPacketHandler.kt @@ -10,6 +10,10 @@ import space.uranos.net.UranosSession object IncomingPlayerPositionPacketHandler : PacketReceivedEventHandler() { override suspend fun handle(session: UranosSession, packet: IncomingPlayerPositionPacket) { - session.earlyPlayer?.let { it.entity.position = packet.position } ?: error("Player not yet initialized") + session.earlyPlayer?.let { + it.entity.position = packet.position + it.entity.headYaw = packet.yaw + it.entity.headPitch = packet.pitch + } ?: error("Player not yet initialized") } } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayProtocolHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayProtocolHandler.kt index 4ed3774..5c64d21 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayProtocolHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayProtocolHandler.kt @@ -15,6 +15,6 @@ object PlayProtocolHandler : ProtocolPacketReceivedEventHandler( IncomingPlayerPositionPacket::class to IncomingPlayerPositionPacketHandler, IncomingPluginMessagePacket::class to IncomingPluginMessagePacketHandler, PlayerOrientationPacket::class to PlayerOrientationPacketHandler, - PlayerLocationPacket::class to PlayerLocationPacketHandler + PlayerPositionPacket::class to PlayerLocationPacketHandler ) ) diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketHandler.kt index e99d59b..16ea0cf 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerLocationPacketHandler.kt @@ -8,13 +8,13 @@ package space.uranos.net.packet.play import space.uranos.net.PacketReceivedEventHandler import space.uranos.net.UranosSession -object PlayerLocationPacketHandler : PacketReceivedEventHandler() { - override suspend fun handle(session: UranosSession, packet: PlayerLocationPacket) { +object PlayerLocationPacketHandler : PacketReceivedEventHandler() { + override suspend fun handle(session: UranosSession, packet: PlayerPositionPacket) { val player = session.earlyPlayer ?: error("Player not yet initialized") player.entity.position = player.entity.position.copy( - x = packet.location.x, - y = packet.location.y, - z = packet.location.z + x = packet.position.x, + y = packet.position.y, + z = packet.position.z ) } } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketHandler.kt index a4350e4..c76b8e0 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/PlayerOrientationPacketHandler.kt @@ -10,7 +10,9 @@ import space.uranos.net.UranosSession object PlayerOrientationPacketHandler : PacketReceivedEventHandler() { override suspend fun handle(session: UranosSession, packet: PlayerOrientationPacket) { - session.earlyPlayer?.entity?.let { it.position = it.position.copy(yaw = packet.yaw, headPitch = packet.pitch) } - ?: error("Player not yet initialized") + session.earlyPlayer?.entity?.let { + it.headYaw = packet.yaw + it.headPitch = packet.pitch + } ?: error("Player not initialized yet") } } diff --git a/uranos-server/src/main/kotlin/space/uranos/player/UranosPlayer.kt b/uranos-server/src/main/kotlin/space/uranos/player/UranosPlayer.kt index c43b246..dbead37 100644 --- a/uranos-server/src/main/kotlin/space/uranos/player/UranosPlayer.kt +++ b/uranos-server/src/main/kotlin/space/uranos/player/UranosPlayer.kt @@ -5,7 +5,6 @@ package space.uranos.player -import space.uranos.Position import space.uranos.chat.TextComponent import space.uranos.entity.PlayerEntity import space.uranos.entity.safeWorld @@ -15,7 +14,7 @@ import space.uranos.net.packet.play.ChunkLightDataPacket import space.uranos.net.packet.play.PlayerInfoPacket import space.uranos.net.packet.play.SelectedHotbarSlotPacket import space.uranos.util.TickSynchronizationContainer -import space.uranos.util.clampArgument +import space.uranos.util.numbers.validateParameterIsInRange import space.uranos.world.Chunk import space.uranos.world.VoxelLocation import space.uranos.world.World @@ -28,8 +27,6 @@ class UranosPlayer( override val uuid: UUID, override var gameMode: GameMode, override var settings: Player.Settings, - position: Position, - headPitch: Float, override var reducedDebugInfo: Boolean, override var fieldOfView: Float, override var canFly: Boolean, @@ -43,7 +40,7 @@ class UranosPlayer( override var selectedHotbarSlot by container.ifChanged( selectedHotbarSlot, - { clampArgument("selectedHotbarSlot", 0..8, it) }) { + { validateParameterIsInRange("selectedHotbarSlot", 0..8, it) }) { session.sendNow(SelectedHotbarSlotPacket(it)) } @@ -60,12 +57,10 @@ class UranosPlayer( override var currentlyViewedChunks = emptyList() - override val entity: PlayerEntity = session.server.createPlayerEntity(this).also { - it.position = position - } + override val entity: PlayerEntity = session.server.createPlayerEntity(this) suspend fun spawnInitially(world: World) { - session.server.entities.forEach { if (it.visibleToNewPlayers && it != entity) it.viewers.add(this) } + session.server.entities.forEach { if (it.visibleToNewPlayers && it != entity && it.world === world) it.viewers.add(this) } entity.setWorld(world) updateCurrentlyViewedChunks() sendChunksAndLight()