diff --git a/blokk-api/build.gradle.kts b/blokk-api/build.gradle.kts index e31dc14..173e3b2 100644 --- a/blokk-api/build.gradle.kts +++ b/blokk-api/build.gradle.kts @@ -1,5 +1,6 @@ plugins { kotlin("jvm") + kotlin("kapt") } group = rootProject.group @@ -13,13 +14,22 @@ repositories { val spekVersion = "2.0.12" dependencies { + // Kotlin implementation(kotlin("stdlib-jdk8")) implementation(kotlin("reflect")) - implementation("com.google.code.gson:gson:2.8.6") - api("org.slf4j:slf4j-api:1.7.30") - api("io.netty:netty-buffer:4.1.50.Final") api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8") + // JSON + kapt("com.squareup.moshi:moshi-kotlin-codegen:1.9.3") + api("com.squareup.moshi:moshi:1.9.3") + + // Logging + api("org.slf4j:slf4j-api:1.7.30") + + // Netty + api("io.netty:netty-buffer:4.1.50.Final") + + // Testing testImplementation("io.strikt:strikt-core:0.26.1") testImplementation("org.spekframework.spek2:spek-dsl-jvm:$spekVersion") testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:$spekVersion") diff --git a/blokk-api/src/main/kotlin/space/blokk/Blokk.kt b/blokk-api/src/main/kotlin/space/blokk/Blokk.kt index f841335..6571461 100644 --- a/blokk-api/src/main/kotlin/space/blokk/Blokk.kt +++ b/blokk-api/src/main/kotlin/space/blokk/Blokk.kt @@ -1,5 +1,7 @@ package space.blokk +import com.squareup.moshi.Moshi +import space.blokk.chat.ChatComponent import space.blokk.events.EventTargetGroup import space.blokk.net.Session import space.blokk.server.Server @@ -18,4 +20,9 @@ object Blokk: BlokkProvider { private var provider: BlokkProvider? = null override val server get() = provider!!.server override val sessions get() = provider!!.sessions + + val json = Moshi.Builder() + .add(ChatComponent.Adapter) + .add(ChatComponent.Color.Adapter) + .build()!! } diff --git a/blokk-api/src/main/kotlin/space/blokk/chat/ChatComponent.kt b/blokk-api/src/main/kotlin/space/blokk/chat/ChatComponent.kt index 780c5fe..0fe8296 100644 --- a/blokk-api/src/main/kotlin/space/blokk/chat/ChatComponent.kt +++ b/blokk-api/src/main/kotlin/space/blokk/chat/ChatComponent.kt @@ -1,23 +1,89 @@ package space.blokk.chat +import com.squareup.moshi.* +import space.blokk.Blokk import kotlin.reflect.KClass sealed class ChatComponent { - abstract val extra: ChatComponent? + abstract val bold: Boolean + abstract val italic: Boolean + abstract val underlined: Boolean + abstract val strikethrough: Boolean + abstract val obfuscated: Boolean + abstract val color: Color? + + /** + * Cannot be an empty list. Use null instead. + */ + abstract val extra: List? + + init { + @Suppress("LeakingThis") + if (extra?.isEmpty() == true) throw IllegalArgumentException("extra cannot be an empty list. Use null instead.") + } fun getExtraTypes(): List> { - val types = mutableListOf>() - var current = extra - while (current != null) { - types.add(current::class) - current = current.extra + val types = mutableSetOf>() + val extras = extra?.toMutableList() ?: return emptyList() + while (extras.isNotEmpty()) { + extras.toList().forEach { + types.add(it::class) + extras.remove(it) + it.extra?.let { extra -> extras.addAll(extra) } + } } return types.toList() } + + enum class Color() { + BLACK, + DARK_BLUE, + DARK_GREEN, + DARK_AQUA, + DARK_RED, + DARK_PURPLE, + GOLD, + GRAY, + DARK_GRAY, + BLUE, + GREEN, + AQUA, + RED, + LIGHT_PURPLE, + YELLOW, + WHITE; + + object Adapter { + @ToJson fun toJson(value: Color) = value.name.toLowerCase() + @FromJson fun fromJson(value: String) = valueOf(value.toUpperCase()) + } + } + + object Adapter { + @FromJson fun fromJson(reader: JsonReader): ChatComponent? { + throw UnsupportedOperationException("ChatComponent cannot be deserialized.") + } + + @ToJson fun toJson(writer: JsonWriter, value: ChatComponent?) { + @Suppress("UNCHECKED_CAST") + if (value == null) writer.nullValue() + else (Blokk.json.adapter(value::class.java) as JsonAdapter).toJson(writer, value) + } + } } -data class TextComponent(val text: String, override val extra: ChatComponent? = null): ChatComponent() { +@JsonClass(generateAdapter = true) +data class TextComponent( + val text: String, + override val bold: Boolean = false, + override val italic: Boolean = false, + override val underlined: Boolean = false, + override val strikethrough: Boolean = false, + override val obfuscated: Boolean = false, + override val color: Color? = null, + override val extra: List? = null +): ChatComponent() { companion object { /** * Creates a new [TextComponent] instance using [text] and returns it. diff --git a/blokk-api/src/main/kotlin/space/blokk/chat/FormattingCode.kt b/blokk-api/src/main/kotlin/space/blokk/chat/FormattingCode.kt index 6131f38..283fbcf 100644 --- a/blokk-api/src/main/kotlin/space/blokk/chat/FormattingCode.kt +++ b/blokk-api/src/main/kotlin/space/blokk/chat/FormattingCode.kt @@ -1,8 +1,8 @@ package space.blokk.chat /** - * Legacy formatting codes. You should use [ChatComponent][space.blokk.chat.ChatComponent] whenever it's possible, but sometimes - * these codes are required, for example in + * Legacy formatting codes. You should use [ChatComponent][space.blokk.chat.ChatComponent] whenever it's possible, + * but sometimes these codes are required, for example in * [the name of a player in a server list sample][space.blokk.net.protocols.status.ResponsePacket.Players.SampleEntry.name]. */ enum class FormattingCode(private val char: Char) { diff --git a/blokk-api/src/main/kotlin/space/blokk/events/Cancellable.kt b/blokk-api/src/main/kotlin/space/blokk/events/Cancellable.kt index e891702..fab8ba9 100644 --- a/blokk-api/src/main/kotlin/space/blokk/events/Cancellable.kt +++ b/blokk-api/src/main/kotlin/space/blokk/events/Cancellable.kt @@ -7,9 +7,9 @@ interface Cancellable { /** * Only executes [fn] if [isCancelled][Cancellable.isCancelled] is true. */ -inline fun Cancellable.ifCancelled(fn: () -> Unit) = if (isCancelled) fn() else Unit +inline fun T.ifCancelled(fn: (T) -> R): R? = if (isCancelled) fn(this) else null /** * Only executes [fn] if [isCancelled][Cancellable.isCancelled] is false. */ -inline fun Cancellable.ifNotCancelled(fn: () -> T): T? = if (!isCancelled) fn() else null +inline fun T.ifNotCancelled(fn: (T) -> R): R? = if (!isCancelled) fn(this) else null diff --git a/blokk-api/src/main/kotlin/space/blokk/events/EventBus.kt b/blokk-api/src/main/kotlin/space/blokk/events/EventBus.kt index 9ce8cdb..302608d 100644 --- a/blokk-api/src/main/kotlin/space/blokk/events/EventBus.kt +++ b/blokk-api/src/main/kotlin/space/blokk/events/EventBus.kt @@ -1,8 +1,7 @@ package space.blokk.events import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import space.blokk.Blokk +import kotlinx.coroutines.async import space.blokk.plugins.Plugin import kotlin.reflect.KClass import kotlin.reflect.KFunction @@ -17,21 +16,15 @@ class EventBus(private val eventClass: KClass, private va /** * Invokes all previously registered event handlers sorted by their priority * and the order in which they were registered. + * + * @return [event] */ - suspend fun emitAndAwait(event: T): T { - handlers.filter { it.eventType.isInstance(event) }.forEach { - scope.launch { - it.fn.callSuspend(it.listener, event) - } - } - + suspend fun emit(event: T): T { + handlers.filter { it.eventType.isInstance(event) }.forEach { it.fn.callSuspend(it.listener, event) } return event } - fun emit(event: T): T { - Blokk.server.scope.launch { emitAndAwait(event) } - return event - } + fun emitAsync(event: T) = scope.async { emit(event) } /** * Registers all [event handlers][EventHandler] in [listener] to be invoked when their corresponding event is emitted. diff --git a/blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketReceivedEvent.kt b/blokk-api/src/main/kotlin/space/blokk/net/events/PacketReceivedEvent.kt similarity index 60% rename from blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketReceivedEvent.kt rename to blokk-api/src/main/kotlin/space/blokk/net/events/PacketReceivedEvent.kt index be5b494..b50d337 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketReceivedEvent.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/events/PacketReceivedEvent.kt @@ -4,6 +4,6 @@ import space.blokk.events.Cancellable import space.blokk.net.Session import space.blokk.net.protocols.IncomingPacket -class SessionPacketReceivedEvent(session: Session, var packet: T): SessionEvent(session), Cancellable { +class PacketReceivedEvent(session: Session, var packet: T): SessionEvent(session), Cancellable { override var isCancelled = false } diff --git a/blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketSendEvent.kt b/blokk-api/src/main/kotlin/space/blokk/net/events/PacketSendEvent.kt similarity index 62% rename from blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketSendEvent.kt rename to blokk-api/src/main/kotlin/space/blokk/net/events/PacketSendEvent.kt index f344207..2751f57 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/events/SessionPacketSendEvent.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/events/PacketSendEvent.kt @@ -4,6 +4,6 @@ import space.blokk.events.Cancellable import space.blokk.net.Session import space.blokk.net.protocols.OutgoingPacket -class SessionPacketSendEvent(session: Session, var packet: OutgoingPacket): SessionEvent(session), Cancellable { +class PacketSendEvent(session: Session, var packet: OutgoingPacket): SessionEvent(session), Cancellable { override var isCancelled = false } diff --git a/blokk-api/src/main/kotlin/space/blokk/net/events/ServerListInfoRequestEvent.kt b/blokk-api/src/main/kotlin/space/blokk/net/events/ServerListInfoRequestEvent.kt new file mode 100644 index 0000000..2bd7552 --- /dev/null +++ b/blokk-api/src/main/kotlin/space/blokk/net/events/ServerListInfoRequestEvent.kt @@ -0,0 +1,12 @@ +package space.blokk.net.events + +import space.blokk.events.Cancellable +import space.blokk.net.Session +import space.blokk.net.protocols.status.ResponsePacket + +class ServerListInfoRequestEvent( + session: Session, + var response: ResponsePacket +): SessionEvent(session), Cancellable { + override var isCancelled = false +} diff --git a/blokk-api/src/main/kotlin/space/blokk/net/protocols/status/ResponsePacket.kt b/blokk-api/src/main/kotlin/space/blokk/net/protocols/status/ResponsePacket.kt index 5777e02..69d3785 100644 --- a/blokk-api/src/main/kotlin/space/blokk/net/protocols/status/ResponsePacket.kt +++ b/blokk-api/src/main/kotlin/space/blokk/net/protocols/status/ResponsePacket.kt @@ -1,28 +1,42 @@ package space.blokk.net.protocols.status -import com.google.gson.GsonBuilder +import com.squareup.moshi.JsonClass import io.netty.buffer.ByteBuf +import space.blokk.Blokk import space.blokk.chat.TextComponent import space.blokk.net.MinecraftDataTypes import space.blokk.net.protocols.OutgoingPacket import space.blokk.net.protocols.OutgoingPacketCompanion -import java.util.* +import space.blokk.utils.toJson data class ResponsePacket( - val versionName: String, - val protocolVersion: Int, - val description: TextComponent, - val players: Players, - val favicon: String? = null -) : OutgoingPacket() { - constructor( - versionName: String, - protocolVersion: Int, - players: Players, - description: TextComponent, - favicon: ByteArray - ): this(versionName, protocolVersion, description, players, Base64.getEncoder().encodeToString(favicon)) + /** + * The name of the Minecraft version the server uses. + */ + val versionName: String, + /** + * The number of the protocol version used by the server. + * @see https://wiki.vg/Protocol_version_numbers + */ + val protocolVersion: Int, + + /** + * The description of the server. Although this is a [TextComponent], + * [legacy Formatting codes][space.blokk.chat.FormattingCode] must be used. + */ + val description: TextComponent, + + /** + * The players shown when hovering over the player count. + */ + val players: Players, + + /** + * The favicon of the server. This must be a base64 encoded 64x64 PNG image. + */ + val favicon: String? = null +) : OutgoingPacket() { init { if (description.getExtraTypes().find { it != TextComponent::class } != null) throw Exception("description may only contain instances of TextComponent") @@ -30,27 +44,27 @@ data class ResponsePacket( override fun encode(dst: ByteBuf) { with(MinecraftDataTypes) { - dst.writeString(gson.toJson(mapOf( - "version" to mapOf( - "name" to versionName, - "protocol" to protocolVersion - ), - "players" to players, - "description" to description, - "favicon" to favicon + dst.writeString(Blokk.json.toJson(mapOf( + "version" to mapOf( + "name" to versionName, + "protocol" to protocolVersion + ), + "players" to players, + "description" to description, + "favicon" to favicon?.let { "data:image/png;base64,$it" } ))) } } + @JsonClass(generateAdapter = true) data class Players(val max: Int, val online: Int, val sample: List) { /** * @param name The name of the player. You can use [FormattingCode](space.blokk.chat.FormattingCode)s * @param id The UUID of the player as a string. You can use a random UUID as it doesn't get validated by the Minecraft client */ + @JsonClass(generateAdapter = true) data class SampleEntry(val name: String, val id: String) } - companion object : OutgoingPacketCompanion(0x00, ResponsePacket::class) { - private val gson = GsonBuilder().disableHtmlEscaping().create()!! - } + companion object : OutgoingPacketCompanion(0x00, ResponsePacket::class) } diff --git a/blokk-api/src/main/kotlin/space/blokk/utils/Logger.kt b/blokk-api/src/main/kotlin/space/blokk/utils/Logger.kt index 81eb7fc..4f55a1a 100644 --- a/blokk-api/src/main/kotlin/space/blokk/utils/Logger.kt +++ b/blokk-api/src/main/kotlin/space/blokk/utils/Logger.kt @@ -1,9 +1,12 @@ package space.blokk.utils +import org.slf4j.Logger import org.slf4j.LoggerFactory class Logger(name: String) { - private val logger = LoggerFactory.getLogger(name) + private val logger: Logger = LoggerFactory.getLogger(name) + + fun error(msg: String, t: Throwable) = logger.error(msg, t) infix fun error(msg: String) = logger.error(msg) infix fun info(msg: String) = logger.info(msg) diff --git a/blokk-api/src/main/kotlin/space/blokk/utils/MoshiUtils.kt b/blokk-api/src/main/kotlin/space/blokk/utils/MoshiUtils.kt new file mode 100644 index 0000000..038574e --- /dev/null +++ b/blokk-api/src/main/kotlin/space/blokk/utils/MoshiUtils.kt @@ -0,0 +1,5 @@ +package space.blokk.utils + +import com.squareup.moshi.Moshi + +fun Moshi.toJson(value: Map<*, *>) = adapter(Map::class.java).toJson(value) diff --git a/blokk-api/src/test/kotlin/space/blokk/events/EventBus.kt b/blokk-api/src/test/kotlin/space/blokk/events/EventBus.kt index 73c1eca..b6a5b68 100644 --- a/blokk-api/src/test/kotlin/space/blokk/events/EventBus.kt +++ b/blokk-api/src/test/kotlin/space/blokk/events/EventBus.kt @@ -1,4 +1,7 @@ package space.blokk.events +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import org.spekframework.spek2.Spek import org.spekframework.spek2.style.specification.describe import strikt.api.expectThat @@ -14,7 +17,7 @@ private class SecondEvent: TestEvent() object EventBusTest: Spek({ describe("EventBus") { - val eventBus by memoized { EventBus(TestEvent::class) } + val eventBus by memoized { EventBus(TestEvent::class, CoroutineScope(Dispatchers.Default)) } it("calls the handler exactly 1 time when the event is emitted 1 time") { var calledCount = 0 @@ -22,7 +25,7 @@ object EventBusTest: Spek({ @EventHandler fun onFirstEvent(event: FirstEvent) { calledCount++ } }) - eventBus.emit(FirstEvent()) + runBlocking { eventBus.emit(FirstEvent()) } expectThat(calledCount).isEqualTo(1) } @@ -32,9 +35,12 @@ object EventBusTest: Spek({ @EventHandler fun onFirstEvent(event: FirstEvent) { calledCount++ } }) - eventBus.emit(FirstEvent()) - eventBus.emit(FirstEvent()) - eventBus.emit(FirstEvent()) + + runBlocking { + eventBus.emit(FirstEvent()) + eventBus.emit(FirstEvent()) + eventBus.emit(FirstEvent()) + } expectThat(calledCount).isEqualTo(3) } @@ -61,7 +67,7 @@ object EventBusTest: Spek({ @EventHandler fun onFirstEvent(event: FirstEvent) { onFirstEventCalled = true } }) - eventBus.emit(FirstEvent()) + runBlocking { eventBus.emit(FirstEvent()) } expectThat(onTestEventCalled).isTrue() expectThat(onFirstEventCalled).isTrue() @@ -75,7 +81,7 @@ object EventBusTest: Spek({ eventBus.unregister(listener) - eventBus.emit(FirstEvent()) + runBlocking { eventBus.emit(FirstEvent()) } expectThat(called).isFalse() } @@ -114,7 +120,7 @@ object EventBusTest: Spek({ @EventHandler(EventPriority.HIGH) fun onFirstEventHigh(event: FirstEvent) { order.add(EventPriority.HIGH) } }) - eventBus.emit(FirstEvent()) + runBlocking { eventBus.emit(FirstEvent()) } expectThat(order).isSorted(Comparator.comparing { it.ordinal }) } diff --git a/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt b/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt index 5e69e38..eeab974 100644 --- a/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt +++ b/blokk-server/src/main/kotlin/space/blokk/BlokkServer.kt @@ -2,8 +2,13 @@ package space.blokk import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope +import space.blokk.chat.ChatComponent +import space.blokk.chat.TextComponent import space.blokk.events.EventBus +import space.blokk.events.EventHandler +import space.blokk.events.Listener import space.blokk.net.BlokkSocketServer +import space.blokk.net.events.ServerListInfoRequestEvent import space.blokk.server.Server import space.blokk.server.events.ServerEvent import space.blokk.utils.Logger @@ -14,7 +19,7 @@ class BlokkServer internal constructor(): Server { override val scope = CoroutineScope(CoroutineName("BlokkServer")) override val eventBus = EventBus(ServerEvent::class, scope) val logger = Logger("BlokkServer") - var blokkSocketServer = BlokkSocketServer(this); private set + var socketServer = BlokkSocketServer(this); private set // TODO: Read from config file val host = "0.0.0.0" @@ -26,14 +31,14 @@ class BlokkServer internal constructor(): Server { providerField.isAccessible = true providerField.set(Blokk, object : BlokkProvider { override val server = this@BlokkServer - override val sessions get() = this@BlokkServer.blokkSocketServer.allSessionsGroup + override val sessions get() = this@BlokkServer.socketServer.allSessionsGroup }) providerField.isAccessible = false } fun start() { logger info "Starting BlokkServer (${if (VERSION == "development") VERSION else "v$VERSION"})" - blokkSocketServer.bind() + socketServer.bind() logger info "Listening on $host:$port" } @@ -44,6 +49,13 @@ class BlokkServer internal constructor(): Server { @JvmStatic fun main(args: Array) { val server = BlokkServer() + Blokk.sessions.registerListener(object : Listener { + @EventHandler + fun onServerListInfoRequest(event: ServerListInfoRequestEvent) { + event.response = event.response.copy(description = TextComponent(event.session.address.hostAddress, bold = true, underlined = true, color = ChatComponent.Color.RED)) + } + }) + server.start() } } diff --git a/blokk-server/src/main/kotlin/space/blokk/net/BlokkSession.kt b/blokk-server/src/main/kotlin/space/blokk/net/BlokkSession.kt index 7bad0c0..68834ff 100644 --- a/blokk-server/src/main/kotlin/space/blokk/net/BlokkSession.kt +++ b/blokk-server/src/main/kotlin/space/blokk/net/BlokkSession.kt @@ -4,9 +4,9 @@ import io.netty.channel.Channel import kotlinx.coroutines.* import space.blokk.BlokkServer import space.blokk.events.* +import space.blokk.net.events.PacketReceivedEvent +import space.blokk.net.events.PacketSendEvent import space.blokk.net.events.SessionEvent -import space.blokk.net.events.SessionPacketReceivedEvent -import space.blokk.net.events.SessionPacketSendEvent import space.blokk.net.protocols.OutgoingPacket import space.blokk.net.protocols.Protocol import space.blokk.net.protocols.handshaking.HandshakingProtocol @@ -23,45 +23,48 @@ class BlokkSession(private val channel: Channel) : Session { override var currentProtocol: Protocol = HandshakingProtocol set(value) { - logger debug "Switching protocol: $currentProtocol -> $value" + if (value == field) return + logger trace "Switching protocol: $currentProtocol -> $value" field = value } override val scope = CoroutineScope(Dispatchers.Unconfined + CoroutineName(identifier)) override val eventBus = EventBus(SessionEvent::class, scope) - var active: Boolean = true + private var active: Boolean = true init { eventBus.register(object : Listener { @EventHandler(priority = EventPriority.INTERNAL) - suspend fun onSessionPacketReceived(event: SessionPacketReceivedEvent<*>) { + suspend fun onSessionPacketReceived(event: PacketReceivedEvent<*>) { SessionPacketReceivedEventHandler.handle(event.session as BlokkSession, event.packet) } }) } fun onConnect() = scope.launch { - if (BlokkServer.i.eventBus.emit(SessionInitializedEvent(this@BlokkSession)).isCancelled) channel.close() - else BlokkServer.i.blokkSocketServer.allSessionsGroup.add(this@BlokkSession) + logger trace "Connected" + if (BlokkServer.i.eventBus.emitAsync(SessionInitializedEvent(this@BlokkSession)).isCancelled) channel.close() + else BlokkServer.i.socketServer.allSessionsGroup.add(this@BlokkSession) } fun onDisconnect() { + if (!active) throw IllegalStateException("The session is not active anymore") + logger trace "Disconnected" active = false scope.cancel("Disconnected") - BlokkServer.i.blokkSocketServer.allSessionsGroup.remove(this) + BlokkServer.i.socketServer.allSessionsGroup.remove(this) } override suspend fun send(packet: OutgoingPacket) { if (!active) throw IllegalStateException("The session is not active anymore") - logger debug { "Sending packet: $packet" } - val event = eventBus.emit(SessionPacketSendEvent(this@BlokkSession, packet)) - event.ifNotCancelled { + logger trace { "Sending packet: $packet" } + eventBus.emit(PacketSendEvent(this@BlokkSession, packet)).ifNotCancelled { try { - channel.writeAndFlush(PacketMessage(this@BlokkSession, event.packet)).awaitSuspending() - } catch (e: Throwable) { - logger error { "Packet send failed: $e" } + channel.writeAndFlush(PacketMessage(this@BlokkSession, it.packet)).awaitSuspending() + } catch (t: Throwable) { + logger.error("Packet send failed:", t) } } } diff --git a/blokk-server/src/main/kotlin/space/blokk/net/PacketCodec.kt b/blokk-server/src/main/kotlin/space/blokk/net/PacketCodec.kt index 3bb766f..26bf893 100644 --- a/blokk-server/src/main/kotlin/space/blokk/net/PacketCodec.kt +++ b/blokk-server/src/main/kotlin/space/blokk/net/PacketCodec.kt @@ -34,6 +34,5 @@ class PacketCodec(private val session: BlokkSession): MessageToMessageCodec>() { override fun channelRead0(ctx: ChannelHandlerContext, msg: PacketMessage<*>) { if (msg.packet !is IncomingPacket) throw Error("Only serverbound packets are allowed. This should never happen.") - session.logger.debug { "Packet received: ${msg.packet}" } - runBlocking { - session.eventBus.emitAndAwait(SessionPacketReceivedEvent(session, msg.packet)) - } + session.logger.trace { "Packet received: ${msg.packet}" } + session.scope.launch { session.eventBus.emit(PacketReceivedEvent(session, msg.packet)) } // TODO: Disconnect when invalid data is received } diff --git a/blokk-server/src/main/kotlin/space/blokk/net/protocols/status/StatusProtocolHandler.kt b/blokk-server/src/main/kotlin/space/blokk/net/protocols/status/StatusProtocolHandler.kt index b4dc6ce..6d25090 100644 --- a/blokk-server/src/main/kotlin/space/blokk/net/protocols/status/StatusProtocolHandler.kt +++ b/blokk-server/src/main/kotlin/space/blokk/net/protocols/status/StatusProtocolHandler.kt @@ -2,24 +2,30 @@ package space.blokk.net.protocols.status import space.blokk.chat.FormattingCode import space.blokk.chat.TextComponent +import space.blokk.events.ifNotCancelled import space.blokk.net.PacketReceivedEventHandler import space.blokk.net.ProtocolPacketReceivedEventHandler +import space.blokk.net.events.ServerListInfoRequestEvent import java.util.* // NOTE: PacketReceivedEventHandler.of MUST have T specified correctly, otherwise the code breaks at runtime object StatusProtocolHandler: ProtocolPacketReceivedEventHandler(mapOf( RequestPacket to PacketReceivedEventHandler.of { session, _ -> - session.send(ResponsePacket( + session.eventBus.emit(ServerListInfoRequestEvent( + session, + // TODO: Use the real server data + ResponsePacket( versionName = "1.15.2", protocolVersion = 578, - description = TextComponent of "nice", + description = TextComponent of "Hello World!", players = ResponsePacket.Players( - 10, - 10, - listOf(ResponsePacket.Players.SampleEntry("${FormattingCode.AQUA}Gronkh", UUID.randomUUID().toString())) + 10, + 10, + listOf(ResponsePacket.Players.SampleEntry("${FormattingCode.AQUA}Gronkh", UUID.randomUUID().toString())) ) - )) + ) + )).ifNotCancelled { session.send(it.response) } }, PingPacket to PacketReceivedEventHandler.of { session, packet -> session.send(PongPacket(packet.payload)) diff --git a/build.gradle.kts b/build.gradle.kts index ae367ff..7dd8a51 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ plugins { kotlin("jvm") version "1.3.71" + kotlin("kapt") version "1.3.72" } group = "space.blokk"