diff --git a/HISTORY.md b/HISTORY.md index 799d0a9..9dfb2d4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,28 +1,3 @@ -## 3.49.0 -* [1.21.111 (#649)](https://github.com/PrismarineJS/bedrock-protocol/commit/b48518a6e79e72101fe7136433cbd6277339fc5c) (thanks @Slauh) -* [Skin Data Changes (#647)](https://github.com/PrismarineJS/bedrock-protocol/commit/407756b93880cdda4fdbff194fc4163ceedf4e82) (thanks @thejfkvis) - -## 3.48.1 -* [Update login client skinData (#635)](https://github.com/PrismarineJS/bedrock-protocol/commit/6b1474d2c6f93b47dee9d4816de59579f82ed5a9) (thanks @TSL534) - -## 3.48.0 -* [1.21.100 (#632)](https://github.com/PrismarineJS/bedrock-protocol/commit/06fb3de3a0023d03201dbcee7e9178c269462766) (thanks @extremeheat) - -## 3.47.0 -* [1.21.93 support (#623)](https://github.com/PrismarineJS/bedrock-protocol/commit/14daa2d95aac90ffcc7b42d625e270020ec2f162) (thanks @CreeperG16) - -## 3.46.0 -* [1.21.90 support (#617)](https://github.com/PrismarineJS/bedrock-protocol/commit/c66cdd3d62d2fa9c581693d8c70d7b41f355b63e) (thanks @CreeperG16) - -## 3.45.0 -* [1.21.80 (#602)](https://github.com/PrismarineJS/bedrock-protocol/commit/e71fd513ddbd432983f221980080b61e11576965) (thanks @extremeheat) - -## 3.44.0 -* [1.21.70 (#594)](https://github.com/PrismarineJS/bedrock-protocol/commit/065f41db8cfc8cbd8106bd9e376c899ec25f3f77) (thanks @CreeperG16) - -## 3.43.1 -* [Fix server not correctly removing clients (#588)](https://github.com/PrismarineJS/bedrock-protocol/commit/47f342ca958ba87a7719783bd5c855cebdd4aa65) (thanks @EntifiedOptics) - ## 3.43.0 * [1.21.60 support (#570)](https://github.com/PrismarineJS/bedrock-protocol/commit/eeb5e47e35f31cc571a9a8a491f5a89b27e637f1) (thanks @CreeperG16) * [Fix version feature handling (#572)](https://github.com/PrismarineJS/bedrock-protocol/commit/0ed8e32be85f05926cd97d5f0317ed004ae5eefa) (thanks @ItsMax123) diff --git a/README.md b/README.md index 5e3add2..cb2dcd4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20, 1.19.21, 1.19.30, 1.19.40, 1.19.41, 1.19.50, 1.19.60, 1.19.62, 1.19.63, 1.19.70, 1.19.80, 1.20.0, 1.20.10, 1.20.30, 1.20.40, 1.20.50, 1.20.61, 1.20.71, 1.20.80, 1.21.0, 1.21.2, 1.21.21, 1.21.30, 1.21.42, 1.21.50, 1.21.60, 1.21.70, 1.21.80, 1.21.90, 1.21.93, 1.21.100, 1.21.111 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20, 1.19.21, 1.19.30, 1.19.40, 1.19.41, 1.19.50, 1.19.60, 1.19.62, 1.19.63, 1.19.70, 1.19.80, 1.20.0, 1.20.10, 1.20.30, 1.20.40, 1.20.50, 1.20.61, 1.20.71, 1.20.80, 1.21.0, 1.21.2, 1.21.21, 1.21.30, 1.21.42, 1.21.50, 1.21.60 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/index.d.ts b/index.d.ts index 3f4a571..581e87a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,7 +3,7 @@ import { Realm } from 'prismarine-realms' import { ServerDeviceCodeResponse } from 'prismarine-auth' declare module 'bedrock-protocol' { - type Version = '1.21.93' | '1.21.90' | '1.21.80' | '1.21.70' | '1.21.60' | '1.21.50' | '1.21.42' | '1.21.30' | '1.21.2' | '1.21.0' | '1.20.80' | '1.20.71' | '1.20.61' | '1.20.50' | '1.20.40' | '1.20.30' | '1.20.10' | '1.20.0' | '1.19.80' | '1.19.70' | '1.19.63' | '1.19.62' | '1.19.60' | '1.19.51' | '1.19.50' | '1.19.41' | '1.19.40' | '1.19.31' | '1.19.30' | '1.19.22' | '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.21.60' | '1.21.50' | '1.21.42' | '1.21.30' | '1.21.2' | '1.21.0' | '1.20.80' | '1.20.71' | '1.20.61' | '1.20.50' | '1.20.40' | '1.20.30' | '1.20.10' | '1.20.0' | '1.19.80' | '1.19.70' | '1.19.63' | '1.19.62' | '1.19.60' | '1.19.51' | '1.19.50' | '1.19.41' | '1.19.40' | '1.19.31' | '1.19.30' | '1.19.22' | '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' export interface Options { // The string version to start the client or server as diff --git a/package.json b/package.json index 6301be0..b5a34cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.49.0", + "version": "3.43.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "types": "index.d.ts", diff --git a/src/client.js b/src/client.js index e3af1d0..472a777 100644 --- a/src/client.js +++ b/src/client.js @@ -62,8 +62,7 @@ class Client extends Connection { const mcData = require('minecraft-data')('bedrock_' + this.options.version) this.features = { compressorInHeader: mcData.supportFeature('compressorInPacketHeader'), - itemRegistryPacket: mcData.supportFeature('itemRegistryPacket'), - newLoginIdentityFields: mcData.supportFeature('newLoginIdentityFields') + itemRegistryPacket: mcData.supportFeature('itemRegistryPacket') } } catch (e) { throw new Error(`Unsupported version: '${this.options.version}', no data available`) @@ -147,18 +146,9 @@ class Client extends Connection { ...this.accessToken // Mojang + Xbox JWT from auth ] - let encodedChain - if (this.features.newLoginIdentityFields) { // 1.21.90+ - encodedChain = JSON.stringify({ - Certificate: JSON.stringify({ chain }), - // 0 = normal, 1 = ss, 2 = offline - AuthenticationType: this.options.offline ? 2 : 0, - Token: '' - }) - } else { - encodedChain = JSON.stringify({ chain }) - } - debug('Auth chain', encodedChain) + const encodedChain = JSON.stringify({ chain }) + + debug('Auth chain', chain) this.write('login', { protocol_version: this.options.protocolVersion, diff --git a/src/handshake/login.js b/src/handshake/login.js index 8a2830d..4523a50 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -36,6 +36,7 @@ module.exports = (client, server, options) => { client.createClientUserChain = (privateKey) => { let payload = { ...skinData, + SkinGeometryDataEngineVersion: client.versionGreaterThanOrEqualTo('1.17.30') ? '' : undefined, ClientRandomId: Date.now(), CurrentInputMode: 1, @@ -46,20 +47,19 @@ module.exports = (client, server, options) => { GameVersion: options.version || '1.16.201', GuiScale: -1, LanguageCode: 'en_GB', // TODO locale - GraphicsMode: 1, // 1:simple, 2:fancy, 3:advanced, 4:ray_traced PlatformOfflineId: '', PlatformOnlineId: '', // chat // PlayFabID is the PlayFab ID produced for the skin. PlayFab is the company that hosts the Marketplace, // skins and other related features from the game. This ID is the ID of the skin used to store the skin - // inside of PlayFab.The playfab ID is always lowercased. - PlayFabId: nextUUID().replace(/-/g, '').slice(0, 16).toLowerCase(), // 1.16.210 + // inside of PlayFab. + PlayFabId: nextUUID().replace(/-/g, '').slice(0, 16), // 1.16.210 SelfSignedId: nextUUID(), ServerAddress: `${options.host}:${options.port}`, - ThirdPartyName: client.profile.name, // Gamertag - ThirdPartyNameOnly: client.versionGreaterThanOrEqualTo('1.21.90') ? undefined : false, + ThirdPartyName: client.profile.name, + ThirdPartyNameOnly: false, UIProfile: 0, IsEditorMode: false, diff --git a/src/options.js b/src/options.js index 6e27dbe..8eb5e0b 100644 --- a/src/options.js +++ b/src/options.js @@ -3,12 +3,12 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.21.111' +const CURRENT_VERSION = '1.21.60' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) // Skip some low priority versions (middle major) on Github Actions to allow faster CI -const skippedVersionsOnGithubCI = ['1.16.210', '1.17.10', '1.17.30', '1.18.11', '1.19.10', '1.19.20', '1.19.30', '1.19.40', '1.19.50', '1.19.60', '1.19.63', '1.19.70', '1.20.10', '1.20.15', '1.20.30', '1.20.40', '1.20.50', '1.20.61', '1.20.71', '1.21.2', '1.21.20', '1.21.30', '1.21.42', '1.21.50', '1.21.60', '1.21.70', '1.21.80', '1.21.90'] +const skippedVersionsOnGithubCI = ['1.16.210', '1.17.10', '1.17.30', '1.18.11', '1.19.10', '1.19.20', '1.19.30', '1.19.40', '1.19.50', '1.19.60', '1.19.63', '1.19.70', '1.20.10', '1.20.15', '1.20.30', '1.20.40', '1.20.50', '1.20.61', '1.20.71'] const testedVersions = process.env.CI ? Object.keys(Versions).filter(v => !skippedVersionsOnGithubCI.includes(v)) : Object.keys(Versions) const defaultOptions = { diff --git a/src/server.js b/src/server.js index 0b43fd2..4dc9852 100644 --- a/src/server.js +++ b/src/server.js @@ -33,8 +33,7 @@ class Server extends EventEmitter { try { const mcData = require('minecraft-data')('bedrock_' + version) this.features = { - compressorInHeader: mcData.supportFeature('compressorInPacketHeader'), - newLoginIdentityFields: mcData.supportFeature('newLoginIdentityFields') + compressorInHeader: mcData.supportFeature('compressorInPacketHeader') } } catch (e) { throw new Error(`Unsupported version: '${version}', no data available`) @@ -90,10 +89,12 @@ class Server extends EventEmitter { this.emit('connect', player) } - onCloseConnection = (conn, reason) => { - this.conLog('Connection closed: ', conn.address, reason) - this.clients[conn.address]?.close() - delete this.clients[conn.address] + onCloseConnection = (inetAddr, reason) => { + this.conLog('Connection closed: ', inetAddr?.address, reason) + + delete this.clients[inetAddr]?.connection // Prevent close loop + this.clients[inetAddr?.address ?? inetAddr]?.close() + delete this.clients[inetAddr] this.clientCount-- } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 2e8ea77..b7ef02d 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -78,18 +78,11 @@ class Player extends Connection { // Parse login data const tokens = body.params.tokens + const authChain = JSON.parse(tokens.identity) + const skinChain = tokens.client + try { - const skinChain = tokens.client - const authChain = JSON.parse(tokens.identity) - let chain - if (authChain.Certificate) { // 1.21.90+ - chain = JSON.parse(authChain.Certificate).chain - } else if (authChain.chain) { - chain = authChain.chain - } else { - throw new Error('Invalid login packet: missing chain or Certificate') - } - var { key, userData, skinData } = this.decodeLoginJWT(chain, skinChain) // eslint-disable-line + var { key, userData, skinData } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { debug(this.address, e) this.disconnect('Server authentication error') diff --git a/test/internal.js b/test/internal.js index ffb403e..70c7b11 100644 --- a/test/internal.js +++ b/test/internal.js @@ -101,11 +101,11 @@ async function startTest (version = CURRENT_VERSION, ok) { loop = setInterval(() => { client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) - }, 6500) + }, 9500) setTimeout(() => { client.write('play_status', { status: 'player_spawn' }) - }, 3000) + }, 6000) // Respond to tick synchronization packets client.on('tick_sync', (packet) => { diff --git a/test/proxy.js b/test/proxy.js index af443d7..345e89f 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -22,12 +22,12 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 console.debug('Client has authenticated') setTimeout(() => { client.disconnect('Hello world !') - }, 500) // allow some time for client to connect + }, 1000) // allow some time for client to connect }) }) console.debug('Server started', server.options.version) - await new Promise(resolve => setTimeout(resolve, 500)) + await new Promise(resolve => setTimeout(resolve, 1000)) const relay = new Relay({ version, @@ -46,7 +46,7 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 await relay.listen() console.debug('Proxy started', server.options.version) - await new Promise(resolve => setTimeout(resolve, 500)) + await new Promise(resolve => setTimeout(resolve, 1000)) const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend, skipPing: true }) console.debug('Client started') @@ -58,7 +58,7 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 server.close() relay.close() console.log('✔ OK') - sleep(200).then(res) + sleep(500).then(res) }) }, timeout, () => { throw Error('timed out') }) } diff --git a/test/proxy.test.js b/test/proxy.test.js index 27761ae..70ea5f1 100644 --- a/test/proxy.test.js +++ b/test/proxy.test.js @@ -11,7 +11,7 @@ describe('proxies client/server', function () { it('proxies ' + version, async () => { console.debug(version) await proxyTest(version) - await sleep(100) + await sleep(1000) console.debug('Done', version) }) } diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index a7c3aa0..dcf6545 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -15,6 +15,7 @@ function createProtocol (version) { const compiler = new ProtoDefCompiler() const protocol = mcData('bedrock_' + version).protocol.types compiler.addTypes(require('../src/datatypes/compiler-minecraft')) + compiler.addTypes(require('prismarine-nbt/zigzag').compiler) compiler.addTypesToCompile(protocol) fs.writeFileSync('./read.js', 'module.exports = ' + compiler.readCompiler.generate().replace('() =>', 'native =>')) @@ -38,7 +39,7 @@ require('minecraft-data/bin/generate_data') // If no argument, build everything if (!process.argv[2]) { - convert('bedrock', 'latest') + convert('latest') for (const version of versions) { main(version) }