From 3a0d6e61285dfa4b3d588cffa72536b62e452e18 Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Tue, 14 Jun 2022 15:15:19 +0530 Subject: [PATCH] 1.19 login support. No chat support yet. - 1.19 is unlisted and 1.18.2 is still default. - Add disconnect translations for 1.19. - Support new 1.19 login packet format. - Chat signing is broken, so is chat format parsing. --- TODO | 2 -- src/minecraft/chatToJsx.tsx | 4 ++- src/minecraft/connection.ts | 12 +++++++-- src/minecraft/translations.ts | 28 ++++++++++++++++++++ src/minecraft/utils.ts | 1 + src/screens/ChatScreen.tsx | 48 ++++++++++++++++++++++++++++++----- 6 files changed, 84 insertions(+), 11 deletions(-) diff --git a/TODO b/TODO index 9285ae2..f9ad6e8 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ -- Finish online mode support. - Add icon and configure app.json. - Reduce bundled icons (1.3 MB per APK). -- Fix issue with split-screen when connected. - Work on replacing auto /spawn with auto commands. - Handle graceful disconnect when being hit by the OOM killer? - https://reactnative.dev/docs/performance (esp when logging in, causes crashes) diff --git a/src/minecraft/chatToJsx.tsx b/src/minecraft/chatToJsx.tsx index de88c7f..7f1fab4 100644 --- a/src/minecraft/chatToJsx.tsx +++ b/src/minecraft/chatToJsx.tsx @@ -183,7 +183,9 @@ const parseChatToJsx = ( ?.flat() ?.filter(component => !!component) chat = { - extra: translation ?? [{ text: '[EnderChat] Unknown translation.' }] + extra: translation ?? [ + { text: `[EnderChat] Unknown translation ${translatedChat.translate}.` } + ] } } const flat = diff --git a/src/minecraft/connection.ts b/src/minecraft/connection.ts index 292a897..76368b0 100644 --- a/src/minecraft/connection.ts +++ b/src/minecraft/connection.ts @@ -24,7 +24,8 @@ import { resolveHostname, generateSharedSecret, mcHexDigest, - authUrl + authUrl, + protocolMap } from './utils' export interface ConnectionOptions { @@ -112,7 +113,14 @@ const initiateConnection = async (opts: ConnectionOptions) => { socket.write(makeBasePacket(0x00, concatPacketData(handshakeData)), () => // Send Login Start packet. socket.write( - makeBasePacket(0x00, concatPacketData([opts.username])), + makeBasePacket( + 0x00, + concatPacketData( + opts.protocolVersion < protocolMap[1.19] + ? [opts.username] + : [opts.username, false] // TODO-1.19: Support chat signing keys. + ) + ), () => { resolved = true resolve(conn) diff --git a/src/minecraft/translations.ts b/src/minecraft/translations.ts index 1b73e63..6c39777 100644 --- a/src/minecraft/translations.ts +++ b/src/minecraft/translations.ts @@ -90,6 +90,34 @@ const translations: { [translation: string]: string } = { 'Incomplete set of tags received from server.\nPlease contact server operator.', 'multiplayer.socialInteractions.not_available': 'Social Interactions are only available in Multiplayer worlds', + 'multiplayer.disconnect.missing_public_key': + 'Missing profile public key.\nThis server requires secure profiles.', + 'multiplayer.disconnect.invalid_public_key_signature': + 'Invalid signature for profile public key.\nTry restarting your game.', + 'multiplayer.disconnect.invalid_public_key': + 'Unable to parse profile public key.', + 'multiplayer.disconnect.out_of_order_chat': + 'Out-of-order chat packet received. Did your system time change?', + 'disconnect.genericReason': '%s', + 'disconnect.unknownHost': 'Unknown host', + 'disconnect.disconnected': 'Disconnected by Server', + 'disconnect.lost': 'Connection Lost', + 'disconnect.kicked': 'Was kicked from the game', + 'disconnect.timeout': 'Timed out', + 'disconnect.closed': 'Connection closed', + 'disconnect.loginFailed': 'Failed to log in', + 'disconnect.loginFailedInfo': 'Failed to log in: %s', + 'disconnect.loginFailedInfo.serversUnavailable': + 'The authentication servers are currently not reachable. Please try again.', + 'disconnect.loginFailedInfo.invalidSession': + 'Invalid session (Try restarting your game and the launcher)', + 'disconnect.loginFailedInfo.insufficientPrivileges': + 'Multiplayer is disabled. Please check your Microsoft account settings.', + 'disconnect.quitting': 'Quitting', + 'disconnect.endOfStream': 'End of stream', + 'disconnect.overflow': 'Buffer overflow', + 'disconnect.spam': 'Kicked for spamming', + 'disconnect.exceeded_packet_rate': 'Kicked for exceeding packet rate limit', 'chat.editBox': 'chat', 'chat.cannotSend': 'Cannot send chat message', 'chat.disabled.options': 'Chat disabled in client options', diff --git a/src/minecraft/utils.ts b/src/minecraft/utils.ts index 01909a1..c644bb2 100644 --- a/src/minecraft/utils.ts +++ b/src/minecraft/utils.ts @@ -10,6 +10,7 @@ export const protocolMap = { 1.18: 757, '1.18.1': 757, '1.18.2': 758, + 1.19: 759, auto: -1 } diff --git a/src/screens/ChatScreen.tsx b/src/screens/ChatScreen.tsx index 294cb8a..a7b3384 100644 --- a/src/screens/ChatScreen.tsx +++ b/src/screens/ChatScreen.tsx @@ -24,7 +24,7 @@ import { ClickEvent, ColorMap } from '../minecraft/chatToJsx' -import { readVarInt, writeVarInt } from '../minecraft/utils' +import { protocolMap, readVarInt, writeVarInt } from '../minecraft/utils' import { concatPacketData } from '../minecraft/packet' import TextField from '../components/TextField' import Text from '../components/Text' @@ -134,14 +134,39 @@ const ChatScreen = ({ navigation }: { navigation: ChatNavigationProp }) => { .writePacket(0x03, concatPacketData(['/spawn'])) .catch(errorHandler(addMessage, sendMessageErr)) } - } else if (packet.id === 0x0f /* Chat Message (clientbound) */) { + } else if ( + packet.id === 0x0f /* Chat Message (clientbound) */ && + connection.connection.options.protocolVersion < protocolMap['1.19'] + ) { try { const [chatLength, chatVarIntLength] = readVarInt(packet.data) const chatJson = packet.data .slice(chatVarIntLength, chatVarIntLength + chatLength) .toString('utf8') const position = packet.data.readInt8(chatVarIntLength + chatLength) - // TODO: Support position 2 and sender. + // TODO: Support position 2 (also in 0x5f packet) and sender for disableChat/blocked players. + if (position === 0 || position === 1) { + addMessage(parseValidJson(chatJson)) + } + } catch (e) { + errorHandler(addMessage, parseMessageErr)(e) + } + } else if ( + packet.id === 0x30 /* Player Chat Message (clientbound) */ && + connection.connection.options.protocolVersion >= protocolMap['1.19'] + ) { + // TODO-1.19: Support player chat messages. + } else if ( + packet.id === 0x5f /* System Chat Message (clientbound) */ && + connection.connection.options.protocolVersion >= protocolMap['1.19'] + ) { + try { + const [chatLength, chatVarIntLength] = readVarInt(packet.data) + const chatJson = packet.data + .slice(chatVarIntLength, chatVarIntLength + chatLength) + .toString('utf8') + const position = packet.data.readInt8(chatVarIntLength + chatLength) + // TODO-1.19 - 3: say command, 4: msg command, 5: team msg command, 6: emote command, 7: tellraw command if (position === 0 || position === 1) { addMessage(parseValidJson(chatJson)) } @@ -212,9 +237,20 @@ const ChatScreen = ({ navigation }: { navigation: ChatNavigationProp }) => { if (msg.startsWith('/') && saveHistory) { setCommandHistory(ch => ch.concat([msg])) } - connection.connection - .writePacket(0x03, concatPacketData([msg])) - .catch(errorHandler(addMessage, sendMessageErr)) + if (connection.connection.options.protocolVersion < protocolMap['1.19']) { + connection.connection + .writePacket(0x03, concatPacketData([msg])) + .catch(errorHandler(addMessage, sendMessageErr)) + } else { + const timestamp = Buffer.alloc(8) + connection.connection + .writePacket( + 0x04, + concatPacketData([msg, timestamp, writeVarInt(0), false]) + ) + .catch(errorHandler(addMessage, sendMessageErr)) + // TODO-1.19: Support sending Chat Command/Chat Message/Chat Preview. + } } if (!connection) return <> // This should never be hit hopefully.