Skip to content

Instantly share code, notes, and snippets.

@aripiprazole
Created August 15, 2022 03:46
Show Gist options
  • Save aripiprazole/33b13abb79ff051f669fbcf40d01878b to your computer and use it in GitHub Desktop.
Save aripiprazole/33b13abb79ff051f669fbcf40d01878b to your computer and use it in GitHub Desktop.
Empty server with Andesite
import andesite.protocol.java.handshake.HandshakePacket
import andesite.protocol.java.handshake.NextState
import andesite.protocol.java.handshake.PingPacket
import andesite.protocol.java.handshake.Players
import andesite.protocol.java.handshake.PongPacket
import andesite.protocol.java.handshake.Response
import andesite.protocol.java.handshake.ResponsePacket
import andesite.protocol.java.handshake.Version
import andesite.protocol.misc.Chat
import andesite.protocol.misc.UuidSerializer
import andesite.protocol.serialization.MinecraftCodec
import io.ktor.network.selector.ActorSelectorManager
import io.ktor.network.sockets.aSocket
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.contextual
import net.benwoodworth.knbt.Nbt
import net.benwoodworth.knbt.NbtCompression
import net.benwoodworth.knbt.NbtVariant
suspend fun main(): Unit = coroutineScope {
val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind("0.0.0.0", 25565)
val codec = MinecraftCodec {
protocolVersion = 756
nbt = Nbt {
variant = NbtVariant.Java
compression = NbtCompression.None
ignoreUnknownKeys = true
}
json = Json {
prettyPrint = true
}
serializersModule = SerializersModule {
contextual(UuidSerializer)
}
}
while (true) {
val client = server.accept()
launch(CoroutineName("session-${client.remoteAddress}")) {
val session = Session(codec, client, this)
val handshake = session.receivePacket(HandshakePacket.serializer())
when (handshake.nextState) {
NextState.Status -> {
session.sendPacket(
ResponsePacket.serializer(),
ResponsePacket(
Response(
version = Version(name = "Andesite for 1.17.1", protocol = 756),
players = Players(max = 10, online = 0, sample = listOf()),
description = Chat.of("&eAndesite for 1.17.1"),
),
),
)
session.receivePacket(PingPacket.serializer())
session.sendPacket(PongPacket.serializer(), PongPacket())
}
NextState.Login -> TODO("implement login logic")
}
}
}
}
import andesite.protocol.ProtocolPacket
import andesite.protocol.extractPacketId
import andesite.protocol.java.JavaPacket
import andesite.protocol.readVarInt
import andesite.protocol.serialization.MinecraftCodec
import andesite.protocol.writeVarInt
import io.ktor.network.sockets.Socket
import io.ktor.network.sockets.openReadChannel
import io.ktor.network.sockets.openWriteChannel
import io.ktor.utils.io.core.buildPacket
import io.ktor.utils.io.core.readBytes
import io.ktor.utils.io.core.writeFully
import io.ktor.utils.io.writePacket
import kotlinx.coroutines.CoroutineScope
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationStrategy
@OptIn(ExperimentalSerializationApi::class)
class Session(val codec: MinecraftCodec, val socket: Socket, val scope: CoroutineScope) : CoroutineScope by scope {
val input = socket.openReadChannel()
val output = socket.openWriteChannel()
suspend fun <T : JavaPacket> receivePacket(deserializer: DeserializationStrategy<T>): T {
val name = deserializer.descriptor.serialName
val size = input.readVarInt()
val packet = input.readPacket(size.toInt())
val id = packet.readVarInt().toInt()
println("Packet `$name` received with id [0x%02x] and size [$size]".format(id))
return codec.decodeFromByteArray(deserializer, packet.readBytes())
}
suspend fun <T : JavaPacket> sendPacket(serializer: SerializationStrategy<T>, packet: T) {
val packetName = serializer.descriptor.serialName
val packetId = extractPacketId(serializer.descriptor)
output.writePacket {
val data = buildPacket {
writeVarInt(packetId)
writeFully(codec.encodeToByteArray(serializer, packet))
}
println("Packet `$packetName` sent with id [0x%02x] with size [${data.remaining}]".format(packetId))
writeVarInt(data.remaining.toInt())
writePacket(data)
}
output.flush()
}
override fun toString(): String {
return "Session(remoteAddress=${socket.remoteAddress})"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment