From 32b83a7e604914bbddfe8cdb553222889afbee29 Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Fri, 8 Jan 2021 19:21:24 +0100 Subject: [PATCH] Add ClientRequest packet --- .../kotlin/space/uranos/event/EventBus.kt | 27 ++++++++++++++----- .../packet/play/ClientRequestPacketCodec.kt | 21 +++++++++++++++ .../uranos/net/packet/play/PlayProtocol.kt | 1 + .../net/packet/play/ClientRequestPacket.kt | 15 +++++++++++ .../space/uranos/net/LoginAndJoinProcedure.kt | 4 +-- .../kotlin/space/uranos/net/UranosSession.kt | 3 ++- .../login/EncryptionResponsePacketHandler.kt | 3 ++- .../packet/login/LoginStartPacketHandler.kt | 3 ++- .../play/ClientSettingsPacketHandler.kt | 3 ++- 9 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacketCodec.kt create mode 100644 uranos-packets/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacket.kt diff --git a/uranos-api/src/main/kotlin/space/uranos/event/EventBus.kt b/uranos-api/src/main/kotlin/space/uranos/event/EventBus.kt index 913917f..652bb9f 100644 --- a/uranos-api/src/main/kotlin/space/uranos/event/EventBus.kt +++ b/uranos-api/src/main/kotlin/space/uranos/event/EventBus.kt @@ -39,6 +39,7 @@ abstract class EventEmitter { ): EventHandler { lateinit var handler: EventHandler + @Suppress("JoinDeclarationAndAssignment") // false positive handler = on(eventType, handlerPosition) { fn(it, handler::remove) } @@ -56,12 +57,21 @@ abstract class EventEmitter { ): EventHandler = onRemovable(eventType, handlerPosition) { event, remove -> remove(); fn(event) } /** - * Suspends until an event of type [T] is emitted and returns it. + * Suspends until an event of type [T] is emitted for which [predicate] returns true and returns it. */ - suspend fun waitFor(eventType: KClass, handlerPosition: EventHandlerPosition = EventHandlerPosition.NORMAL): T = + suspend fun waitFor( + eventType: KClass, + handlerPosition: EventHandlerPosition = EventHandlerPosition.NORMAL, + predicate: (event: T) -> Boolean = { true } + ): T = suspendCancellableCoroutine { c -> - val handler = EventHandler(this, eventType, Plugin.getCalling(), handlerPosition) { - c.resume(it) + lateinit var handler: EventHandler<*> + + handler = EventHandler(this, eventType, Plugin.getCalling(), handlerPosition) { + if (predicate(it)) { + handler.remove() + c.resume(it) + } } handlers.add(handler) @@ -103,10 +113,13 @@ abstract class EventEmitter { ): EventHandler = once(T::class, handlerPosition, fn) /** - * Suspends until an event of type [T] is emitted and returns it. + * Suspends until an event of type [T] is emitted for which [predicate] returns true and returns it. */ - suspend inline fun waitFor(position: EventHandlerPosition = EventHandlerPosition.NORMAL): T = - waitFor(T::class, position) + suspend inline fun waitFor( + position: EventHandlerPosition = EventHandlerPosition.NORMAL, + noinline predicate: (event: T) -> Boolean = { true } + ): T = + waitFor(T::class, position, predicate) } abstract class EventBus: EventEmitter() { diff --git a/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacketCodec.kt b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacketCodec.kt new file mode 100644 index 0000000..e7fa663 --- /dev/null +++ b/uranos-packet-codecs/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacketCodec.kt @@ -0,0 +1,21 @@ +/* + * 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.net.packet.play + +import io.netty.buffer.ByteBuf +import space.uranos.net.MinecraftProtocolDataTypes.readVarInt +import space.uranos.net.packet.IncomingPacketCodec + +object ClientRequestPacketCodec : + IncomingPacketCodec(0x04, ClientRequestPacket::class) { + override fun decode(msg: ByteBuf): ClientRequestPacket = ClientRequestPacket( + when (msg.readVarInt()) { + 0 -> ClientRequestPacket.Type.PERFORM_RESPAWN + 1 -> ClientRequestPacket.Type.STATS + else -> throw Exception("Unknown client request type") + } + ) +} 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 39dadd7..ede8bab 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 @@ -11,6 +11,7 @@ object PlayProtocol : Protocol( "PLAY", ChunkDataPacketCodec, ChunkLightDataPacketCodec, + ClientRequestPacketCodec, ClientSettingsPacketCodec, CompassTargetPacketCodec, DeclareCommandsPacketCodec, diff --git a/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacket.kt b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacket.kt new file mode 100644 index 0000000..0f9c24e --- /dev/null +++ b/uranos-packets/src/main/kotlin/space/uranos/net/packet/play/ClientRequestPacket.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.net.packet.play + +import space.uranos.net.packet.IncomingPacket + +data class ClientRequestPacket(val type: Type) : IncomingPacket() { + enum class Type { + PERFORM_RESPAWN, + STATS + } +} 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 ad3a229..7f71b14 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/LoginAndJoinProcedure.kt @@ -207,13 +207,11 @@ class LoginAndJoinProcedure(val session: UranosSession) { session.scheduleKeepAlivePacket(true) player.spawnInitially(state.world) + session.state = Session.State.Playing(player) player.sendChunksAndLight() // WorldBorder session.send(CompassTargetPacket(player.compassTarget)) session.send(OutgoingPlayerPositionPacket(state.position)) - - // TODO: Wait for ClientStatus(action=0) packet - session.state = Session.State.Playing(player) } } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/UranosSession.kt b/uranos-server/src/main/kotlin/space/uranos/net/UranosSession.kt index bf6baec..1047d61 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/UranosSession.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/UranosSession.kt @@ -44,7 +44,8 @@ class UranosSession(val channel: io.netty.channel.Channel, val server: UranosSer override var ping: Int = -1 set(value) { if (field == -1) { - val packet = PlayerInfoPacket(PlayerInfoPacket.Action.UpdateLatency(mapOf(player!!.uuid to value))) + val packet = + PlayerInfoPacket(PlayerInfoPacket.Action.UpdateLatency(mapOf((state as State.WithPlayer).player.uuid to value))) scope.launch { server.players.forEach { it.session.send(packet) } } } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/login/EncryptionResponsePacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/login/EncryptionResponsePacketHandler.kt index 365d8a8..86ca2bb 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/login/EncryptionResponsePacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/login/EncryptionResponsePacketHandler.kt @@ -5,13 +5,14 @@ package space.uranos.net.packet.login +import kotlinx.coroutines.launch import space.uranos.net.PacketReceivedEventHandler import space.uranos.net.UranosSession object EncryptionResponsePacketHandler : PacketReceivedEventHandler() { override suspend fun handle(session: UranosSession, packet: EncryptionResponsePacket) { try { - session.joinProcedure.onEncryptionResponse(packet) + session.scope.launch { session.joinProcedure.onEncryptionResponse(packet) } } catch (e: IllegalStateException) { session.failAndDisconnectBecauseOfClient("Client sent EncryptionResponsePacket when it was not allowed.") } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/login/LoginStartPacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/login/LoginStartPacketHandler.kt index 959291d..646dbd1 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/login/LoginStartPacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/login/LoginStartPacketHandler.kt @@ -5,13 +5,14 @@ package space.uranos.net.packet.login +import kotlinx.coroutines.launch import space.uranos.net.PacketReceivedEventHandler import space.uranos.net.UranosSession object LoginStartPacketHandler : PacketReceivedEventHandler() { override suspend fun handle(session: UranosSession, packet: LoginStartPacket) { try { - session.joinProcedure.start(packet) + session.scope.launch { session.joinProcedure.start(packet) } } catch (e: IllegalStateException) { session.failAndDisconnectBecauseOfClient("Client sent LoginStartPacket when it was not allowed") } diff --git a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketHandler.kt b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketHandler.kt index a17d33d..fef71a7 100644 --- a/uranos-server/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketHandler.kt +++ b/uranos-server/src/main/kotlin/space/uranos/net/packet/play/ClientSettingsPacketHandler.kt @@ -5,6 +5,7 @@ package space.uranos.net.packet.play +import kotlinx.coroutines.launch import space.uranos.net.PacketReceivedEventHandler import space.uranos.net.UranosSession import space.uranos.player.UranosPlayer @@ -16,7 +17,7 @@ object ClientSettingsPacketHandler : PacketReceivedEventHandler