From 23c8a81c40b2fc5409d1c02ce847884679c14e22 Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Thu, 17 Aug 2023 01:00:26 +0530 Subject: [PATCH] Prepare for 1.20.2 with CONFIGURATION conn state. --- .../modules/connection/ConnectionModule.kt | 10 +++--- .../com/enderchat/modules/connection/Utils.kt | 5 +++ src/minecraft/connection/index.ts | 8 ++++- src/minecraft/connection/javascript.ts | 34 ++++++++++++++----- src/minecraft/connection/native.ts | 23 ++++++++----- src/minecraft/pingServer.ts | 4 +-- src/screens/chat/packetHandler.ts | 10 ++++-- 7 files changed, 67 insertions(+), 27 deletions(-) diff --git a/android/app/src/main/java/com/enderchat/modules/connection/ConnectionModule.kt b/android/app/src/main/java/com/enderchat/modules/connection/ConnectionModule.kt index 449c0c2..29e105b 100644 --- a/android/app/src/main/java/com/enderchat/modules/connection/ConnectionModule.kt +++ b/android/app/src/main/java/com/enderchat/modules/connection/ConnectionModule.kt @@ -33,7 +33,7 @@ class ConnectionModule(reactContext: ReactApplicationContext) private var compressionEnabled = false private var aesDecipher: Cipher? = null private var aesCipher: Cipher? = null - private var loggedIn = false + private var state = ConnectionState.LOGIN override fun getName() = "ConnectionModule" @@ -47,7 +47,7 @@ class ConnectionModule(reactContext: ReactApplicationContext) compressionEnabled = false aesDecipher = null aesCipher = null - loggedIn = false + state = ConnectionState.LOGIN } private fun directlyWritePacket(id: Int, data: ByteArray): Boolean { @@ -253,12 +253,12 @@ class ConnectionModule(reactContext: ReactApplicationContext) // No write lock since writePacket isn't called during login sequence (usually). if (packet.id.value == keepAliveClientBoundId) { directlyWritePacket(keepAliveServerBoundId, packet.data) - } else if (packet.id.value == setCompressionId && !loggedIn) { + } else if (packet.id.value == setCompressionId && state == ConnectionState.LOGIN) { val threshold = VarInt.read(packet.data)?.value ?: 0 compressionThreshold = threshold compressionEnabled = threshold >= 0 - } else if (packet.id.value == loginSuccessId && !loggedIn) { - loggedIn = true + } else if (packet.id.value == loginSuccessId && state == ConnectionState.LOGIN) { + state = ConnectionState.PLAY } // Forward the packet to JavaScript. diff --git a/android/app/src/main/java/com/enderchat/modules/connection/Utils.kt b/android/app/src/main/java/com/enderchat/modules/connection/Utils.kt index c61e707..7d3aeb4 100644 --- a/android/app/src/main/java/com/enderchat/modules/connection/Utils.kt +++ b/android/app/src/main/java/com/enderchat/modules/connection/Utils.kt @@ -4,6 +4,11 @@ import java.io.ByteArrayOutputStream import java.util.zip.Deflater import java.util.zip.Inflater +enum class ConnectionState { + LOGIN, + PLAY +} + const val PROTOCOL_VERSION_1164 = 754 const val PROTOCOL_VERSION_117 = 755 const val PROTOCOL_VERSION_119 = 759 diff --git a/src/minecraft/connection/index.ts b/src/minecraft/connection/index.ts index 06b9df2..3ef78f3 100644 --- a/src/minecraft/connection/index.ts +++ b/src/minecraft/connection/index.ts @@ -15,9 +15,15 @@ export interface ConnectionOptions { certificate?: Certificate } +export enum ConnectionState { + LOGIN, + CONFIGURATION, + PLAY +} + export interface ServerConnection extends events.EventEmitter { options: ConnectionOptions - loggedIn: boolean + state: ConnectionState closed: boolean msgSalt?: Buffer disconnectReason?: string diff --git a/src/minecraft/connection/javascript.ts b/src/minecraft/connection/javascript.ts index 0a75795..818320a 100644 --- a/src/minecraft/connection/javascript.ts +++ b/src/minecraft/connection/javascript.ts @@ -16,7 +16,11 @@ import { parseCompressedPacket, parsePacket } from '../packet' -import { type ServerConnection, type ConnectionOptions } from '.' +import { + type ServerConnection, + type ConnectionOptions, + ConnectionState +} from '.' import { getLoginPacket, handleEncryptionRequest } from './shared' import { readVarInt, writeVarInt, resolveHostname } from '../utils' import packetIds from '../packets/ids' @@ -38,7 +42,7 @@ export class JavaScriptServerConnection bufferedData: Buffer = Buffer.from([]) compressionThreshold = -1 compressionEnabled = false - loggedIn = false + state = ConnectionState.LOGIN closed = false socket: net.Socket options: ConnectionOptions @@ -140,12 +144,18 @@ const initiateJavaScriptConnection = async ( : conn.bufferedData.slice(packet.packetLength) // Internally handle login packets. const { protocolVersion: version } = conn.options - if (packet.id === 0x03 && !conn.loggedIn /* Set Compression */) { + if ( + packet.id === 0x03 && + conn.state === ConnectionState.LOGIN /* Set Compression */ + ) { const [threshold] = readVarInt(packet.data) conn.compressionThreshold = threshold conn.compressionEnabled = threshold >= 0 - } else if (packet.id === 0x02 && !conn.loggedIn) { - conn.loggedIn = true // Login Success + } else if ( + packet.id === 0x02 && + conn.state === ConnectionState.LOGIN /* Login Success */ + ) { + conn.state = ConnectionState.PLAY } else if ( packet.id === packetIds.CLIENTBOUND_KEEP_ALIVE(version) ) { @@ -155,20 +165,26 @@ const initiateJavaScriptConnection = async ( .catch(err => conn.emit('error', err)) } else if ( // Disconnect (login) or Disconnect (play) - (packet.id === 0x00 && !conn.loggedIn) || + (packet.id === 0x00 && conn.state === ConnectionState.LOGIN) || (packet.id === packetIds.CLIENTBOUND_DISCONNECT_PLAY(version) && - conn.loggedIn) + conn.state === ConnectionState.PLAY) ) { const [chatLength, chatVarIntLength] = readVarInt(packet.data) conn.disconnectReason = packet.data .slice(chatVarIntLength, chatVarIntLength + chatLength) .toString('utf8') - } else if (packet.id === 0x04 && !conn.loggedIn) { + } else if ( + packet.id === 0x04 && + conn.state === ConnectionState.LOGIN + ) { /* Login Plugin Request */ const [msgId] = readVarInt(packet.data) const rs = concatPacketData([writeVarInt(msgId), false]) conn.writePacket(0x02, rs).catch(err => conn.emit('error', err)) - } else if (packet.id === 0x01 && !conn.loggedIn) { + } else if ( + packet.id === 0x01 && + conn.state === ConnectionState.LOGIN + ) { /* Encryption Request */ if (!accessToken || !selectedProfile) { conn.disconnectReason = diff --git a/src/minecraft/connection/native.ts b/src/minecraft/connection/native.ts index 48b04a5..a0e8fd4 100644 --- a/src/minecraft/connection/native.ts +++ b/src/minecraft/connection/native.ts @@ -4,7 +4,11 @@ import { NativeModules } from 'react-native' import events from 'events' -import { type ServerConnection, type ConnectionOptions } from '.' +import { + type ServerConnection, + type ConnectionOptions, + ConnectionState +} from '.' import { concatPacketData, type Packet } from '../packet' import { getLoginPacket, handleEncryptionRequest } from './shared' import { readVarInt, writeVarInt, resolveHostname } from '../utils' @@ -43,7 +47,7 @@ export class NativeServerConnection { /* eslint-enable @typescript-eslint/brace-style */ eventEmitter = new NativeEventEmitter(ConnectionModule) - loggedIn = false + state = ConnectionState.LOGIN closed = false id: string options: ConnectionOptions @@ -89,24 +93,27 @@ export class NativeServerConnection const { protocolVersion: version } = options // Set Compression and Keep Alive are handled in native for now. // When modifying this code, apply the same changes to the JavaScript back-end. - if (packet.id === 0x02 && !this.loggedIn /* Login Success */) { - this.loggedIn = true + if ( + packet.id === 0x02 && + this.state === ConnectionState.LOGIN /* Login Success */ + ) { + this.state = ConnectionState.PLAY } else if ( // Disconnect (login) or Disconnect (play) - (packet.id === 0x00 && !this.loggedIn) || + (packet.id === 0x00 && this.state === ConnectionState.LOGIN) || (packet.id === packetIds.CLIENTBOUND_DISCONNECT_PLAY(version) && - this.loggedIn) + this.state === ConnectionState.PLAY) ) { const [chatLength, chatVarIntLength] = readVarInt(packet.data) this.disconnectReason = packet.data .slice(chatVarIntLength, chatVarIntLength + chatLength) .toString('utf8') - } else if (packet.id === 0x04 && !this.loggedIn) { + } else if (packet.id === 0x04 && this.state === ConnectionState.LOGIN) { /* Login Plugin Request */ const [msgId] = readVarInt(packet.data) const rs = concatPacketData([writeVarInt(msgId), false]) this.writePacket(0x02, rs).catch(err => this.emit('error', err)) - } else if (packet.id === 0x01 && !this.loggedIn) { + } else if (packet.id === 0x01 && this.state === ConnectionState.LOGIN) { /* Encryption Request */ const { accessToken, selectedProfile } = options if (!accessToken || !selectedProfile) { diff --git a/src/minecraft/pingServer.ts b/src/minecraft/pingServer.ts index a3d0577..4c7212f 100644 --- a/src/minecraft/pingServer.ts +++ b/src/minecraft/pingServer.ts @@ -88,7 +88,7 @@ export const legacyPing = async (opts: { len: data.readUInt16BE(1), protocol: +parts[1], version: parts[2], - ping: time / 2, + ping: time, motd: parts[3], online: +parts[4], maxPlayers: +parts[5] @@ -155,7 +155,7 @@ export const modernPing = async (opts: { const response = parseValidJson(json) resolve({ - ping: (timeReceived - timeSent) / 2, + ping: timeReceived - timeSent, version: response.version, players: response.players, favicon: response.favicon, diff --git a/src/screens/chat/packetHandler.ts b/src/screens/chat/packetHandler.ts index 78c712e..31a9c9b 100644 --- a/src/screens/chat/packetHandler.ts +++ b/src/screens/chat/packetHandler.ts @@ -1,7 +1,10 @@ import type React from 'react' import { type Status } from './ChatScreen' import { type MinecraftChat, parseValidJson } from '../../minecraft/chatToJsx' -import { type ServerConnection } from '../../minecraft/connection' +import { + ConnectionState, + type ServerConnection +} from '../../minecraft/connection' import { concatPacketData, type Packet, @@ -99,7 +102,10 @@ export const packetHandler = ) => (packet: Packet) => { const { protocolVersion: version } = connection.options - if (statusRef.current === 'CONNECTING' && connection.loggedIn) { + if ( + statusRef.current === 'CONNECTING' && + connection.state === ConnectionState.LOGIN + ) { setLoading('') statusRef.current = 'CONNECTED' const messageToSend = joinMessage.substring(0, charLimit).trim()