Update Gradle, fix a ByteBuf leak and kick the client when a decoding error occurs
This commit is contained in:
parent
44ff61bf03
commit
32103d695a
15 changed files with 130 additions and 121 deletions
|
@ -3,15 +3,10 @@ package space.blokk.logging
|
||||||
import space.blokk.Blokk
|
import space.blokk.Blokk
|
||||||
|
|
||||||
class Logger(val name: String, private val printThreadName: Boolean = true) {
|
class Logger(val name: String, private val printThreadName: Boolean = true) {
|
||||||
fun log(level: Level, message: String, throwable: Throwable? = null) =
|
private fun log(level: Level, message: String, throwable: Throwable? = null) =
|
||||||
Blokk.loggingOutputProvider.log(printThreadName, name, level, message, throwable)
|
Blokk.loggingOutputProvider.log(printThreadName, name, level, message, throwable)
|
||||||
|
|
||||||
fun error(msg: String, t: Throwable) {
|
fun error(message: String, throwable: Throwable) = log(Level.ERROR, message, throwable)
|
||||||
if (Level.ERROR.isEnabled) {
|
|
||||||
error(msg)
|
|
||||||
t.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
infix fun error(message: String) = log(Level.ERROR, message, null)
|
infix fun error(message: String) = log(Level.ERROR, message, null)
|
||||||
infix fun info(message: String) = log(Level.INFO, message, null)
|
infix fun info(message: String) = log(Level.INFO, message, null)
|
||||||
|
|
|
@ -8,12 +8,4 @@ import space.blokk.world.ChunkData
|
||||||
/**
|
/**
|
||||||
* Sent to inform the player about blocks and biomes in a chunk.
|
* Sent to inform the player about blocks and biomes in a chunk.
|
||||||
*/
|
*/
|
||||||
data class ChunkDataPacket(val key: Chunk.Key, val data: ChunkData) : OutgoingPacket() {
|
data class ChunkDataPacket(val key: Chunk.Key, val data: ChunkData) : OutgoingPacket()
|
||||||
init {
|
|
||||||
if (key.x == 0 && key.z == 0) {
|
|
||||||
data.sections[0]?.forEach {
|
|
||||||
print(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,12 +46,6 @@ class BlokkServer internal constructor() : Server {
|
||||||
CoroutineName("Server") + SupervisorJob() +
|
CoroutineName("Server") + SupervisorJob() +
|
||||||
Executors.newSingleThreadExecutor { r -> Thread(r, "server") }.asCoroutineDispatcher()
|
Executors.newSingleThreadExecutor { r -> Thread(r, "server") }.asCoroutineDispatcher()
|
||||||
|
|
||||||
init {
|
|
||||||
coroutineContext.job.invokeOnCompletion {
|
|
||||||
println(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val sessions by socketServer::sessions
|
override val sessions by socketServer::sessions
|
||||||
override val players get() = sessions.mapNotNull { it.player }
|
override val players get() = sessions.mapNotNull { it.player }
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.time.Duration
|
||||||
data class BlokkConfig(
|
data class BlokkConfig(
|
||||||
val port: Int,
|
val port: Int,
|
||||||
val host: String,
|
val host: String,
|
||||||
val silentNonServerErrors: Boolean,
|
val ignoreClientCausedErrors: Boolean,
|
||||||
val authenticateAndEncrypt: Boolean,
|
val authenticateAndEncrypt: Boolean,
|
||||||
val developmentMode: Boolean,
|
val developmentMode: Boolean,
|
||||||
val minLogLevel: Logger.Level,
|
val minLogLevel: Logger.Level,
|
||||||
|
|
|
@ -16,7 +16,6 @@ object BlokkLoggingOutputProvider : LoggingOutputProvider {
|
||||||
throwable: Throwable?
|
throwable: Throwable?
|
||||||
) {
|
) {
|
||||||
if (!level.isEnabled) return
|
if (!level.isEnabled) return
|
||||||
|
|
||||||
val time = Date()
|
val time = Date()
|
||||||
|
|
||||||
val stream: PrintStream = if (level.isGreaterOrEqualThan(Logger.Level.ERROR)) System.err else System.out
|
val stream: PrintStream = if (level.isGreaterOrEqualThan(Logger.Level.ERROR)) System.err else System.out
|
||||||
|
@ -40,5 +39,6 @@ object BlokkLoggingOutputProvider : LoggingOutputProvider {
|
||||||
parts.add(message)
|
parts.add(message)
|
||||||
|
|
||||||
stream.println(parts.joinToString(" "))
|
stream.println(parts.joinToString(" "))
|
||||||
|
throwable?.printStackTrace(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package space.blokk.net
|
package space.blokk.net
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
|
import io.netty.util.ReferenceCountUtil
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import space.blokk.BlokkServer
|
import space.blokk.BlokkServer
|
||||||
|
@ -24,7 +25,6 @@ import space.blokk.net.packet.status.StatusProtocol
|
||||||
import space.blokk.server.event.SessionInitializedEvent
|
import space.blokk.server.event.SessionInitializedEvent
|
||||||
import space.blokk.util.awaitSuspending
|
import space.blokk.util.awaitSuspending
|
||||||
import space.blokk.util.supervisorChild
|
import space.blokk.util.supervisorChild
|
||||||
import java.io.IOException
|
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
|
@ -63,64 +63,11 @@ class BlokkSession(private val channel: io.netty.channel.Channel, val server: Bl
|
||||||
is State.Disconnected -> null
|
is State.Disconnected -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
private var packetsChannel: Channel<IncomingPacket>? = null
|
|
||||||
private val packetDataChannel: Channel<ByteBuf> = Channel(Channel.UNLIMITED)
|
|
||||||
|
|
||||||
fun launchPacketsChannelWorker() {
|
|
||||||
val channel = Channel<IncomingPacket>(Channel.UNLIMITED)
|
|
||||||
packetsChannel = channel
|
|
||||||
|
|
||||||
scope.launch {
|
|
||||||
for (packet in channel) {
|
|
||||||
handlePacket(packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun handlePacket(packet: IncomingPacket) {
|
|
||||||
logger.trace { "Packet received: $packet" }
|
|
||||||
|
|
||||||
server.eventBus.emit(PacketReceivedEvent(this@BlokkSession, packet)).ifNotCancelled {
|
|
||||||
SessionPacketReceivedEventHandler.handle(this@BlokkSession, packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
logger trace "Created"
|
|
||||||
|
|
||||||
scope.launch {
|
|
||||||
for (data in packetDataChannel) {
|
|
||||||
val packetID = data.readVarInt()
|
|
||||||
val codec = currentProtocol!!.incomingPacketCodecsByID[packetID]
|
|
||||||
|
|
||||||
if (codec == null) {
|
|
||||||
val message = "Client sent an unknown packet (ID: $packetID)"
|
|
||||||
|
|
||||||
if (server.config.developmentMode) {
|
|
||||||
logger warn "$message. This will cause the client to disconnect in production mode."
|
|
||||||
continue
|
|
||||||
} else throw IOException(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
val packet = codec.decode(data)
|
|
||||||
|
|
||||||
if (packetsChannel != null) {
|
|
||||||
// The protocol will not change anymore, so we can safely decode all packets with the current one
|
|
||||||
if (!packetsChannel!!.offer(packet)) {
|
|
||||||
logger.warn("The packet buffer is full (size: ${server.config.packetsBufferSize})")
|
|
||||||
disconnect(internalReason = "You sent more packets than the packet buffer can handle")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The protocol could change because of this packet, so we must wait
|
|
||||||
handlePacket(packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun disconnect(reason: TextComponent, internalReason: String?) {
|
override suspend fun disconnect(reason: TextComponent, internalReason: String?) {
|
||||||
|
stopProcessingIncomingPackets()
|
||||||
|
|
||||||
if (currentProtocol == LoginProtocol || currentProtocol == PlayProtocol) {
|
if (currentProtocol == LoginProtocol || currentProtocol == PlayProtocol) {
|
||||||
logger info "Disconnected." + (internalReason?.let { " Internal reason: $it" } ?: "")
|
logger info "Disconnected" + (internalReason?.let { ". Internal reason: $it" } ?: "")
|
||||||
|
|
||||||
val finalReason = if (server.config.developmentMode && internalReason != null) {
|
val finalReason = if (server.config.developmentMode && internalReason != null) {
|
||||||
val additional = listOf<ChatComponent>(
|
val additional = listOf<ChatComponent>(
|
||||||
|
@ -138,12 +85,82 @@ class BlokkSession(private val channel: io.netty.channel.Channel, val server: Bl
|
||||||
LoginProtocol -> send(space.blokk.net.packet.login.DisconnectPacket(finalReason))
|
LoginProtocol -> send(space.blokk.net.packet.login.DisconnectPacket(finalReason))
|
||||||
PlayProtocol -> send(space.blokk.net.packet.play.DisconnectPacket(finalReason))
|
PlayProtocol -> send(space.blokk.net.packet.play.DisconnectPacket(finalReason))
|
||||||
}
|
}
|
||||||
}
|
} else logger trace "Disconnected"
|
||||||
|
|
||||||
onDisconnect(true)
|
onDisconnect(true)
|
||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var packetsChannel: Channel<IncomingPacket>? = null
|
||||||
|
private val packetDataChannel: Channel<ByteBuf> = Channel(Channel.UNLIMITED)
|
||||||
|
|
||||||
|
fun launchPacketsChannelConsumer() {
|
||||||
|
val channel = Channel<IncomingPacket>(server.config.packetsBufferSize)
|
||||||
|
packetsChannel = channel
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
for (packet in channel) {
|
||||||
|
handlePacket(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchPacketDataChannelConsumer() {
|
||||||
|
scope.launch {
|
||||||
|
for (data in packetDataChannel) {
|
||||||
|
try {
|
||||||
|
handlePacketData(data)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
failAndDisconnectBecauseOfClient(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopProcessingIncomingPackets() {
|
||||||
|
packetDataChannel.close()
|
||||||
|
packetsChannel?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handlePacket(packet: IncomingPacket) {
|
||||||
|
logger.trace { "Packet received: $packet" }
|
||||||
|
|
||||||
|
server.eventBus.emit(PacketReceivedEvent(this@BlokkSession, packet)).ifNotCancelled {
|
||||||
|
SessionPacketReceivedEventHandler.handle(this@BlokkSession, packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handlePacketData(data: ByteBuf) {
|
||||||
|
val packetID = data.readVarInt()
|
||||||
|
val codec = currentProtocol!!.incomingPacketCodecsByID[packetID]
|
||||||
|
|
||||||
|
if (codec == null) {
|
||||||
|
val message = "Received an unknown packet (ID: $packetID)"
|
||||||
|
|
||||||
|
if (server.config.developmentMode)
|
||||||
|
logger warn "$message. This will cause the client to disconnect in production mode."
|
||||||
|
else failAndDisconnectBecauseOfClient(message)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val packet = codec.decode(data)
|
||||||
|
ReferenceCountUtil.release(data)
|
||||||
|
|
||||||
|
if (packetsChannel != null) {
|
||||||
|
// The protocol will not change anymore, so we can safely decode all pending packets with the current one
|
||||||
|
if (!packetsChannel!!.offer(packet)) {
|
||||||
|
logger.warn("The packet buffer is full (size: ${server.config.packetsBufferSize})")
|
||||||
|
disconnect(internalReason = "You sent more packets than the packet buffer can handle")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The protocol could change because of this packet, so we must wait
|
||||||
|
handlePacket(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val joinProcedure = LoginAndJoinProcedure(this)
|
||||||
|
|
||||||
var lastKeepAlivePacketTimestamp by Delegates.notNull<Long>()
|
var lastKeepAlivePacketTimestamp by Delegates.notNull<Long>()
|
||||||
lateinit var keepAliveDisconnectJob: Job
|
lateinit var keepAliveDisconnectJob: Job
|
||||||
|
|
||||||
|
@ -168,39 +185,52 @@ class BlokkSession(private val channel: io.netty.channel.Channel, val server: Bl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val joinProcedure = LoginAndJoinProcedure(this)
|
|
||||||
|
|
||||||
fun onConnect() = scope.launch {
|
fun onConnect() = scope.launch {
|
||||||
logger trace "Connected"
|
logger trace "Connected"
|
||||||
|
launchPacketDataChannelConsumer()
|
||||||
|
|
||||||
state = State.WaitingForHandshake
|
state = State.WaitingForHandshake
|
||||||
if (server.eventBus.emit(SessionInitializedEvent(this@BlokkSession)).cancelled) channel.close()
|
if (server.eventBus.emit(SessionInitializedEvent(this@BlokkSession)).cancelled) channel.close()
|
||||||
else server.sessions.add(this@BlokkSession)
|
else server.sessions.add(this@BlokkSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDisconnect(expected: Boolean) {
|
fun onDisconnect(expected: Boolean) {
|
||||||
if (state == State.Disconnected) return
|
scope.launch {
|
||||||
|
if (state == State.Disconnected) return@launch
|
||||||
if (!expected && currentProtocol != HandshakingProtocol && currentProtocol != StatusProtocol)
|
if (!expected && currentProtocol != HandshakingProtocol && currentProtocol != StatusProtocol)
|
||||||
logger trace "The client disconnected unexpectedly"
|
logger trace "The client disconnected unexpectedly"
|
||||||
|
|
||||||
val closeException = DisconnectedCancellationException()
|
stopProcessingIncomingPackets()
|
||||||
|
coroutineContext.cancel(DisconnectedCancellationException())
|
||||||
state = State.Disconnected
|
state = State.Disconnected
|
||||||
server.sessions.remove(this)
|
server.sessions.remove(this@BlokkSession)
|
||||||
|
}
|
||||||
packetDataChannel.close(closeException)
|
|
||||||
packetsChannel?.close(closeException)
|
|
||||||
|
|
||||||
coroutineContext.cancel(closeException)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPacketDataReceived(packetData: ByteBuf) {
|
fun onPacketDataReceived(packetData: ByteBuf) {
|
||||||
packetDataChannel.offer(packetData)
|
packetDataChannel.offer(packetData)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun failBecauseOfClient(message: String) {
|
internal fun failAndDisconnectBecauseOfClient(throwable: Throwable) =
|
||||||
val messageGetter = { "The client caused a connection error: $message" }
|
failAndDisconnectBecauseOfClient("${throwable::class.java.name}: ${throwable.message}", throwable)
|
||||||
if (server.config.silentNonServerErrors) logger debug messageGetter else logger error messageGetter
|
|
||||||
|
internal fun failAndDisconnectBecauseOfClient(message: String, throwable: Throwable? = null) {
|
||||||
|
val start = "The client caused a connection error"
|
||||||
|
|
||||||
|
if (server.config.ignoreClientCausedErrors) {
|
||||||
|
logger debug "The client caused a connection error: $message"
|
||||||
|
// Does not send the Disconnect packet
|
||||||
|
channel.close()
|
||||||
onDisconnect(true)
|
onDisconnect(true)
|
||||||
|
} else {
|
||||||
|
if (throwable == null) logger.error("$start: $message")
|
||||||
|
else logger.error(start, throwable)
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
// Sends the Disconnect packet
|
||||||
|
disconnect(internalReason = message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enableEncryptionCodec(key: SecretKey) {
|
fun enableEncryptionCodec(key: SecretKey) {
|
||||||
|
@ -217,15 +247,13 @@ class BlokkSession(private val channel: io.netty.channel.Channel, val server: Bl
|
||||||
.addAfter("framing", "compression", CompressionCodec(server.config.packetCompressionThreshold))
|
.addAfter("framing", "compression", CompressionCodec(server.config.packetCompressionThreshold))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun send(packet: OutgoingPacket) {
|
override suspend fun send(packet: OutgoingPacket) = withContext<Unit>(coroutineContext) {
|
||||||
if (state is State.Disconnected) throw IllegalStateException("The session is not active anymore")
|
|
||||||
|
|
||||||
logger.trace { "Sending packet: $packet" }
|
logger.trace { "Sending packet: $packet" }
|
||||||
server.eventBus.emit(PacketSendEvent(this, packet)).ifNotCancelled {
|
server.eventBus.emit(PacketSendEvent(this@BlokkSession, packet)).ifNotCancelled {
|
||||||
try {
|
try {
|
||||||
channel.writeAndFlush(it.packet).awaitSuspending()
|
channel.writeAndFlush(it.packet).awaitSuspending()
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
if (!channel.isActive) return
|
if (!channel.isActive) return@withContext
|
||||||
logger.error("Sending packet failed", t)
|
logger.error("Sending packet failed", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,6 @@ class LoginAndJoinProcedure(val session: BlokkSession) {
|
||||||
val uuid = UUID.nameUUIDFromBytes("OfflinePlayer:${packet.username}".toByteArray())
|
val uuid = UUID.nameUUIDFromBytes("OfflinePlayer:${packet.username}".toByteArray())
|
||||||
session.send(LoginSuccessPacket(uuid, packet.username))
|
session.send(LoginSuccessPacket(uuid, packet.username))
|
||||||
session.state = Session.State.LoginSucceeded(packet.username, uuid)
|
session.state = Session.State.LoginSucceeded(packet.username, uuid)
|
||||||
session.launchPacketsChannelWorker()
|
|
||||||
|
|
||||||
afterLogin()
|
afterLogin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,12 +71,12 @@ class LoginAndJoinProcedure(val session: BlokkSession) {
|
||||||
|
|
||||||
session.send(LoginSuccessPacket(result.uuid, result.username))
|
session.send(LoginSuccessPacket(result.uuid, result.username))
|
||||||
session.state = Session.State.LoginSucceeded(result.username, result.uuid)
|
session.state = Session.State.LoginSucceeded(result.username, result.uuid)
|
||||||
|
|
||||||
afterLogin()
|
afterLogin()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun afterLogin() {
|
private suspend fun afterLogin() {
|
||||||
val state: Session.State.LoginSucceeded = session.state.getOrFail()
|
val state: Session.State.LoginSucceeded = session.state.getOrFail()
|
||||||
|
session.launchPacketsChannelConsumer()
|
||||||
|
|
||||||
val event = session.server.eventBus.emit(SessionAfterLoginEvent(session))
|
val event = session.server.eventBus.emit(SessionAfterLoginEvent(session))
|
||||||
val initialWorldAndLocation = event.initialWorldAndLocation
|
val initialWorldAndLocation = event.initialWorldAndLocation
|
||||||
|
|
|
@ -4,12 +4,9 @@ import io.netty.buffer.ByteBuf
|
||||||
import io.netty.channel.ChannelDuplexHandler
|
import io.netty.channel.ChannelDuplexHandler
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.channel.ChannelPromise
|
import io.netty.channel.ChannelPromise
|
||||||
import io.netty.handler.codec.MessageToMessageCodec
|
|
||||||
import space.blokk.net.MinecraftProtocolDataTypes.readVarInt
|
|
||||||
import space.blokk.net.MinecraftProtocolDataTypes.writeVarInt
|
import space.blokk.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
import space.blokk.net.packet.OutgoingPacket
|
import space.blokk.net.packet.OutgoingPacket
|
||||||
import space.blokk.net.packet.OutgoingPacketCodec
|
import space.blokk.net.packet.OutgoingPacketCodec
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class PacketMessageDuplexHandler(private val session: BlokkSession) : ChannelDuplexHandler() {
|
class PacketMessageDuplexHandler(private val session: BlokkSession) : ChannelDuplexHandler() {
|
||||||
override fun channelActive(ctx: ChannelHandlerContext) {
|
override fun channelActive(ctx: ChannelHandlerContext) {
|
||||||
|
@ -34,11 +31,10 @@ class PacketMessageDuplexHandler(private val session: BlokkSession) : ChannelDup
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
|
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
|
||||||
// TODO: Check if the ByteBuf needs to be released
|
session.onPacketDataReceived(msg as ByteBuf) // ByteBuf must be released by the session
|
||||||
session.onPacketDataReceived(msg as ByteBuf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
|
||||||
session.failBecauseOfClient("${cause::class.java.name}: ${cause.message}")
|
session.logger.error("An uncaught exception occurred", Exception(cause))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ object EncryptionResponsePacketHandler : PacketReceivedEventHandler<EncryptionRe
|
||||||
try {
|
try {
|
||||||
session.joinProcedure.onEncryptionResponse(packet)
|
session.joinProcedure.onEncryptionResponse(packet)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
session.failBecauseOfClient("Client sent EncryptionResponsePacket when it was not allowed.")
|
session.failAndDisconnectBecauseOfClient("Client sent EncryptionResponsePacket when it was not allowed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ object LoginStartPacketHandler : PacketReceivedEventHandler<LoginStartPacket>()
|
||||||
try {
|
try {
|
||||||
session.joinProcedure.start(packet)
|
session.joinProcedure.start(packet)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
session.failBecauseOfClient("Client sent LoginStartPacket when it was not allowed")
|
session.failAndDisconnectBecauseOfClient("Client sent LoginStartPacket when it was not allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ object ClientSettingsPacketHandler : PacketReceivedEventHandler<ClientSettingsPa
|
||||||
try {
|
try {
|
||||||
session.joinProcedure.onClientSettingsReceived(packet)
|
session.joinProcedure.onClientSettingsReceived(packet)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
session.failBecauseOfClient("Client sent ClientSettingsPacket when it was not allowed")
|
session.failAndDisconnectBecauseOfClient("Client sent ClientSettingsPacket when it was not allowed")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(player as BlokkPlayer).settings =
|
(player as BlokkPlayer).settings =
|
||||||
|
|
|
@ -13,7 +13,7 @@ object IncomingPluginMessagePacketHandler : PacketReceivedEventHandler<IncomingP
|
||||||
// TODO: Add API for registering plugin channels and using them
|
// TODO: Add API for registering plugin channels and using them
|
||||||
|
|
||||||
if (packet.channel == "minecraft:brand") {
|
if (packet.channel == "minecraft:brand") {
|
||||||
if (session.brand != null) session.failBecauseOfClient("The client sent his brand name more than once")
|
if (session.brand != null) session.failAndDisconnectBecauseOfClient("The client sent his brand name more than once")
|
||||||
else {
|
else {
|
||||||
val buffer: ByteBuf = Unpooled.copiedBuffer(packet.data)
|
val buffer: ByteBuf = Unpooled.copiedBuffer(packet.data)
|
||||||
val brand = buffer.readString()
|
val brand = buffer.readString()
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package space.blokk.player
|
package space.blokk.player
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
|
import kotlinx.coroutines.yield
|
||||||
import space.blokk.chat.TextComponent
|
import space.blokk.chat.TextComponent
|
||||||
import space.blokk.net.Session
|
import space.blokk.net.Session
|
||||||
import space.blokk.net.packet.play.ChunkDataPacket
|
import space.blokk.net.packet.play.ChunkDataPacket
|
||||||
|
@ -9,6 +13,7 @@ import space.blokk.world.LocationWithRotation
|
||||||
import space.blokk.world.VoxelLocation
|
import space.blokk.world.VoxelLocation
|
||||||
import space.blokk.world.World
|
import space.blokk.world.World
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class BlokkPlayer(
|
class BlokkPlayer(
|
||||||
|
@ -66,6 +71,7 @@ class BlokkPlayer(
|
||||||
suspend fun sendChunksAndLight() {
|
suspend fun sendChunksAndLight() {
|
||||||
val chunks = currentlyViewedChunks.sortedBy { abs(it.key.x) + abs(it.key.z) }
|
val chunks = currentlyViewedChunks.sortedBy { abs(it.key.x) + abs(it.key.z) }
|
||||||
chunks.forEach { session.send(ChunkLightDataPacket(it.key, it.getLightData(this))) }
|
chunks.forEach { session.send(ChunkLightDataPacket(it.key, it.getLightData(this))) }
|
||||||
|
|
||||||
chunks.forEach { session.send(ChunkDataPacket(it.key, it.getData(this))) }
|
chunks.forEach { session.send(ChunkDataPacket(it.key, it.getData(this))) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 25565
|
port: 25565
|
||||||
silentNonServerErrors: true
|
ignoreClientCausedErrors: false
|
||||||
authenticateAndEncrypt: true
|
authenticateAndEncrypt: true
|
||||||
developmentMode: false
|
developmentMode: false
|
||||||
minLogLevel: INFO
|
minLogLevel: INFO
|
||||||
packetCompressionThreshold: 256
|
packetCompressionThreshold: 256
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
packetsBufferSize: 40
|
packetsBufferSize: 1
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
Reference in a new issue