Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@ jobs:
distribution: 'adopt'
- name: Install dependencies
run: npm install
- run: cd node_modules && cd minecraft-data && mv minecraft-data minecraft-data-old && git clone -b pc_26_1 https://github.com/PrismarineJS/minecraft-data --depth 1 && node bin/generate_data.js
- run: curl -o node_modules/protodef/src/serializer.js https://raw.githubusercontent.com/extremeheat/node-protodef/refs/heads/dlog/src/serializer.js && curl -o node_modules/protodef/src/compiler.js https://raw.githubusercontent.com/extremeheat/node-protodef/refs/heads/dlog/src/compiler.js

- name: Run tests
run: npm run mochaTest -- -g ${{ matrix.mcVersion }}v
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Parse and serialize minecraft packets, plus authentication and encryption.
1.15 (1.15, 1.15.1, 1.15.2), 1.16 (20w13b, 20w14a, 1.16-rc1, 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5),
1.17 (21w07a, 1.17, 1.17.1), 1.18 (1.18, 1.18.1 and 1.18.2),
1.19 (1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4), 1.20 (1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6),
1.21, 1.21.1, 1.21.3, 1.21.4, 1.21.5, 1.21.6, 1.21.8, 1.21.9, 1.21.11
1.21, 1.21.1, 1.21.3, 1.21.4, 1.21.5, 1.21.6, 1.21.8, 1.21.9, 1.21.11, 26.1
<!--add_next_version_above-->

* Parses all packets and emits events with packet fields as JavaScript
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@
"debug": "^4.3.2",
"endian-toggle": "^0.0.0",
"lodash.merge": "^4.3.0",
"minecraft-data": "^3.78.0",
"minecraft-data": "^3.109.0",
"minecraft-folder-path": "^1.2.0",
"node-fetch": "^2.6.1",
"node-rsa": "^0.4.2",
"prismarine-auth": "^2.2.0",
"prismarine-auth": "^3.1.1",
"prismarine-chat": "^1.10.0",
"prismarine-nbt": "^2.5.0",
"prismarine-realms": "^1.2.0",
Expand Down
32 changes: 21 additions & 11 deletions src/client/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,20 +302,30 @@ module.exports = function (client, options) {

const sliceIndexForMessage = {}
client.on('declare_commands', (packet) => {
// Defensive guard: command data comes from the network and may be malformed or partially decoded.
if (!Array.isArray(packet?.nodes) || !Array.isArray(packet.nodes[0]?.children)) {
return
}

const nodes = packet.nodes
function visit (node, commandName, depth = 0) {
if (!node || !node.extraNodeData) return

const { name, parser } = node.extraNodeData
if (parser === 'minecraft:message') {
sliceIndexForMessage[commandName] = [name, depth]
}

for (const childIndex of node.children || []) {
visit(nodes[childIndex], commandName, depth + 1)
}
}

for (const commandNode of nodes[0].children) {
const node = nodes[commandNode]
const commandName = node.extraNodeData.name
function visit (node, depth = 0) {
const name = node.extraNodeData.name
if (node.extraNodeData.parser === 'minecraft:message') {
sliceIndexForMessage[commandName] = [name, depth]
}
for (const child of node.children) {
visit(nodes[child], depth + 1)
}
}
visit(node, 0)
const commandName = node?.extraNodeData?.name
if (!commandName) continue
visit(node, commandName, 0)
}
})

Expand Down
4 changes: 2 additions & 2 deletions src/version.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

module.exports = {
defaultVersion: '1.21.11',
supportedVersions: ['1.7', '1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4', '1.20', '1.20.1', '1.20.2', '1.20.4', '1.20.6', '1.21.1', '1.21.3', '1.21.4', '1.21.5', '1.21.6', '1.21.8', '1.21.9', '1.21.11']
defaultVersion: '26.1',
supportedVersions: ['1.7', '1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4', '1.20', '1.20.1', '1.20.2', '1.20.4', '1.20.6', '1.21.1', '1.21.3', '1.21.4', '1.21.5', '1.21.6', '1.21.8', '1.21.9', '1.21.11', '26.1']
}
58 changes: 58 additions & 0 deletions test/declareCommandsTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* eslint-env mocha */

const assert = require('assert')
const EventEmitter = require('events')
const minecraftDataPath = require.resolve('minecraft-data')
const injectChatPlugin = require('../src/client/chat')

describe('declare_commands handling', () => {
let originalMinecraftData

beforeEach(() => {
originalMinecraftData = require.cache[minecraftDataPath]?.exports
require.cache[minecraftDataPath] = {
exports: () => ({
supportFeature (feature) {
return feature === 'useChatSessions' || feature === 'seperateSignedChatCommandPacket'
}
})
}
})

afterEach(() => {
if (originalMinecraftData) {
require.cache[minecraftDataPath] = { exports: originalMinecraftData }
} else {
delete require.cache[minecraftDataPath]
}
})

it('tracks message arguments from structured declare_commands nodes', () => {
const client = new EventEmitter()
client.version = '26.1'
client.verifyMessage = () => true
client.profileKeys = true
client._session = { uuid: '00000000-0000-0000-0000-000000000000' }

const writes = []
client.write = (name, data) => writes.push({ name, data })

injectChatPlugin(client, {})
client.signMessage = () => Buffer.from([1])

client.emit('declare_commands', {
nodes: [
{ children: [1] },
{ children: [2], extraNodeData: { name: 'msg' } },
{ children: [], extraNodeData: { name: 'message', parser: 'minecraft:message' } }
]
})

client._signedChat('/msg hello there', { timestamp: 1n, salt: 1n })

assert.strictEqual(writes.length, 1)
assert.strictEqual(writes[0].name, 'chat_command_signed')
assert.deepStrictEqual(writes[0].data.argumentSignatures.map(sig => sig.argumentName), ['message'])
})

})
Loading