diff --git a/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/ConnectedProperty.kt b/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/ConnectedProperty.kt
deleted file mode 100644
index d61013eb5..000000000
--- a/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/ConnectedProperty.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Minosoft
- * Copyright (C) 2020-2024 Moritz Zwerger
- *
- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program. If not, see .
- *
- * This software is not affiliated with Mojang AB, the original developer of Minecraft.
- */
-
-package de.bixilon.minosoft.commands.parser.minosoft.session.selector.properties
-
-import de.bixilon.minosoft.commands.errors.ExpectedArgumentError
-import de.bixilon.minosoft.commands.parser.brigadier.bool.BooleanParser.readBoolean
-import de.bixilon.minosoft.commands.parser.selector.TargetProperty
-import de.bixilon.minosoft.commands.parser.selector.TargetPropertyFactory
-import de.bixilon.minosoft.commands.util.CommandReader
-import de.bixilon.minosoft.protocol.network.session.play.PlaySession
-
-class ConnectedProperty(
- val connected: Boolean,
-) : TargetProperty {
-
- override fun passes(value: PlaySession): Boolean {
- val connected = value.network.connected
- return connected == this.connected
- }
-
- companion object : TargetPropertyFactory {
- override val name: String = "connected"
-
- override fun read(reader: CommandReader): ConnectedProperty {
- return ConnectedProperty(reader.readBoolean() ?: throw ExpectedArgumentError(reader))
- }
- }
-}
diff --git a/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/SessionTargetProperties.kt b/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/SessionTargetProperties.kt
index 1894a6483..5b4d3c06b 100644
--- a/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/SessionTargetProperties.kt
+++ b/src/main/java/de/bixilon/minosoft/commands/parser/minosoft/session/selector/properties/SessionTargetProperties.kt
@@ -20,6 +20,5 @@ object SessionTargetProperties : TargetProperties() {
init {
register(StateProperty)
- register(ConnectedProperty)
}
}
diff --git a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/local/SignatureKeyManagement.kt b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/local/SignatureKeyManagement.kt
index 428092b30..747ae5796 100644
--- a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/local/SignatureKeyManagement.kt
+++ b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/local/SignatureKeyManagement.kt
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.entities.entities.player.local
+import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.concurrent.schedule.TaskScheduler.runLater
import de.bixilon.kutil.latch.AbstractLatch
@@ -23,6 +24,7 @@ import de.bixilon.minosoft.data.chat.signature.ChatSignatureProperties
import de.bixilon.minosoft.data.chat.signature.errors.KeyExpiredError
import de.bixilon.minosoft.data.text.TextComponent
import de.bixilon.minosoft.modding.event.events.chat.ChatMessageEvent
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.packets.c2s.play.SessionDataC2SP
import de.bixilon.minosoft.protocol.protocol.ProtocolStates
@@ -46,7 +48,8 @@ class SignatureKeyManagement(
private fun registerRefresh(millis: Int) {
runLater(millis) {
- if (session.error != null || (session.established && !session.network.connected) || (session.network.connected && !session.network.encrypted)) {
+ val connected = session.connection.nullCast()?.state != null
+ if (session.error != null || (session.established && !connected) || (connected && !session.network.encrypted)) {
// session is dead
return@runLater
}
@@ -89,7 +92,7 @@ class SignatureKeyManagement(
if (session.version.versionId < ProtocolVersions.V_22W43A) {
return
}
- if (session.network.state != ProtocolStates.PLAY || !session.network.connected) {
+ if (session.connection !is NetworkConnection || session.connection.state != ProtocolStates.PLAY) {
return
}
if (!session.network.encrypted) {
diff --git a/src/main/java/de/bixilon/minosoft/example/ExampleMod.kt b/src/main/java/de/bixilon/minosoft/example/ExampleMod.kt
index d7f56f14f..2c20a3a8e 100644
--- a/src/main/java/de/bixilon/minosoft/example/ExampleMod.kt
+++ b/src/main/java/de/bixilon/minosoft/example/ExampleMod.kt
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.example
+import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.stream.InputStreamUtil.readAsString
import de.bixilon.minosoft.modding.event.events.chat.ChatMessageEvent
@@ -20,6 +21,7 @@ import de.bixilon.minosoft.modding.event.events.session.play.PlaySessionCreateEv
import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen
import de.bixilon.minosoft.modding.event.master.GlobalEventMaster
import de.bixilon.minosoft.modding.loader.mod.ModMain
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.util.KUtil.toResourceLocation
@@ -37,7 +39,8 @@ object ExampleMod : ModMain() {
}
private fun PlaySession.startListening() {
- if (this.address.hostname != "localhost" && this.address.hostname != "127.0.0.1") {
+ val address = this.connection.nullCast()?.address ?: return
+ if (address.hostname != "localhost" && address.hostname != "127.0.0.1") {
return
}
events.listen {
diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt
index aef8cc81b..c1232898b 100644
--- a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt
@@ -45,6 +45,7 @@ import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventListener
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.ctext
import de.bixilon.minosoft.modding.event.events.KickEvent
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.network.session.play.PlaySessionStates
import de.bixilon.minosoft.protocol.network.session.play.PlaySessionStates.Companion.disconnected
@@ -136,11 +137,12 @@ class ServerListController : EmbeddedJavaFXController(), Refreshable {
for ((type, name) in server.profiles) {
override[ProfileManagers[type]?.type ?: continue] = name
}
+ val profiles = SelectedProfiles(override)
val session = PlaySession(
- address = ping.realAddress ?: DNSUtil.getServerAddress(server.address),
+ connection = NetworkConnection(ping.connection?.address ?: DNSUtil.getServerAddress(server.address), native = profiles.other.nativeNetwork),
account = account,
version = version,
- profiles = SelectedProfiles(override)
+ profiles = profiles
)
account.sessions[server] = session
serverCard.sessions += session
@@ -151,14 +153,14 @@ class ServerListController : EmbeddedJavaFXController(), Refreshable {
serverCard.sessions -= session
}
if (ErosProfileManager.selected.general.hideErosOnceConnected) {
- if (session.network.connected) {
+ if (session.connection.active) {
if (session.state == PlaySessionStates.PLAYING) {
Eros.setVisibility(false)
}
} else {
var connected = false
for (entry in PlaySession.ACTIVE_CONNECTIONS.toSynchronizedSet()) {
- if (entry.network.connected) {
+ if (entry.connection.active) {
connected = true
break
}
@@ -313,7 +315,8 @@ class ServerListController : EmbeddedJavaFXController(), Refreshable {
// ToDo: server.connections.clear()
ping.terminate()
- ping.address = server.address
+ ping.reset()
+ ping.hostname = server.address
ping.ping()
}
JavaFXUtil.runLater { refreshList() }
@@ -425,7 +428,7 @@ class ServerListController : EmbeddedJavaFXController(), Refreshable {
private val SERVER_INFO_PROPERTIES: List Any?>> = listOf(
"minosoft:server_info.server_name".toResourceLocation() to { it.server.name },
"minosoft:server_info.server_address".toResourceLocation() to { it.server.address },
- "minosoft:server_info.real_server_address".toResourceLocation() to { it.ping.realAddress },
+ "minosoft:server_info.real_server_address".toResourceLocation() to { it.ping.connection?.address },
"minosoft:server_info.forced_version".toResourceLocation() to { it.server.forcedVersion },
TranslatableComponents.GENERAL_EMPTY to { " " },
diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/type/types/CustomServerType.kt b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/type/types/CustomServerType.kt
index 17ccc8aa4..14fc0661f 100644
--- a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/type/types/CustomServerType.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/type/types/CustomServerType.kt
@@ -62,7 +62,7 @@ object CustomServerType : ServerType {
continue
}
DefaultThreadPool += ForcePooledRunnable {
- ping.network.disconnect()
+ ping.terminate()
ping.ping()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/fade/FadingTextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/fade/FadingTextElement.kt
index bc4f45e55..be752eadc 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/fade/FadingTextElement.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/fade/FadingTextElement.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2023 Moritz Zwerger
+ * Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -65,6 +65,7 @@ class FadingTextElement(
fun show() {
val time = millis()
+ // TODO: extend time on call if already showing text
val phase = times.createPhase(time)
this.phase = phase
updateSize(phase)
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/debug/DebugHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/debug/DebugHUDElement.kt
index 2297030bc..c88b876cf 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/debug/DebugHUDElement.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/debug/DebugHUDElement.kt
@@ -129,7 +129,7 @@ class DebugHUDElement(guiRenderer: GUIRenderer) : Element(guiRenderer), Layouted
layout += LineSpacerElement(guiRenderer)
layout += TextElement(guiRenderer, BaseComponent("Account ", session.account.username))
- layout += TextElement(guiRenderer, BaseComponent("Address ", session.address))
+ layout += TextElement(guiRenderer, BaseComponent("Address ", session.connection.identifier))
layout += TextElement(guiRenderer, BaseComponent("Network version ", session.version))
layout += TextElement(guiRenderer, BaseComponent("Server brand ", session.serverInfo.brand)).apply { session.serverInfo::brand.observe(this@DebugHUDElement) { this.text = BaseComponent("Server brand ", it.truncate(50)) } }
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
index be537acb7..fe655b6cc 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
@@ -107,7 +107,7 @@ class ScreenshotTaker(
val size = Vec2i(context.window.size)
val buffer = context.system.readPixels(Vec2i.EMPTY_INSTANCE, size)
- val path = RunConfiguration.HOME_DIRECTORY.resolve("screenshots").resolve(context.session.address.hostname)
+ val path = RunConfiguration.HOME_DIRECTORY.resolve("screenshots").resolve(context.session.connection.identifier)
val time = millis()
DefaultThreadPool += ForcePooledRunnable(priority = ThreadPool.HIGHER) { store(buffer, path, time) }
} catch (exception: Exception) {
diff --git a/src/main/java/de/bixilon/minosoft/protocol/AddressResolver.kt b/src/main/java/de/bixilon/minosoft/protocol/AddressResolver.kt
new file mode 100644
index 000000000..c0835e7d9
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/AddressResolver.kt
@@ -0,0 +1,35 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2024 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol
+
+import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
+import de.bixilon.minosoft.util.DNSUtil
+import de.bixilon.minosoft.util.logging.Log
+import de.bixilon.minosoft.util.logging.LogMessageType
+
+class AddressResolver(
+ val address: String,
+) {
+ private var candidates: MutableList = DNSUtil.resolveServerAddress(address).toMutableList()
+
+
+ fun tryNext(): NetworkConnection? {
+ if (candidates.isEmpty()) return null
+ val address = candidates.removeAt(0)
+
+ Log.log(LogMessageType.NETWORK) { "Trying address: $address" }
+ return NetworkConnection(address, false)
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/connection/NetworkConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/connection/NetworkConnection.kt
new file mode 100644
index 000000000..602708acf
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/connection/NetworkConnection.kt
@@ -0,0 +1,60 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2024 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.connection
+
+import de.bixilon.kutil.concurrent.lock.thread.ThreadLock
+import de.bixilon.kutil.observer.DataObserver
+import de.bixilon.kutil.observer.DataObserver.Companion.observe
+import de.bixilon.kutil.observer.DataObserver.Companion.observed
+import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.network.network.client.ClientNetwork
+import de.bixilon.minosoft.protocol.network.network.client.netty.NettyClient
+import de.bixilon.minosoft.protocol.network.session.Session
+import de.bixilon.minosoft.protocol.packets.c2s.C2SPacket
+import de.bixilon.minosoft.protocol.protocol.ProtocolStates
+import de.bixilon.minosoft.util.logging.Log
+import de.bixilon.minosoft.util.logging.LogLevels
+import de.bixilon.minosoft.util.logging.LogMessageType
+
+class NetworkConnection(
+ val address: ServerAddress,
+ val native: Boolean,
+) : ServerConnection {
+ var client: ClientNetwork? = null
+ private set
+ override val identifier = address.toString()
+ override var active by observed(false)
+ private set
+ var state: ProtocolStates? by DataObserver(null, ThreadLock())
+
+ init {
+ this::state.observe(this) { active = it != null }
+ }
+
+ override fun connect(session: Session) {
+ Log.log(LogMessageType.NETWORK, level = LogLevels.INFO) { "Connecting to server: $address" }
+ if (client != null) throw IllegalStateException("Already connected???")
+ val netty = NettyClient(this, session)
+ this.client = netty
+ netty.connect()
+ }
+
+ override fun disconnect() {
+ client?.disconnect()
+ }
+
+ override fun send(packet: C2SPacket) {
+ client?.send(packet)
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/connection/ServerConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/connection/ServerConnection.kt
new file mode 100644
index 000000000..3416f4311
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/connection/ServerConnection.kt
@@ -0,0 +1,28 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2024 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.connection
+
+import de.bixilon.minosoft.protocol.network.session.Session
+import de.bixilon.minosoft.protocol.packets.c2s.C2SPacket
+
+interface ServerConnection {
+ val identifier: String
+
+ val active: Boolean
+
+ fun connect(session: Session)
+ fun disconnect()
+
+ fun send(packet: C2SPacket)
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/ClientNetwork.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/ClientNetwork.kt
index 9ee6ef5c4..08f204a6f 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/ClientNetwork.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/ClientNetwork.kt
@@ -13,25 +13,23 @@
package de.bixilon.minosoft.protocol.network.network.client
-import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.network.client.netty.packet.receiver.PacketReceiver
import de.bixilon.minosoft.protocol.network.network.client.netty.packet.sender.PacketSender
import de.bixilon.minosoft.protocol.packets.c2s.C2SPacket
-import de.bixilon.minosoft.protocol.protocol.ProtocolStates
import javax.crypto.Cipher
interface ClientNetwork {
- val connected: Boolean
+ val connection: NetworkConnection
val encrypted: Boolean
val detached: Boolean
- var state: ProtocolStates
val compressionThreshold: Int
val receiver: PacketReceiver
val sender: PacketSender
- fun connect(address: ServerAddress, native: Boolean)
+ fun connect()
fun disconnect()
fun detach()
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/NettyClient.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/NettyClient.kt
index a7545837e..5e06bd56a 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/NettyClient.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/NettyClient.kt
@@ -15,9 +15,9 @@ package de.bixilon.minosoft.protocol.network.network.client.netty
import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.exception.ExceptionUtil.catchAll
-import de.bixilon.kutil.observer.DataObserver.Companion.observed
+import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.config.profile.profiles.other.OtherProfileManager
-import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.network.client.ClientNetwork
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.NetworkException
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.PacketHandleException
@@ -51,14 +51,13 @@ import javax.crypto.Cipher
@ChannelHandler.Sharable
class NettyClient(
+ override val connection: NetworkConnection,
val session: Session,
) : SimpleChannelInboundHandler(), ClientNetwork {
+ @Deprecated("unused")
+ var state = ProtocolStates.HANDSHAKE // TODO
override val sender = PacketSender(this)
override val receiver = PacketReceiver(this, session)
- private var address: ServerAddress? = null
- override var connected by observed(false)
- private set
- override var state by observed(ProtocolStates.HANDSHAKE)
override var compressionThreshold = -1
override var encrypted: Boolean = false
private set
@@ -66,20 +65,22 @@ class NettyClient(
override var detached = false
private set
- override fun connect(address: ServerAddress, native: Boolean) {
- this.address = address
- state = ProtocolStates.HANDSHAKE
- val natives = if (native) TransportNatives.get() else NioNatives
+ init {
+ connection::state.observe(this) { this.state = it ?: ProtocolStates.HANDSHAKE }
+ }
+
+ override fun connect() {
+ val natives = if (connection.native) TransportNatives.get() else NioNatives
val bootstrap = Bootstrap()
.group(natives.pool)
.channel(natives.channel)
.handler(NetworkPipeline(this))
+ val address = connection.address
val future = bootstrap.connect(address.hostname, address.port)
future.addListener {
- if (!it.isSuccess) {
- handleError(it.cause())
- }
+ if (it.isSuccess) return@addListener
+ handleError(it.cause())
}
}
@@ -118,7 +119,7 @@ class NettyClient(
encrypted = false
channel = null
compressionThreshold = -1
- connected = false
+ connection.state = null
}
override fun detach() {
@@ -140,15 +141,17 @@ class NettyClient(
override fun channelActive(context: ChannelHandlerContext) {
catchAll { context.channel().config().setOption(ChannelOption.TCP_NODELAY, true) }
- context.channel().config().isAutoRead = true
- this.channel = context.channel()
- connected = true
+ val channel = context.channel()
+ this.channel = channel
+ connection.state = ProtocolStates.HANDSHAKE
+ channel.config().isAutoRead = true
}
override fun channelInactive(context: ChannelHandlerContext) {
- Log.log(LogMessageType.NETWORK, LogLevels.VERBOSE) { "Session closed ($address)" }
+ Log.log(LogMessageType.NETWORK, LogLevels.VERBOSE) { "Session closed (${connection.address})" }
if (detached) return
- connected = false
+ this.channel = null
+ connection.state = null
}
override fun handleError(error: Throwable) {
@@ -158,11 +161,11 @@ class NettyClient(
} else if (cause is EncoderException) {
cause = error.cause ?: cause
}
- if (RunConfiguration.DISABLE_EROS || session !is StatusSession) {
+ if (RunConfiguration.DISABLE_EROS || session is StatusSession) {
val log = if (cause is PacketHandleException || cause is PacketReadException) cause.cause else cause
Log.log(LogMessageType.NETWORK_IN, LogLevels.WARN) { log }
}
- if (cause !is NetworkException || cause is CriticalNetworkException || state == ProtocolStates.LOGIN) {
+ if (cause !is NetworkException || cause is CriticalNetworkException || connection.state == ProtocolStates.LOGIN) {
session.error = cause
disconnect()
return
@@ -175,7 +178,7 @@ class NettyClient(
private fun getChannel(): Channel? {
val channel = this.channel
- if (!connected || channel == null) {
+ if (channel == null || connection.state == null) {
return null
}
return channel
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/receiver/PacketReceiver.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/receiver/PacketReceiver.kt
index d8f71ee93..5b8a1d3b8 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/receiver/PacketReceiver.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/receiver/PacketReceiver.kt
@@ -56,7 +56,7 @@ class PacketReceiver(
}
private fun tryHandle(type: PacketType, packet: S2CPacket) {
- if (!network.connected) return
+ if (!network.connection.active) return
try {
handle(packet)
@@ -93,7 +93,7 @@ class PacketReceiver(
fun onReceive(type: PacketType, packet: S2CPacket) {
if (network.detached) return
- if (!network.connected) return
+ if (!network.connection.active) return
val discard = notify(packet)
if (discard) return
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/sender/PacketSender.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/sender/PacketSender.kt
index a7f168969..1e00caccb 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/sender/PacketSender.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/packet/sender/PacketSender.kt
@@ -41,7 +41,7 @@ class PacketSender(
fun send(packet: C2SPacket) {
if (network.detached) return
- if (!network.connected) return
+ if (!network.connection.active) return
val discard = notify(packet)
if (discard) return
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketDecoder.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketDecoder.kt
index 86c5f6409..f947f75a5 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketDecoder.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketDecoder.kt
@@ -38,7 +38,7 @@ class PacketDecoder(
val packetId = buffer.readVarInt()
val data = buffer.readRest()
- val state = client.state
+ val state = client.connection.state ?: throw IllegalStateException("Not connected!")
val type = version?.s2c?.get(state, packetId) ?: DefaultPacketMapping.S2C_PACKET_MAPPING[state, packetId] ?: throw UnknownPacketIdException(packetId, state, version)
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketEncoder.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketEncoder.kt
index bcff56344..ae8f0e443 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketEncoder.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/encoding/PacketEncoder.kt
@@ -74,8 +74,8 @@ class PacketEncoder(
throw PacketNotAvailableException(type, state, version)
}
- override fun encode(context: ChannelHandlerContext, packet: C2SPacket, out: MutableList) {
- val state = client.state
+ private fun encode(packet: C2SPacket): ByteArray {
+ val state = client.connection.state!!
val type = DefaultPackets.C2S[state]?.get(packet::class) ?: throw UnknownPacketException(packet::class.java)
val id = getPacketId(version, state, type)
@@ -86,7 +86,11 @@ class PacketEncoder(
data.writeVarInt(id)
data.writeBareByteArray(packetData.toArray())
- out += data.toArray()
+ return data.toArray()
+ }
+
+ override fun encode(context: ChannelHandlerContext, packet: C2SPacket, out: MutableList) {
+ out += encode(packet)
}
companion object {
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/length/LengthDecoder.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/length/LengthDecoder.kt
index 06d0159b0..f013e2e21 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/length/LengthDecoder.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/netty/pipeline/length/LengthDecoder.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2023 Moritz Zwerger
+ * Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.network.network.client.netty.pipeline.length
+import de.bixilon.kutil.exception.FastException
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.ciritical.PacketTooLongException
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
@@ -76,6 +77,6 @@ class LengthDecoder(
return varInt
}
- private class BufferTooShortException : Exception()
+ private class BufferTooShortException : FastException()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/session/Session.kt b/src/main/java/de/bixilon/minosoft/protocol/network/session/Session.kt
index 23b792360..6acb68f81 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/session/Session.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/session/Session.kt
@@ -16,13 +16,10 @@ package de.bixilon.minosoft.protocol.network.session
import de.bixilon.kutil.observer.DataObserver.Companion.observed
import de.bixilon.minosoft.modding.event.master.EventMaster
import de.bixilon.minosoft.modding.event.master.GlobalEventMaster
-import de.bixilon.minosoft.protocol.network.network.client.ClientNetwork
-import de.bixilon.minosoft.protocol.network.network.client.netty.NettyClient
import de.bixilon.minosoft.protocol.versions.Version
import java.util.concurrent.atomic.AtomicInteger
abstract class Session {
- val network: ClientNetwork = NettyClient(this)
val events = EventMaster(GlobalEventMaster)
val id = Session.id.getAndIncrement()
var established = false
@@ -31,9 +28,7 @@ abstract class Session {
var error: Throwable? by observed(null)
- open fun terminate() {
- network.disconnect()
- }
+ abstract fun terminate()
companion object {
private val id = AtomicInteger()
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/session/play/PlaySession.kt b/src/main/java/de/bixilon/minosoft/protocol/network/session/play/PlaySession.kt
index 4a329e2a7..d6f746375 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/session/play/PlaySession.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/session/play/PlaySession.kt
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.protocol.network.session.play
+import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.kutil.collections.CollectionUtil.synchronizedSetOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedSet
@@ -49,10 +50,12 @@ import de.bixilon.minosoft.gui.rendering.Rendering
import de.bixilon.minosoft.modding.event.events.chat.ChatMessageEvent
import de.bixilon.minosoft.modding.event.events.loading.RegistriesLoadEvent
import de.bixilon.minosoft.modding.event.events.session.play.PlaySessionCreateEvent
-import de.bixilon.minosoft.modding.event.listener.CallbackEventListener
+import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen
import de.bixilon.minosoft.modding.event.master.GlobalEventMaster
import de.bixilon.minosoft.modding.loader.phase.DefaultModPhases
-import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
+import de.bixilon.minosoft.protocol.connection.ServerConnection
+import de.bixilon.minosoft.protocol.network.network.client.netty.NettyClient
import de.bixilon.minosoft.protocol.network.session.Session
import de.bixilon.minosoft.protocol.network.session.play.channel.DefaultChannelHandlers
import de.bixilon.minosoft.protocol.network.session.play.channel.SessionChannelHandler
@@ -75,11 +78,13 @@ import java.util.concurrent.atomic.AtomicInteger
class PlaySession(
- val address: ServerAddress,
+ val connection: ServerConnection,
val account: Account,
override val version: Version,
val profiles: SelectedProfiles = SelectedProfiles(),
) : Session() {
+ @Deprecated("connection")
+ val network = NettyClient(connection.unsafeCast(), this)
val sessionId = KUtil.secureRandomUUID()
val settingsManager = ClientSettingsManager(this)
val registries = Registries().apply { updateFlattened(version.flattened) }
@@ -127,15 +132,16 @@ class PlaySession(
RegistriesFixer.register(this)
DefaultChannelHandlers.register(this)
- network::connected.observe(this) {
- if (it) {
+ connection.unsafeCast()::state.observe(this) {
+ if (it != null) {
ACTIVE_CONNECTIONS += this
ERRORED_CONNECTIONS -= this
state = PlaySessionStates.HANDSHAKING
- network.send(HandshakeC2SP(address, HandshakeC2SP.Actions.PLAY, version.protocolId))
+ val address = connection.unsafeCast().address
+ network.send(HandshakeC2SP(address.hostname, address.port, HandshakeC2SP.Actions.PLAY, version.protocolId))
// after sending it, switch to next state
- network.state = ProtocolStates.LOGIN
+ network.connection.state = ProtocolStates.LOGIN
} else {
established = true
assetsManager.unload()
@@ -146,7 +152,7 @@ class PlaySession(
}
}
}
- network::state.observe(this) { state ->
+ connection.unsafeCast()::state.observe(this) { state ->
when (state) {
ProtocolStates.HANDSHAKE, ProtocolStates.STATUS -> Broken("Invalid state!")
ProtocolStates.LOGIN -> {
@@ -162,17 +168,17 @@ class PlaySession(
CLI.session = this
}
- events.register(CallbackEventListener.of {
+ events.listen {
val additionalPrefix = when (it.message.type.position) {
ChatTextPositions.SYSTEM -> "[SYSTEM] "
ChatTextPositions.HOTBAR -> "[HOTBAR] "
else -> ""
}
Log.log(LogMessageType.CHAT_IN, level = if (it.message.type.position == ChatTextPositions.HOTBAR) LogLevels.VERBOSE else LogLevels.INFO, prefix = ChatComponent.of(additionalPrefix)) { it.message.text }
- })
+ }
}
- ProtocolStates.CONFIGURATION -> Unit
+ else -> Unit
}
}
ticker.init()
@@ -206,7 +212,7 @@ class PlaySession(
}
val keyManagement = SignatureKeyManagement(this, account)
- if (version.requiresSignedChat && !profiles.session.signature.disableKeys) {
+ if (version.requiresSignedChat && !profiles.session.signature.disableKeys && connection is NetworkConnection) {
taskWorker += WorkerTask(optional = true) { keyManagement.init(latch) }
}
@@ -242,8 +248,7 @@ class PlaySession(
private fun establish(latch: AbstractLatch?) {
latch?.dec() // remove initial value
- Log.log(LogMessageType.NETWORK, level = LogLevels.INFO) { "Connecting to server: $address" }
- network.connect(address, profiles.other.nativeNetwork)
+ network.connect()
state = PlaySessionStates.ESTABLISHING
}
@@ -260,7 +265,7 @@ class PlaySession(
}
override fun terminate() {
- super.terminate()
+ network.disconnect()
state = PlaySessionStates.DISCONNECTED
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/session/status/StatusSession.kt b/src/main/java/de/bixilon/minosoft/protocol/network/session/status/StatusSession.kt
index 1d81620e3..1bbb2c79c 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/session/status/StatusSession.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/session/status/StatusSession.kt
@@ -17,7 +17,8 @@ import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.observer.DataObserver.Companion.observed
import de.bixilon.minosoft.modding.event.events.session.status.StatusSessionCreateEvent
import de.bixilon.minosoft.modding.event.master.GlobalEventMaster
-import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.AddressResolver
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.Session
import de.bixilon.minosoft.protocol.packets.c2s.handshake.HandshakeC2SP
import de.bixilon.minosoft.protocol.packets.c2s.status.StatusRequestC2SP
@@ -27,132 +28,111 @@ import de.bixilon.minosoft.protocol.status.StatusPing
import de.bixilon.minosoft.protocol.status.StatusPong
import de.bixilon.minosoft.protocol.versions.Version
import de.bixilon.minosoft.protocol.versions.Versions
-import de.bixilon.minosoft.util.DNSUtil
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogMessageType
class StatusSession(
- var address: String,
+ var hostname: String,
var forcedVersion: Version? = null,
) : Session() {
+ var connection: NetworkConnection? = null
+ private var resolver: AddressResolver? = null
+
var status: ServerStatus? by observed(null)
var ping: StatusPing? by observed(null)
var pong: StatusPong? by observed(null)
- var realAddress: ServerAddress? = null
- private set
- private var addresses: List? = null
- private var addressIndex = 0
-
var serverVersion: Version? = null
var state by observed(StatusSessionStates.WAITING)
val timeout = TimeoutHandler(this)
-
init {
this::error.observe(this) {
if (it == null) return@observe
- ping = null
- status = null
+ terminate()
+ reset()
state = StatusSessionStates.ERROR
- timeout.cancel()
- network.disconnect()
- }
- network::connected.observe(this) {
- if (it) {
- state = StatusSessionStates.HANDSHAKING
- network.send(HandshakeC2SP(realAddress!!, HandshakeC2SP.Actions.STATUS, forcedVersion?.protocolId ?: Versions.AUTOMATIC.protocolId))
- network.state = ProtocolStates.STATUS
- return@observe
- }
- if (status != null) {
- return@observe
- }
- tryNextAddress()
- }
-
- network::state.observe(this) {
- when (it) {
- ProtocolStates.HANDSHAKE -> {}
- ProtocolStates.PLAY, ProtocolStates.LOGIN, ProtocolStates.CONFIGURATION -> throw IllegalStateException("Invalid state!")
- ProtocolStates.STATUS -> {
- state = StatusSessionStates.QUERYING_STATUS
- network.send(StatusRequestC2SP())
- }
- }
}
GlobalEventMaster.fire(StatusSessionCreateEvent(this))
- }
- private fun tryNextAddress() {
- val addresses = this.addresses ?: return
- val nextIndex = ++addressIndex
- if (addresses.size > nextIndex) {
- val nextAddress = addresses[nextIndex]
- Log.log(LogMessageType.NETWORK) { "Could not connect to $address, trying next hostname: $nextAddress" }
- realAddress = nextAddress
- ping(nextAddress)
+ this::error.observe(this) {
+ if (it == null) return@observe
+ tryNext()
}
}
- private fun resolve(): List {
- state = StatusSessionStates.RESOLVING
+ private fun NetworkConnection.register() {
+ this::state.observe(this) {
+ if (this@StatusSession.connection != this) return@observe
+ when (it) {
+ ProtocolStates.HANDSHAKE -> {
+ // send handshake
+ send(HandshakeC2SP(hostname, this.address.port, HandshakeC2SP.Actions.STATUS, forcedVersion?.protocolId ?: Versions.AUTOMATIC.protocolId))
+ state = ProtocolStates.STATUS
+ }
- var addresses = this.addresses
- if (addresses == null) {
- addresses = DNSUtil.resolveServerAddress(address)
- realAddress = addresses.first()
- this.addresses = addresses
- this.addressIndex = 0
+ ProtocolStates.STATUS -> {
+ this@StatusSession.state = StatusSessionStates.QUERYING_STATUS
+ send(StatusRequestC2SP())
+ }
+
+ null -> Unit // done
+
+ else -> throw IllegalStateException("Illegal status state: $it")
+ }
}
- return addresses
+ }
+
+ override fun terminate() {
+ timeout.cancel()
+ this.connection?.disconnect()
+ this.connection = null
+ state = StatusSessionStates.WAITING
}
fun reset() {
- timeout.cancel()
- realAddress = null
- this.addresses = null
- this.addressIndex = 0
status = null
ping = null
pong = null
serverVersion = null
error = null
- state = StatusSessionStates.WAITING
}
- fun ping(address: ServerAddress) {
- if (state == StatusSessionStates.ESTABLISHING || network.connected) {
+ private fun tryNext(): Boolean {
+ val network = resolver!!.tryNext() ?: return false
+ this.connection = network
+
+ if (state == StatusSessionStates.ESTABLISHING) {
error("Already connecting!")
}
+
timeout.register()
- Log.log(LogMessageType.NETWORK) { "Pinging $address (from ${this.address})" }
+ Log.log(LogMessageType.NETWORK) { "Pinging ${network.address} (from ${this.hostname})" }
state = StatusSessionStates.ESTABLISHING
- network.connect(address, false)
+ network.register()
+ network.connect(this)
+
+ return true
}
fun ping() {
- if (state == StatusSessionStates.RESOLVING || state == StatusSessionStates.ESTABLISHING || network.connected) {
+ if (state == StatusSessionStates.RESOLVING || state == StatusSessionStates.ESTABLISHING) {
error("Already connecting!")
}
+ terminate()
reset()
+
state = StatusSessionStates.RESOLVING
- val addresses: List
try {
- // TODO: Don't resolve if address is ip
- addresses = resolve()
- } catch (exception: Exception) {
- Log.log(LogMessageType.NETWORK) { "Can not resolve ${this.address}" }
+ val resolver = AddressResolver(hostname)
+ this.resolver = resolver
+ } catch (error: Exception) {
+ Log.log(LogMessageType.NETWORK) { "Can not resolve ${this.hostname}" }
return
}
- ping(addresses.first())
- }
-
- override fun terminate() {
- super.terminate()
- state = StatusSessionStates.WAITING
+ tryNext()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/c2s/handshake/HandshakeC2SP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/c2s/handshake/HandshakeC2SP.kt
index 6afcbec1b..9d264e78e 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/c2s/handshake/HandshakeC2SP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/c2s/handshake/HandshakeC2SP.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2023 Moritz Zwerger
+ * Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -12,7 +12,6 @@
*/
package de.bixilon.minosoft.protocol.packets.c2s.handshake
-import de.bixilon.minosoft.protocol.address.ServerAddress
import de.bixilon.minosoft.protocol.packets.c2s.C2SPacket
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.protocol.protocol.buffers.OutByteBuffer
@@ -21,20 +20,21 @@ import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
class HandshakeC2SP(
- val address: ServerAddress,
+ val hostname: String,
+ val port: Int,
val action: Actions = Actions.STATUS,
val protocolId: Int = ProtocolDefinition.QUERY_PROTOCOL_VERSION_ID,
) : C2SPacket {
override fun write(buffer: OutByteBuffer) {
buffer.writeVarInt(protocolId)
- buffer.writeString(address.hostname)
- buffer.writeShort(address.port)
+ buffer.writeString(hostname)
+ buffer.writeShort(port)
buffer.writeVarInt(action.protocolId)
}
override fun log(reducedLog: Boolean) {
- Log.log(LogMessageType.NETWORK_OUT, LogLevels.VERBOSE) { "Handshake (protocolId=$protocolId, hostname=${address.hostname}, port=${address.port}, action=$action)" }
+ Log.log(LogMessageType.NETWORK_OUT, LogLevels.VERBOSE) { "Handshake (protocolId=$protocolId, hostname=${hostname}, port=${port}, action=$action)" }
}
enum class Actions(val protocolId: Int) {
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/registry/PacketType.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/registry/PacketType.kt
index e10fe0612..663a90150 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/registry/PacketType.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/registry/PacketType.kt
@@ -13,10 +13,13 @@
package de.bixilon.minosoft.protocol.packets.registry
+import de.bixilon.kutil.cast.CastUtil.nullCast
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.PacketBufferUnderflowException
import de.bixilon.minosoft.protocol.network.network.client.netty.exceptions.implementation.PacketNotImplementedException
import de.bixilon.minosoft.protocol.network.session.Session
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
+import de.bixilon.minosoft.protocol.network.session.status.StatusSession
import de.bixilon.minosoft.protocol.packets.registry.factory.PacketFactory
import de.bixilon.minosoft.protocol.packets.types.Packet
import de.bixilon.minosoft.protocol.protocol.buffers.InByteBuffer
@@ -31,7 +34,8 @@ class PacketType(
) {
fun create(data: ByteArray, session: Session): Packet {
- val factory = this.factory ?: throw PacketNotImplementedException(name, session.network.state, session.version)
+ val connection = session.nullCast()?.connection ?: session.nullCast()?.connection?.nullCast()
+ val factory = this.factory ?: throw PacketNotImplementedException(name, connection!!.state!!, session.version)
val buffer = if (session is PlaySession) PlayInByteBuffer(data, session) else InByteBuffer(data)
val packet = factory.create(buffer)
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/common/KickS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/common/KickS2CP.kt
index b16fb58c2..5ea8ceca8 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/common/KickS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/common/KickS2CP.kt
@@ -28,18 +28,18 @@ class KickS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
val reason: ChatComponent = if (buffer.session.network.state == ProtocolStates.LOGIN && buffer.versionId >= V_23W42A) buffer.readChatComponent() else buffer.readNbtChatComponent()
override fun handle(session: PlaySession) {
- if (!session.network.connected) {
+ if (!session.connection.active) {
return // already disconnected, maybe timed out?
}
session.events.fire(KickEvent(session, reason))
// got kicked
- session.network.disconnect()
+ session.terminate()
if (session.network.state == ProtocolStates.LOGIN) {
session.state = PlaySessionStates.ERROR
} else {
session.state = PlaySessionStates.KICKED
}
- Log.log(LogMessageType.NETWORK, LogLevels.WARN) { "Kicked from ${session.address}: $reason" }
+ Log.log(LogMessageType.NETWORK, LogLevels.WARN) { "Kicked from ${session.connection.identifier}: $reason" }
}
override fun log(reducedLog: Boolean) {
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/PongS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/PongS2CP.kt
index 3be32c3a4..b8c6c1569 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/PongS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/PongS2CP.kt
@@ -28,7 +28,7 @@ class PongS2CP(buffer: InByteBuffer) : StatusS2CPacket {
override fun handle(session: StatusSession) {
val ping = session.ping ?: return
val latency = nanos() - ping.nanos
- session.network.disconnect()
+ session.terminate()
session.pong = StatusPong(latency)
session.state = StatusSessionStates.PING_DONE
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/StatusS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/StatusS2CP.kt
index 15b9eb462..91dd91ee5 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/StatusS2CP.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/status/StatusS2CP.kt
@@ -41,7 +41,7 @@ class StatusS2CP(buffer: InByteBuffer) : StatusS2CPacket {
val ping = StatusPing()
session.ping = ping
session.state = StatusSessionStates.QUERYING_PING
- session.network.send(PingC2SP(ThreadLocalRandom.current().nextLong()))
+ session.connection?.send(PingC2SP(ThreadLocalRandom.current().nextLong()))
}
override fun log(reducedLog: Boolean) {
diff --git a/src/main/java/de/bixilon/minosoft/terminal/AutoConnect.kt b/src/main/java/de/bixilon/minosoft/terminal/AutoConnect.kt
index a617e5cbd..ef4b98acd 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/AutoConnect.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/AutoConnect.kt
@@ -19,6 +19,7 @@ import de.bixilon.kutil.shutdown.ShutdownManager
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.network.session.play.PlaySessionStates.Companion.disconnected
import de.bixilon.minosoft.protocol.network.session.status.StatusSession
@@ -35,7 +36,7 @@ object AutoConnect {
private fun autoConnect(address: ServerAddress, version: Version, account: Account) {
val session = PlaySession(
- address = address,
+ connection = NetworkConnection(address, true), // TODO: native network
account = account,
version = version,
)
@@ -67,7 +68,7 @@ object AutoConnect {
if (version == Versions.AUTOMATIC) {
Log.log(LogMessageType.AUTO_CONNECT, LogLevels.INFO) { "Pinging server to get version..." }
val ping = StatusSession(address)
- ping::status.observe(this) { autoConnect(ping.realAddress!!, ping.serverVersion ?: throw IllegalArgumentException("Could not determinate server's version!"), account) }
+ ping::status.observe(this) { autoConnect(ping.connection!!.address, ping.serverVersion ?: throw IllegalArgumentException("Could not determinate server's version!"), account) }
ping::error.observe(this) { exitProcess(1) }
ping.ping()
return
diff --git a/src/main/java/de/bixilon/minosoft/terminal/commands/ConnectCommand.kt b/src/main/java/de/bixilon/minosoft/terminal/commands/ConnectCommand.kt
index 110721ac9..612c94758 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/commands/ConnectCommand.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/commands/ConnectCommand.kt
@@ -22,6 +22,7 @@ import de.bixilon.minosoft.commands.stack.print.PrintTarget
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.protocol.address.ServerAddress
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
import de.bixilon.minosoft.protocol.network.session.status.StatusSession
import de.bixilon.minosoft.protocol.versions.Version
@@ -38,7 +39,7 @@ object ConnectCommand : Command {
if (version == null) {
stack.print.print("Pinging server to get version...")
val ping = StatusSession(address)
- ping::status.observe(this) { connect(stack.print, ping.realAddress!!, ping.serverVersion ?: throw IllegalArgumentException("Could not determinate server's version!"), account) }
+ ping::status.observe(this) { connect(stack.print, ping.connection!!.address, ping.serverVersion ?: throw IllegalArgumentException("Could not determinate server's version!"), account) }
ping::error.observe(this) { stack.print.print("Could not ping $address: $it") }
ping.ping()
return@add
@@ -52,7 +53,7 @@ object ConnectCommand : Command {
private fun connect(print: PrintTarget, address: ServerAddress, version: Version, account: Account) {
print.print("Connecting to $address")
- val session = PlaySession(address, account, version)
+ val session = PlaySession(NetworkConnection(address, true), account, version) // TODO: native network
session.connect()
}
}
diff --git a/src/main/java/de/bixilon/minosoft/terminal/commands/SessionManageCommand.kt b/src/main/java/de/bixilon/minosoft/terminal/commands/SessionManageCommand.kt
index a975d1b4e..867ae0d74 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/commands/SessionManageCommand.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/commands/SessionManageCommand.kt
@@ -31,20 +31,20 @@ object SessionManageCommand : Command {
val filtered = it.collect()
if (filtered.isEmpty()) throw CommandException("No session matched your filter!")
- it.print.print(table(filtered, "Id", "State", "Address") { c -> arrayOf(c.id, c.state, c.address) })
+ it.print.print(table(filtered, "Id", "State", "Address") { c -> arrayOf(c.id, c.state, c.connection.identifier) })
})
.addChild(ArgumentNode("filter", SessionParser, executable = true)),
LiteralNode("terminate", aliases = setOf("disconnect")).apply {
addFilter { stack, sessions ->
var count = 0
- sessions.filter { it.network.connected }.forEach { it.terminate(); count++ }
+ sessions.forEach { it.terminate(); count++ }
stack.print.print("Terminated $count sessions.")
}
},
LiteralNode("select").apply {
addFilter(false) { stack, sessions ->
val session = sessions.first()
- if (!session.network.connected) {
+ if (session.network.connection.state == null) {
throw CommandException("Session $session not established anymore!")
}
CLI.session = session
diff --git a/src/main/java/de/bixilon/minosoft/util/DNSUtil.kt b/src/main/java/de/bixilon/minosoft/util/DNSUtil.kt
index f50d6def7..b72d20cc1 100644
--- a/src/main/java/de/bixilon/minosoft/util/DNSUtil.kt
+++ b/src/main/java/de/bixilon/minosoft/util/DNSUtil.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2023 Moritz Zwerger
+ * Copyright (C) 2020-2024 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -22,21 +22,22 @@ import org.xbill.DNS.Type
object DNSUtil {
fun resolveServerAddress(hostname: String): List {
- val originalAddress = getServerAddress(hostname)
+ val original = getServerAddress(hostname)
+ // TODO: Don't resolve if address is ip address
if (":" in hostname) {
// port provided, skip srv check
- return listOf(originalAddress)
+ return listOf(original)
}
val query = "_minecraft._tcp.$hostname"
- val records = catchAll { Lookup(query, Type.SRV).run() } ?: return listOf(originalAddress)
+ val records = catchAll { Lookup(query, Type.SRV).run() } ?: return listOf(original)
val addresses: MutableList = mutableListOf()
for (record in records) {
if (record !is SRVRecord) continue
addresses += ServerAddress(record.target.toString(true), record.port)
}
- addresses += originalAddress
+ addresses += original
return addresses
}
diff --git a/src/main/java/de/bixilon/minosoft/util/crash/section/SessionCrashSection.kt b/src/main/java/de/bixilon/minosoft/util/crash/section/SessionCrashSection.kt
index 521950372..311f2ff86 100644
--- a/src/main/java/de/bixilon/minosoft/util/crash/section/SessionCrashSection.kt
+++ b/src/main/java/de/bixilon/minosoft/util/crash/section/SessionCrashSection.kt
@@ -13,6 +13,7 @@
package de.bixilon.minosoft.util.crash.section
+import de.bixilon.minosoft.protocol.connection.NetworkConnection
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
class SessionCrashSection(
@@ -20,16 +21,19 @@ class SessionCrashSection(
) : ArrayCrashSection("Sessions", sessions) {
override fun format(entry: PlaySession, builder: StringBuilder, intent: String) {
+ val connection = entry.connection
builder.appendProperty(intent, "Id", entry.id)
builder.appendProperty(intent, "Version", entry.version)
builder.appendProperty(intent, "Account", entry.account.username)
- builder.appendProperty(intent, "Address", entry.address)
+ builder.appendProperty(intent, "Address", entry.connection.identifier)
builder.appendProperty(intent, "Brand", entry.serverInfo.brand)
builder.appendProperty(intent, "Events", entry.events.size)
builder.appendProperty(intent, "State", entry.state)
- builder.appendProperty(intent, "DefaultPacketMapping state", entry.network.state)
- builder.appendProperty(intent, "Compression threshold", entry.network.compressionThreshold)
- builder.appendProperty(intent, "Encrypted", entry.network.encrypted)
+ if (connection is NetworkConnection) {
+ builder.appendProperty(intent, "Network state", connection.state)
+ builder.appendProperty(intent, "Compression threshold", connection.client?.compressionThreshold)
+ builder.appendProperty(intent, "Encrypted", connection.client?.encrypted)
+ }
builder.appendProperty(intent, "Was connected", entry.established)
builder.appendProperty(intent, "Rendering", entry.rendering != null)
builder.appendProperty(intent, "Error", entry.error)
diff --git a/src/test/java/de/bixilon/minosoft/data/text/ChatComponentTest.kt b/src/test/java/de/bixilon/minosoft/data/text/ChatComponentTest.kt
index 6d87cca8d..b86e7050e 100644
--- a/src/test/java/de/bixilon/minosoft/data/text/ChatComponentTest.kt
+++ b/src/test/java/de/bixilon/minosoft/data/text/ChatComponentTest.kt
@@ -318,6 +318,15 @@ internal class ChatComponentTest {
assertEquals(text, expected)
}
+ @Test
+ fun something() { // tree.ac
+ val string = """"§2Join the Other Server? Find it at §6Port 25566§2!""""
+ val chat = ChatComponent.of(string)
+
+ TODO()
+
+ }
+
private fun assertEquals(expected: ChatComponent, actual: ChatComponent) {
when (expected) {
is BaseComponent -> {