mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-24 03:30:12 -04:00
1.19.4 (#1226)
* Rename 'session' (packet) to chat_session_update to fix auth event conflict * impl packet "bundle" grouping, add client.writeBundle(packets) * fix handling, test * test 1.19.4 * 1.19.4 test ci * test ci against mcdata fork * lint * fix delim * fix 1.19.3 being skipped * Update ci.yml * Update package.json --------- Co-authored-by: Romain Beaumont <romain.rom1@gmail.com>
This commit is contained in:
parent
a32a1cf478
commit
2718bc64c0
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
mcVersion: ['1.7', '1.8', '1.9', '1.10', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3']
|
mcVersion: ['1.7', '1.8', '1.9', '1.10', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4']
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
tasks:
|
tasks:
|
||||||
- command: npm install
|
- command: npm install && sdk install java
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
"endian-toggle": "^0.0.0",
|
"endian-toggle": "^0.0.0",
|
||||||
"lodash.get": "^4.1.2",
|
"lodash.get": "^4.1.2",
|
||||||
"lodash.merge": "^4.3.0",
|
"lodash.merge": "^4.3.0",
|
||||||
"minecraft-data": "^3.21.0",
|
"minecraft-data": "^3.34.0",
|
||||||
"minecraft-folder-path": "^1.2.0",
|
"minecraft-folder-path": "^1.2.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"node-rsa": "^0.4.2",
|
"node-rsa": "^0.4.2",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter
|
const EventEmitter = require('events').EventEmitter
|
||||||
const debug = require('debug')('minecraft-protocol')
|
const debug = require('debug')('minecraft-protocol')
|
||||||
const compression = require('./transforms/compression')
|
const compression = require('./transforms/compression')
|
||||||
@ -30,8 +29,9 @@ class Client extends EventEmitter {
|
|||||||
this.latency = 0
|
this.latency = 0
|
||||||
this.hideErrors = hideErrors
|
this.hideErrors = hideErrors
|
||||||
this.closeTimer = null
|
this.closeTimer = null
|
||||||
|
const mcData = require('minecraft-data')(version)
|
||||||
this.state = states.HANDSHAKING
|
this.state = states.HANDSHAKING
|
||||||
|
this._hasBundlePacket = mcData.supportFeature('hasBundlePacket')
|
||||||
}
|
}
|
||||||
|
|
||||||
get state () {
|
get state () {
|
||||||
@ -77,7 +77,13 @@ class Client extends EventEmitter {
|
|||||||
if (!this.compressor) { this.splitter.pipe(this.deserializer) } else { this.decompressor.pipe(this.deserializer) }
|
if (!this.compressor) { this.splitter.pipe(this.deserializer) } else { this.decompressor.pipe(this.deserializer) }
|
||||||
this.emit('error', e)
|
this.emit('error', e)
|
||||||
})
|
})
|
||||||
|
this._mcBundle = []
|
||||||
|
const emitPacket = (parsed) => {
|
||||||
|
this.emit('packet', parsed.data, parsed.metadata, parsed.buffer, parsed.fullBuffer)
|
||||||
|
this.emit(parsed.metadata.name, parsed.data, parsed.metadata)
|
||||||
|
this.emit('raw.' + parsed.metadata.name, parsed.buffer, parsed.metadata)
|
||||||
|
this.emit('raw', parsed.buffer, parsed.metadata)
|
||||||
|
}
|
||||||
this.deserializer.on('data', (parsed) => {
|
this.deserializer.on('data', (parsed) => {
|
||||||
parsed.metadata.name = parsed.data.name
|
parsed.metadata.name = parsed.data.name
|
||||||
parsed.data = parsed.data.params
|
parsed.data = parsed.data.params
|
||||||
@ -87,10 +93,18 @@ class Client extends EventEmitter {
|
|||||||
const s = JSON.stringify(parsed.data, null, 2)
|
const s = JSON.stringify(parsed.data, null, 2)
|
||||||
debug(s && s.length > 10000 ? parsed.data : s)
|
debug(s && s.length > 10000 ? parsed.data : s)
|
||||||
}
|
}
|
||||||
this.emit('packet', parsed.data, parsed.metadata, parsed.buffer, parsed.fullBuffer)
|
if (parsed.metadata.name === 'bundle_delimiter') {
|
||||||
this.emit(parsed.metadata.name, parsed.data, parsed.metadata)
|
if (this._mcBundle.length) {
|
||||||
this.emit('raw.' + parsed.metadata.name, parsed.buffer, parsed.metadata)
|
this._mcBundle.forEach(emitPacket)
|
||||||
this.emit('raw', parsed.buffer, parsed.metadata)
|
this._mcBundle = []
|
||||||
|
} else { // Start bundle
|
||||||
|
this._mcBundle.push(parsed)
|
||||||
|
}
|
||||||
|
} else if (this._mcBundle.length) {
|
||||||
|
this._mcBundle.push(parsed)
|
||||||
|
} else {
|
||||||
|
emitPacket(parsed)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,6 +235,12 @@ class Client extends EventEmitter {
|
|||||||
this.serializer.write({ name, params })
|
this.serializer.write({ name, params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeBundle (packets) {
|
||||||
|
if (this._hasBundlePacket) this.write('bundle_delimiter', {})
|
||||||
|
for (const [name, params] of packets) this.write(name, params)
|
||||||
|
if (this._hasBundlePacket) this.write('bundle_delimiter', {})
|
||||||
|
}
|
||||||
|
|
||||||
writeRaw (buffer) {
|
writeRaw (buffer) {
|
||||||
const stream = this.compressor === null ? this.framer : this.compressor
|
const stream = this.compressor === null ? this.framer : this.compressor
|
||||||
if (!stream.writable) { return }
|
if (!stream.writable) { return }
|
||||||
|
@ -19,7 +19,7 @@ module.exports = function (client, options) {
|
|||||||
uuid: uuid.v4fast()
|
uuid: uuid.v4fast()
|
||||||
}
|
}
|
||||||
|
|
||||||
client.write('session', {
|
client.write('chat_session_update', {
|
||||||
sessionUUID: client._session.uuid,
|
sessionUUID: client._session.uuid,
|
||||||
expireTime: client.profileKeys ? BigInt(client.profileKeys.expiresOn.getTime()) : undefined,
|
expireTime: client.profileKeys ? BigInt(client.profileKeys.expiresOn.getTime()) : undefined,
|
||||||
publicKey: client.profileKeys ? client.profileKeys.public.export({ type: 'spki', format: 'der' }) : undefined,
|
publicKey: client.profileKeys ? client.profileKeys.public.export({ type: 'spki', format: 'der' }) : undefined,
|
||||||
|
@ -76,7 +76,7 @@ module.exports = function (client, server, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client.on('session', (packet) => {
|
client.on('chat_session_update', (packet) => {
|
||||||
client._session = {
|
client._session = {
|
||||||
index: 0,
|
index: 0,
|
||||||
uuid: packet.sessionUuid
|
uuid: packet.sessionUuid
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
defaultVersion: '1.19.3',
|
defaultVersion: '1.19.4',
|
||||||
supportedVersions: ['1.7', '1.8', '1.9', '1.10', '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']
|
supportedVersions: ['1.7', '1.8', '1.9', '1.10', '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']
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ const values = {
|
|||||||
}
|
}
|
||||||
Object.keys(typeArgs).forEach(function (index) {
|
Object.keys(typeArgs).forEach(function (index) {
|
||||||
const v = typeArgs[index].name === 'type' && typeArgs[index].type === 'string' && typeArgs[2] !== undefined &&
|
const v = typeArgs[index].name === 'type' && typeArgs[index].type === 'string' && typeArgs[2] !== undefined &&
|
||||||
typeArgs[2].type !== undefined
|
typeArgs[2].type !== undefined
|
||||||
? (typeArgs[2].type[1].fields['minecraft:crafting_shapeless'] === undefined ? 'crafting_shapeless' : 'minecraft:crafting_shapeless')
|
? (typeArgs[2].type[1].fields['minecraft:crafting_shapeless'] === undefined ? 'crafting_shapeless' : 'minecraft:crafting_shapeless')
|
||||||
: getValue(typeArgs[index].type, results)
|
: getValue(typeArgs[index].type, results)
|
||||||
if (typeArgs[index].anon) {
|
if (typeArgs[index].anon) {
|
||||||
@ -96,6 +96,15 @@ const values = {
|
|||||||
delete results['..']
|
delete results['..']
|
||||||
return results
|
return results
|
||||||
},
|
},
|
||||||
|
vec3f: {
|
||||||
|
x: 0, y: 0, z: 0
|
||||||
|
},
|
||||||
|
vec3f64: {
|
||||||
|
x: 0, y: 0, z: 0
|
||||||
|
},
|
||||||
|
vec4f: {
|
||||||
|
x: 0, y: 0, z: 0, w: 0
|
||||||
|
},
|
||||||
count: 1, // TODO : might want to set this to a correct value
|
count: 1, // TODO : might want to set this to a correct value
|
||||||
bool: true,
|
bool: true,
|
||||||
f64: 99999.2222,
|
f64: 99999.2222,
|
||||||
@ -266,8 +275,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
Object.keys(packets[state]).forEach(function (direction) {
|
Object.keys(packets[state]).forEach(function (direction) {
|
||||||
Object.keys(packets[state][direction].types)
|
Object.keys(packets[state][direction].types)
|
||||||
.filter(function (packetName) {
|
.filter(function (packetName) {
|
||||||
return packetName !== 'packet' &&
|
return packetName !== 'packet' && packetName.startsWith('packet_')
|
||||||
packetName.startsWith('packet_')
|
|
||||||
})
|
})
|
||||||
.forEach(function (packetName) {
|
.forEach(function (packetName) {
|
||||||
packetInfo = packets[state][direction].types[packetName]
|
packetInfo = packets[state][direction].types[packetName]
|
||||||
|
@ -62,23 +62,23 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
// removed `dimension`
|
// removed `dimension`
|
||||||
// removed `dimensionCodec`
|
// removed `dimensionCodec`
|
||||||
registryCodec: {
|
registryCodec: {
|
||||||
"type": "compound",
|
type: 'compound',
|
||||||
"name": "",
|
name: '',
|
||||||
"value": {}
|
value: {}
|
||||||
},
|
},
|
||||||
worldType: "minecraft:overworld",
|
worldType: 'minecraft:overworld',
|
||||||
death: undefined
|
death: undefined
|
||||||
// more to be added
|
// more to be added
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendBroadcastMessage(server, clients, message, sender) {
|
function sendBroadcastMessage (server, clients, message, sender) {
|
||||||
if (mcData.supportFeature('signedChat')) {
|
if (mcData.supportFeature('signedChat')) {
|
||||||
server.writeToClients(clients, 'player_chat', {
|
server.writeToClients(clients, 'player_chat', {
|
||||||
plainMessage: message,
|
plainMessage: message,
|
||||||
signedChatContent: '',
|
signedChatContent: '',
|
||||||
unsignedChatContent: JSON.stringify({ text: message }),
|
unsignedChatContent: JSON.stringify({ text: message }),
|
||||||
type: 0,
|
type: 0,
|
||||||
senderUuid: 'd3527a0b-bc03-45d5-a878-2aafdd8c8a43', // random
|
senderUuid: 'd3527a0b-bc03-45d5-a878-2aafdd8c8a43', // random
|
||||||
senderName: JSON.stringify({ text: sender }),
|
senderName: JSON.stringify({ text: sender }),
|
||||||
senderTeam: undefined,
|
senderTeam: undefined,
|
||||||
@ -96,7 +96,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
|
|
||||||
describe('mc-server ' + version.minecraftVersion, function () {
|
describe('mc-server ' + version.minecraftVersion, function () {
|
||||||
this.timeout(5000)
|
this.timeout(5000)
|
||||||
this.beforeAll(async function() {
|
this.beforeAll(async function () {
|
||||||
PORT = await getPort()
|
PORT = await getPort()
|
||||||
console.log(`Using port for tests: ${PORT}`)
|
console.log(`Using port for tests: ${PORT}`)
|
||||||
})
|
})
|
||||||
@ -214,7 +214,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
sample: []
|
sample: []
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
extra: [ { color: 'red', text: 'Red text' } ],
|
extra: [{ color: 'red', text: 'Red text' }],
|
||||||
bold: true,
|
bold: true,
|
||||||
text: 'Example chat mesasge'
|
text: 'Example chat mesasge'
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
version: version.minecraftVersion,
|
version: version.minecraftVersion,
|
||||||
port: PORT
|
port: PORT
|
||||||
})
|
})
|
||||||
client.on('packet', (data, {name})=>{
|
client.on('packet', (data, { name }) => {
|
||||||
if (name === 'success') {
|
if (name === 'success') {
|
||||||
assert.strictEqual(data.uuid, notchUUID, 'UUID')
|
assert.strictEqual(data.uuid, notchUUID, 'UUID')
|
||||||
server.close()
|
server.close()
|
||||||
@ -333,7 +333,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const p1Join = await player1.nextMessage('player2')
|
const p1Join = await player1.nextMessage('player2')
|
||||||
|
|
||||||
assert.strictEqual(p1Join, '{"text":"player2 joined the game."}')
|
assert.strictEqual(p1Join, '{"text":"player2 joined the game."}')
|
||||||
|
|
||||||
player2.chat('hi')
|
player2.chat('hi')
|
||||||
@ -441,7 +441,7 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
|
|
||||||
sendBroadcastMessage(server, Object.values(server.clients), 'A message from the server.')
|
sendBroadcastMessage(server, Object.values(server.clients), 'A message from the server.')
|
||||||
|
|
||||||
let results = await Promise.all([player1.nextMessage(), player2.nextMessage()])
|
const results = await Promise.all([player1.nextMessage(), player2.nextMessage()])
|
||||||
for (const msg of results) {
|
for (const msg of results) {
|
||||||
assert.strictEqual(msg, '{"text":"A message from the server."}')
|
assert.strictEqual(msg, '{"text":"A message from the server."}')
|
||||||
}
|
}
|
||||||
@ -452,5 +452,43 @@ for (const supportedVersion of mc.supportedVersions) {
|
|||||||
server.close()
|
server.close()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('supports bundle packet', function (done) {
|
||||||
|
const server = mc.createServer({
|
||||||
|
'online-mode': false,
|
||||||
|
version: version.minecraftVersion,
|
||||||
|
port: PORT
|
||||||
|
})
|
||||||
|
server.on('login', function (client) {
|
||||||
|
client.on('end', function (reason) {
|
||||||
|
assert.strictEqual(reason, 'ServerShutdown')
|
||||||
|
})
|
||||||
|
client.write('login', loginPacket(client, server))
|
||||||
|
client.writeBundle([
|
||||||
|
['update_time', { age: 1, time: 2 }],
|
||||||
|
['close_window', { windowId: 0 }]
|
||||||
|
])
|
||||||
|
})
|
||||||
|
server.on('close', done)
|
||||||
|
server.on('listening', function () {
|
||||||
|
const client = mc.createClient({
|
||||||
|
username: 'lalalal',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
version: version.minecraftVersion,
|
||||||
|
port: PORT
|
||||||
|
})
|
||||||
|
client.on('update_time', function () {
|
||||||
|
// Below handler synchronously defined should be guaranteed to be called after the above one
|
||||||
|
const d1 = Date.now()
|
||||||
|
client.on('close_window', function () {
|
||||||
|
server.close()
|
||||||
|
const d2 = Date.now()
|
||||||
|
if (mcData.supportFeature('hasBundlePacket') && (d2 - d1) > 1) {
|
||||||
|
throw new Error(`bundle packet constituents did not arrive at once : ${d1}, ${d2}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user