diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19d6257..74edbe9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,5 +26,11 @@ jobs: with: java-version: 17 java-package: jre + # Old versions of bedrock use old libssl that Ubuntu no longer ships with; need manual install + - name: (Linux) Install libssl 1.1 + if: runner.os == 'Linux' + run: | + wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb + sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb - run: npm install - run: npm test \ No newline at end of file diff --git a/lib/bedrock/index.js b/lib/bedrock/index.js index 8cb3970..4e40ff5 100644 --- a/lib/bedrock/index.js +++ b/lib/bedrock/index.js @@ -29,7 +29,10 @@ module.exports = (data) => { return { handleStartGame (packet) { - loadItemStates(packet.itemstates) + if (packet.itemstates != null) { + loadItemStates(packet.itemstates) + } + if (this.supportFeature('blockHashes') && packet.block_network_ids_are_hashes) { loadHashedRuntimeIds(this) } else { diff --git a/test/mcbedrock.js b/test/mcbedrock.js index c90805d..aaef086 100644 --- a/test/mcbedrock.js +++ b/test/mcbedrock.js @@ -10,21 +10,22 @@ async function main (version = '1.19.63') { console.log('Loading item palette and custom blocks') registry.handleStartGame(params) - console.log('Loaded item palette', registry.items) + if (params.itemstates != null) { + console.log('Loaded item palette') - const reEncoded = registry.writeItemStates() - assert.deepEqual( - reEncoded.sort((a, b) => a.runtime_id - b.runtime_id), - params.itemstates.sort((a, b) => a.runtime_id - b.runtime_id) - ) - console.log('Re-encoded item palette') + const reEncoded = registry.writeItemStates() + assert.deepEqual( + reEncoded.sort((a, b) => a.runtime_id - b.runtime_id), + params.itemstates.sort((a, b) => a.runtime_id - b.runtime_id) + ) + console.log('Re-encoded item palette') + } loggedIn = true } } await collectPackets(version, Object.keys(handlers), (name, params) => handlers[name](version, params)) - await new Promise((resolve) => setTimeout(resolve, 30000)) if (!loggedIn) { throw new Error('Did not login') } diff --git a/test/mcbedrock.test.js b/test/mcbedrock.test.js index f565970..d8edad2 100644 --- a/test/mcbedrock.test.js +++ b/test/mcbedrock.test.js @@ -1,13 +1,17 @@ /* eslint-env mocha */ -const SUPPORTED_VERSIONS = ['1.17.10', '1.18.0', '1.18.11', '1.18.30', '1.19.1', '1.19.10'] +const SUPPORTED_VERSIONS = ['1.17.10', '1.18.0', '1.18.11', '1.18.30', '1.19.1', '1.19.10', '1.21.70'] const test = require('./mcbedrock') +const { sleep } = require('./util/sleep') describe('mcbedrock', function () { - this.timeout(18000 * 10) + const vcount = SUPPORTED_VERSIONS.length + this.timeout(vcount * 80 * 1000) for (const version of SUPPORTED_VERSIONS) { - // skipped bedrock because it times out; fix in https://github.com/PrismarineJS/prismarine-registry/issues/43 - it.skip('works on ' + version, () => test(version)) + it('works on ' + version, async () => { + await test(version) + await sleep(100) + }) } }) diff --git a/test/util/collectBedrockPackets.js b/test/util/collectBedrockPackets.js index 9b8b3e4..6c7bd81 100644 --- a/test/util/collectBedrockPackets.js +++ b/test/util/collectBedrockPackets.js @@ -1,52 +1,77 @@ const bedrock = require('bedrock-protocol') -const { startServer } = require('minecraft-bedrock-server') +const { startServerAndWait2 } = require('minecraft-bedrock-server') const debug = require('debug')('prismarine-registry') const path = require('path') +const { getPort } = require('./getPort') +const { waitFor } = require('./waitFor') +const { sleep } = require('./sleep') async function collectPackets (version, names = ['start_game'], cb) { - const collected = [] - const server = await new Promise((resolve) => { - const server = startServer(version, () => resolve(server), { - 'online-mode': false, - 'server-port': 19130, - path: path.join(__dirname, `server_bedrock_${version}`) - }) + const [port, v6] = [await getPort(), await getPort()] + console.log('Starting vanilla server', version, 'on port', port, v6) + const server = await startServerAndWait2(version, 1000 * 220, { + 'online-mode': false, + 'server-port': port, + 'server-portv6': v6, + path: path.join(__dirname, `server_bedrock_${version}`) }) + console.log('Started server') - console.log('Started server', version) + await sleep(200) const client = bedrock.createClient({ - version, host: '127.0.0.1', - port: 19130, + port, username: 'test', - offline: true + version, + raknetBackend: 'raknet-native', + offline: true, + skipPing: true }) + console.log('Started client. Connecting to server') + let clientConnected = false + const collected = [] + await waitFor((resolve) => { + client.on('join', () => { + console.log('[client] Client connected') + clientConnected = true + stopIfDone() + }) - client.on('join', () => { - console.log('[client] Client connected') - clientConnected = true - }) + client.on('packet', ({ name }) => debug('[client] -> ', name)) - for (const name of names) { - client.on(name, (packet) => { - cb(name, packet) - collected.push(packet) + client.on('error', (err) => { + console.error('[client]', err) + resolve('timeout') }) - } + client.on('end', () => console.log('Bot disconnected.')) - client.on('packet', ({ name }) => debug('[client] -> ', name)) + for (const name of names) { + client.on(name, (packet) => { + cb(name, packet) + collected.push(packet) + stopIfDone() + }) + } - setTimeout(() => { - console.log('Stopping server', version) - server.kill() - client.close() - if (!clientConnected) { - throw new Error('Client never connected') + function stopIfDone () { + if (clientConnected && collected.length === names.length) { + console.log('✔ Got all packets') + console.log('Stopping server', version) + server.kill() + client.close() + resolve() + } } - }, 9000) + }, 1000 * 60, () => { + client.close() + server.kill() + throw Error('❌ client timed out ') + }) + + console.log('Stopping server', version) } module.exports = collectPackets diff --git a/test/util/getPort.js b/test/util/getPort.js new file mode 100644 index 0000000..9d308b2 --- /dev/null +++ b/test/util/getPort.js @@ -0,0 +1,17 @@ +const net = require('net') + +const getPort = () => new Promise(resolve => { + const server = net.createServer() + server.listen(0, '127.0.0.1') + server.on('listening', () => { + const { port } = server.address() + server.close(() => { + // Wait a bit for port to free as we try to bind right after freeing it + setTimeout(() => { + resolve(port) + }, 200) + }) + }) +}) + +module.exports = { getPort } diff --git a/test/util/sleep.js b/test/util/sleep.js new file mode 100644 index 0000000..f21f538 --- /dev/null +++ b/test/util/sleep.js @@ -0,0 +1,5 @@ +function sleep (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +module.exports = { sleep } diff --git a/test/util/waitFor.js b/test/util/waitFor.js new file mode 100644 index 0000000..2062f6a --- /dev/null +++ b/test/util/waitFor.js @@ -0,0 +1,12 @@ +async function waitFor (cb, withTimeout, onTimeout) { + let t + const ret = await Promise.race([ + new Promise((resolve, reject) => cb(resolve, reject)), + new Promise(resolve => { t = setTimeout(() => resolve('timeout'), withTimeout) }) + ]) + clearTimeout(t) + if (ret === 'timeout') await onTimeout() + return ret +} + +module.exports = { waitFor }