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