Skip to content

Commit 2467716

Browse files
extremeheatrom1504
andauthored
1.21.5 (#1408)
* 1.21.5 * Update client.js debug logging * Update packetTest.js slots * Update ci.yml --------- Co-authored-by: Romain Beaumont <romain.rom1@gmail.com>
1 parent 3918d74 commit 2467716

File tree

12 files changed

+82
-18
lines changed

12 files changed

+82
-18
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ test/npm-debug.log
33
test/server_*
44
package-lock.json
55
versions/
6-
src/client/*.json
6+
src/client/*.json
7+
test_*

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Parse and serialize minecraft packets, plus authentication and encryption.
1313

1414
* Supports Minecraft PC version 1.7.10, 1.8.8, 1.9 (15w40b, 1.9, 1.9.1-pre2, 1.9.2, 1.9.4),
1515
1.10 (16w20a, 1.10-pre1, 1.10, 1.10.1, 1.10.2), 1.11 (16w35a, 1.11, 1.11.2), 1.12 (17w15a, 17w18b, 1.12-pre4, 1.12, 1.12.1, 1.12.2), and 1.13 (17w50a, 1.13, 1.13.1, 1.13.2-pre1, 1.13.2-pre2, 1.13.2), 1.14 (1.14, 1.14.1, 1.14.3, 1.14.4)
16-
, 1.15 (1.15, 1.15.1, 1.15.2) and 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.21.1, 1.21.3, 1.21.4)
16+
, 1.15 (1.15, 1.15.1, 1.15.2) and 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.21.1, 1.21.3, 1.21.4, 1.21.5)
1717
* Parses all packets and emits events with packet fields as JavaScript
1818
objects.
1919
* Send a packet by supplying fields as a JavaScript object.

examples/server/server.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const options = {
1111
const server = mc.createServer(options)
1212
const mcData = require('minecraft-data')(server.version)
1313
const loginPacket = mcData.loginPacket
14+
15+
// Global chat index counter for 1.21.5+
16+
let nextChatIndex = 1
17+
1418
function chatText (text) {
1519
return mcData.supportFeature('chatPacketsUseNbtComponents')
1620
? nbt.comp({ text: nbt.string(text) })
@@ -72,6 +76,7 @@ server.on('listening', function () {
7276
function sendBroadcastMessage (server, clients, message, sender) {
7377
if (mcData.supportFeature('signedChat')) {
7478
server.writeToClients(clients, 'player_chat', {
79+
globalIndex: nextChatIndex++,
7580
plainMessage: message,
7681
signedChatContent: '',
7782
unsignedChatContent: chatText(message),

examples/server_helloworld/server_helloworld.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const mcData = require('minecraft-data')(server.version)
1010
const loginPacket = mcData.loginPacket
1111
const nbt = require('prismarine-nbt')
1212

13+
// Global chat index counter for 1.21.5+
14+
let nextChatIndex = 1
15+
1316
function chatText (text) {
1417
return mcData.supportFeature('chatPacketsUseNbtComponents')
1518
? nbt.comp({ text: nbt.string(text) })
@@ -65,6 +68,7 @@ server.on('playerJoin', function (client) {
6568
}
6669
if (mcData.supportFeature('signedChat')) {
6770
client.write('player_chat', {
71+
globalIndex: nextChatIndex++,
6872
plainMessage: message,
6973
signedChatContent: '',
7074
unsignedChatContent: chatText(message),

src/client.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use strict'
22
const EventEmitter = require('events').EventEmitter
3-
const debug = require('debug')('minecraft-protocol')
43
const compression = require('./transforms/compression')
54
const framing = require('./transforms/framing')
65
const states = require('./states')
6+
const debug = require('debug')('minecraft-protocol')
7+
const debugSkip = process.env.DEBUG_SKIP?.split(',') ?? []
78

89
const createSerializer = require('./transforms/serializer').createSerializer
910
const createDeserializer = require('./transforms/serializer').createDeserializer
@@ -89,8 +90,8 @@ class Client extends EventEmitter {
8990
parsed.metadata.name = parsed.data.name
9091
parsed.data = parsed.data.params
9192
parsed.metadata.state = state
92-
debug('read packet ' + state + '.' + parsed.metadata.name)
93-
if (debug.enabled) {
93+
if (debug.enabled && !debugSkip.includes(parsed.metadata.name)) {
94+
debug('read packet ' + state + '.' + parsed.metadata.name)
9495
const s = JSON.stringify(parsed.data, null, 2)
9596
debug(s && s.length > 10000 ? parsed.data : s)
9697
}
@@ -238,8 +239,10 @@ class Client extends EventEmitter {
238239

239240
write (name, params) {
240241
if (!this.serializer.writable) { return }
241-
debug('writing packet ' + this.state + '.' + name)
242-
debug(params)
242+
if (debug.enabled && !debugSkip.includes(name)) {
243+
debug('writing packet ' + this.state + '.' + name)
244+
debug(params)
245+
}
243246
this.serializer.write({ name, params })
244247
}
245248

src/client/chat.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const crypto = require('crypto')
2+
const { computeChatChecksum } = require('../datatypes/checksums')
23
const concat = require('../transforms/binaryStream').concat
34
const { processNbtMessage } = require('prismarine-chat')
45
const messageExpireTime = 420000 // 7 minutes (ms)
@@ -192,6 +193,7 @@ module.exports = function (client, options) {
192193
const verified = !packet.unsignedChatContent && updateAndValidateSession(packet.senderUuid, packet.plainMessage, packet.signature, packet.index, packet.previousMessages, packet.salt, packet.timestamp) && !expired
193194
if (verified) client._signatureCache.push(packet.signature)
194195
client.emit('playerChat', {
196+
globalIndex: packet.globalIndex,
195197
plainMessage: packet.plainMessage,
196198
unsignedContent: processMessage(packet.unsignedChatContent),
197199
type: packet.type,
@@ -363,14 +365,16 @@ module.exports = function (client, options) {
363365
if (mcData.supportFeature('useChatSessions')) { // 1.19.3+
364366
const { acknowledged, acknowledgements } = getAcknowledgements()
365367
const canSign = client.profileKeys && client._session
366-
client.write((mcData.supportFeature('seperateSignedChatCommandPacket') && canSign) ? 'chat_command_signed' : 'chat_command', {
368+
const chatPacket = {
367369
command,
368370
timestamp: options.timestamp,
369371
salt: options.salt,
370372
argumentSignatures: canSign ? signaturesForCommand(command, options.timestamp, options.salt, options.preview, acknowledgements) : [],
371373
messageCount: client._lastSeenMessages.pending,
374+
checksum: computeChatChecksum(client._lastSeenMessages), // 1.21.5+
372375
acknowledged
373-
})
376+
}
377+
client.write((mcData.supportFeature('seperateSignedChatCommandPacket') && canSign) ? 'chat_command_signed' : 'chat_command', chatPacket)
374378
client._lastSeenMessages.pending = 0
375379
} else {
376380
client.write('chat_command', {
@@ -383,6 +387,7 @@ module.exports = function (client, options) {
383387
messageSender: e.sender,
384388
messageSignature: e.signature
385389
})),
390+
checksum: computeChatChecksum(client._lastSeenMessages),
386391
lastRejectedMessage: client._lastRejectedMessage
387392
})
388393
}
@@ -398,6 +403,7 @@ module.exports = function (client, options) {
398403
salt: options.salt,
399404
signature: (client.profileKeys && client._session) ? client.signMessage(message, options.timestamp, options.salt, undefined, acknowledgements) : undefined,
400405
offset: client._lastSeenMessages.pending,
406+
checksum: computeChatChecksum(client._lastSeenMessages), // 1.21.5+
401407
acknowledged
402408
})
403409
client._lastSeenMessages.pending = 0
@@ -416,7 +422,8 @@ module.exports = function (client, options) {
416422
messageSender: e.sender,
417423
messageSignature: e.signature
418424
})),
419-
lastRejectedMessage: client._lastRejectedMessage
425+
lastRejectedMessage: client._lastRejectedMessage,
426+
checksum: computeChatChecksum(client._lastSeenMessages) // 1.21.5+
420427
})
421428
client._lastSeenMessages.pending = 0
422429
} else if (client.serverFeatures.chatPreview) {

src/datatypes/checksums.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Compute chat checksum using Java's Arrays.hashCode algorithm to match vanilla client
2+
function computeChatChecksum (lastSeenMessages) {
3+
if (!lastSeenMessages || lastSeenMessages.length === 0) return 1
4+
5+
let checksum = 1
6+
for (const message of lastSeenMessages) {
7+
if (message.signature) {
8+
let sigHash = 1
9+
for (let i = 0; i < message.signature.length; i++) {
10+
sigHash = (31 * sigHash + message.signature[i]) & 0xffffffff
11+
}
12+
checksum = (31 * checksum + sigHash) & 0xffffffff
13+
}
14+
}
15+
// Convert to byte
16+
const result = checksum & 0xff
17+
return result === 0 ? 1 : result
18+
}
19+
20+
module.exports = { computeChatChecksum }

src/server/chat.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const crypto = require('crypto')
2+
const { computeChatChecksum } = require('../datatypes/checksums')
23
const concat = require('../transforms/binaryStream').concat
34
const debug = require('debug')('minecraft-protocol')
45
const messageExpireTime = 300000 // 5 min (ms)
@@ -104,6 +105,14 @@ module.exports = function (client, server, options) {
104105
}
105106
lastTimestamp = packet.timestamp
106107

108+
// Validate checksum for 1.21.5+
109+
if (client.supportFeature('chatGlobalIndexAndChecksum') && options.enforceChatChecksum && packet.checksum !== undefined) {
110+
const expectedChecksum = computeChatChecksum(client._lastSeenMessages || [])
111+
if (packet.checksum !== 0 && packet.checksum !== expectedChecksum) {
112+
return raise('multiplayer.disconnect.chat_validation_failed')
113+
}
114+
}
115+
107116
// Checks here: 1) make sure client can chat, 2) chain/session is OK, 3) signature is OK, 4) log if expired
108117
if (client.settings.disabledChat) return raise('chat.disabled.options')
109118
if (client.supportFeature('chainedChatWithHashing')) validateMessageChain(packet) // 1.19.1

src/version.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

33
module.exports = {
4-
defaultVersion: '1.21.1',
5-
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']
4+
defaultVersion: '1.21.5',
5+
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']
66
}

test/clientTest.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ for (const supportedVersion of mc.supportedVersions) {
100100
})
101101
})
102102

103+
// chat/Style.java
104+
const CLICK_EVENT = mcData.version['>=']('1.21.5') ? 'click_event' : 'clickEvent'
103105
it('connects successfully - offline mode', function (done) {
104106
const client = applyClientHelpers(mc.createClient({
105107
username: 'Player',
@@ -198,10 +200,9 @@ for (const supportedVersion of mc.supportedVersions) {
198200

199201
if (chatCount === 1) {
200202
assert.strictEqual(plainMessage, 'hello everyone; I have logged in.')
201-
assert.deepEqual(sender.clickEvent, {
202-
action: 'suggest_command',
203-
value: '/tell Player '
204-
})
203+
const clickEvent = sender[CLICK_EVENT]
204+
assert.strictEqual(clickEvent.action, 'suggest_command')
205+
assert.ok(['/tell Player ', '/msg Player '].includes(clickEvent.value || clickEvent.command))
205206
assert.strictEqual(sender.text, 'Player')
206207
} else if (chatCount === 2) {
207208
const plainSender = client.parseMessage(sender).toString()
@@ -222,7 +223,7 @@ for (const supportedVersion of mc.supportedVersions) {
222223
const message = JSON.parse(data.formattedMessage)
223224
if (chatCount === 1) {
224225
assert.strictEqual(message.translate, 'chat.type.text')
225-
assert.deepEqual(message.with[0].clickEvent, {
226+
assert.deepEqual(message.with[0][CLICK_EVENT], {
226227
action: 'suggest_command',
227228
value: mcData.version.version > 340 ? '/tell Player ' : '/msg Player '
228229
})

0 commit comments

Comments
 (0)