mirror of
https://github.com/PrismarineJS/node-minecraft-protocol.git
synced 2024-12-18 11:32:35 -05:00
support 1.21.3 (#1347)
* support 1.21.3 * Add bitflags, registryEntryHolder and registryEntryHolderSet types * Fix spacing in compiler types * Update compiler-minecraft.js * Fix registryEntryHolderSet read code (#1351) * Update ci.yml * Fix test for 1.21.3 (#1353) * Remove debug logging * Fix benchmark tests for 1.21.3 * Start updating packetTest for 1.21.3 * Update packetTest.js with new types * Fix minecraft-compiler * Speedup tests by setting world type to flat and disabling structures. * Didn't mean to commit that --------- Co-authored-by: extremeheat <extreme@protonmail.ch> Co-authored-by: Grooble <grooble.dierne@gmail.com>
This commit is contained in:
parent
590dc33fed
commit
2224d82406
6 changed files with 247 additions and 15 deletions
|
@ -13,7 +13,7 @@ Parse and serialize minecraft packets, plus authentication and encryption.
|
||||||
|
|
||||||
* 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),
|
* 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),
|
||||||
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)
|
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)
|
||||||
, 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, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21.1)
|
, 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)
|
||||||
* Parses all packets and emits events with packet fields as JavaScript
|
* Parses all packets and emits events with packet fields as JavaScript
|
||||||
objects.
|
objects.
|
||||||
* Send a packet by supplying fields as a JavaScript object.
|
* Send a packet by supplying fields as a JavaScript object.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-return-assign */
|
||||||
const UUID = require('uuid-1345')
|
const UUID = require('uuid-1345')
|
||||||
const minecraft = require('./minecraft')
|
const minecraft = require('./minecraft')
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ module.exports = {
|
||||||
code += '}'
|
code += '}'
|
||||||
return compiler.wrapCode(code)
|
return compiler.wrapCode(code)
|
||||||
}],
|
}],
|
||||||
arrayWithLengthOffset: ['parametrizable', (compiler, array) => {
|
arrayWithLengthOffset: ['parametrizable', (compiler, array) => { // TODO: remove
|
||||||
let code = ''
|
let code = ''
|
||||||
if (array.countType) {
|
if (array.countType) {
|
||||||
code += 'const { value: count, size: countSize } = ' + compiler.callType(array.countType) + '\n'
|
code += 'const { value: count, size: countSize } = ' + compiler.callType(array.countType) + '\n'
|
||||||
|
@ -61,6 +62,56 @@ module.exports = {
|
||||||
code += '}\n'
|
code += '}\n'
|
||||||
code += 'return { value: data, size }'
|
code += 'return { value: data, size }'
|
||||||
return compiler.wrapCode(code)
|
return compiler.wrapCode(code)
|
||||||
|
}],
|
||||||
|
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
||||||
|
let fstr = JSON.stringify(flags)
|
||||||
|
if (Array.isArray(flags)) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
|
||||||
|
fstr += '}'
|
||||||
|
} else if (shift) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
|
||||||
|
fstr += '}'
|
||||||
|
}
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
const { value: _value, size } = ${compiler.callType(type, 'offset')}
|
||||||
|
const value = { _value }
|
||||||
|
const flags = ${fstr}
|
||||||
|
for (const key in flags) {
|
||||||
|
value[key] = (_value & flags[key]) == flags[key]
|
||||||
|
}
|
||||||
|
return { value, size }
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolder: ['parametrizable', (compiler, opts) => {
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
const { value: n, size: nSize } = ${compiler.callType('varint')}
|
||||||
|
if (n !== 0) {
|
||||||
|
return { value: { ${opts.baseName}: n - 1 }, size: nSize }
|
||||||
|
} else {
|
||||||
|
const holder = ${compiler.callType(opts.otherwise.type)}
|
||||||
|
return { value: { ${opts.otherwise.name}: holder.data }, size: nSize + holder.size }
|
||||||
|
}
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolderSet: ['parametrizable', (compiler, opts) => {
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
const { value: n, size: nSize } = ${compiler.callType('varint')}
|
||||||
|
if (n === 0) {
|
||||||
|
const base = ${compiler.callType(opts.base.type, 'offset + nSize')}
|
||||||
|
return { value: { ${opts.base.name}: base.value }, size: base.size + nSize }
|
||||||
|
} else {
|
||||||
|
const set = []
|
||||||
|
let accSize = nSize
|
||||||
|
for (let i = 0; i < n - 1; i++) {
|
||||||
|
const entry = ${compiler.callType(opts.otherwise.type, 'offset + accSize')}
|
||||||
|
set.push(entry.value)
|
||||||
|
accSize += entry.size
|
||||||
|
}
|
||||||
|
return { value: { ${opts.otherwise.name}: set }, size: accSize }
|
||||||
|
}
|
||||||
|
`.trim())
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
Write: {
|
Write: {
|
||||||
|
@ -106,6 +157,58 @@ module.exports = {
|
||||||
code += '}\n'
|
code += '}\n'
|
||||||
code += 'return offset'
|
code += 'return offset'
|
||||||
return compiler.wrapCode(code)
|
return compiler.wrapCode(code)
|
||||||
|
}],
|
||||||
|
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
||||||
|
let fstr = JSON.stringify(flags)
|
||||||
|
if (Array.isArray(flags)) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
|
||||||
|
fstr += '}'
|
||||||
|
} else if (shift) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
|
||||||
|
fstr += '}'
|
||||||
|
}
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
const flags = ${fstr}
|
||||||
|
let val = value._value ${big ? '|| 0n' : ''}
|
||||||
|
for (const key in flags) {
|
||||||
|
if (value[key]) val |= flags[key]
|
||||||
|
}
|
||||||
|
return (ctx.${type})(val, buffer, offset)
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolder: ['parametrizable', (compiler, opts) => {
|
||||||
|
const baseName = `value.${opts.baseName}`
|
||||||
|
const otherwiseName = `value.${opts.otherwise.name}`
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
if (${baseName}) {
|
||||||
|
offset = ${compiler.callType(`${baseName} + 1`, 'varint')}
|
||||||
|
} else if (${otherwiseName}) {
|
||||||
|
offset = ${compiler.callType(`${otherwiseName}`, opts.otherwise.type)}
|
||||||
|
} else {
|
||||||
|
throw new Error('registryEntryHolder type requires "${baseName}" or "${otherwiseName}" fields to be set')
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolderSet: ['parametrizable', (compiler, opts) => {
|
||||||
|
const baseName = `value.${opts.base.name}`
|
||||||
|
const otherwiseName = `value.${opts.otherwise.name}`
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
if (${baseName}) {
|
||||||
|
offset = ${compiler.callType(0, 'varint')}
|
||||||
|
offset = ${compiler.callType(`${baseName}`, opts.base.type)}
|
||||||
|
} else if (${otherwiseName}) {
|
||||||
|
offset = ${compiler.callType(`${otherwiseName}.length + 1`, 'varint')}
|
||||||
|
for (let i = 0; i < ${otherwiseName}.length; i++) {
|
||||||
|
offset = ${compiler.callType(`${otherwiseName}[i]`, opts.otherwise.type)}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('registryEntryHolder type requires "${opts.base.name}" or "${opts.otherwise.name}" fields to be set')
|
||||||
|
}
|
||||||
|
return offset
|
||||||
|
`.trim())
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
SizeOf: {
|
SizeOf: {
|
||||||
|
@ -149,6 +252,60 @@ module.exports = {
|
||||||
}
|
}
|
||||||
code += 'return size'
|
code += 'return size'
|
||||||
return compiler.wrapCode(code)
|
return compiler.wrapCode(code)
|
||||||
|
}],
|
||||||
|
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
||||||
|
let fstr = JSON.stringify(flags)
|
||||||
|
if (Array.isArray(flags)) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
|
||||||
|
fstr += '}'
|
||||||
|
} else if (shift) {
|
||||||
|
fstr = '{'
|
||||||
|
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
|
||||||
|
fstr += '}'
|
||||||
|
}
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
const flags = ${fstr}
|
||||||
|
let val = value._value ${big ? '|| 0n' : ''}
|
||||||
|
for (const key in flags) {
|
||||||
|
if (value[key]) val |= flags[key]
|
||||||
|
}
|
||||||
|
return (ctx.${type})(val)
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolder: ['parametrizable', (compiler, opts) => {
|
||||||
|
const baseName = `value.${opts.baseName}`
|
||||||
|
const otherwiseName = `value.${opts.otherwise.name}`
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
let size = 0
|
||||||
|
if (${baseName}) {
|
||||||
|
size += ${compiler.callType(`${baseName} + 1`, 'varint')}
|
||||||
|
} else if (${otherwiseName}) {
|
||||||
|
size += ${compiler.callType(`${otherwiseName}`, opts.otherwise.type)}
|
||||||
|
} else {
|
||||||
|
throw new Error('registryEntryHolder type requires "${baseName}" or "${otherwiseName}" fields to be set')
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
`.trim())
|
||||||
|
}],
|
||||||
|
registryEntryHolderSet: ['parametrizable', (compiler, opts) => {
|
||||||
|
const baseName = `value.${opts.base.name}`
|
||||||
|
const otherwiseName = `value.${opts.otherwise.name}`
|
||||||
|
return compiler.wrapCode(`
|
||||||
|
let size = 0
|
||||||
|
if (${baseName}) {
|
||||||
|
size += ${compiler.callType(0, 'varint')}
|
||||||
|
size += ${compiler.callType(`${baseName}`, opts.base.type)}
|
||||||
|
} else if (${otherwiseName}) {
|
||||||
|
size += ${compiler.callType(`${otherwiseName}.length + 1`, 'varint')}
|
||||||
|
for (let i = 0; i < ${otherwiseName}.length; i++) {
|
||||||
|
size += ${compiler.callType(`${otherwiseName}[i]`, opts.otherwise.type)}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('registryEntryHolder type requires "${opts.base.name}" or "${opts.otherwise.name}" fields to be set')
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
`.trim())
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
defaultVersion: '1.21.1',
|
defaultVersion: '1.21.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']
|
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']
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,18 @@ const ITERATIONS = 10000
|
||||||
const mc = require('../')
|
const mc = require('../')
|
||||||
const states = mc.states
|
const states = mc.states
|
||||||
|
|
||||||
const testDataWrite = [
|
|
||||||
{ name: 'keep_alive', params: { keepAliveId: 957759560 } },
|
|
||||||
// TODO: 1.19+ `chat` -> `player_chat` feature toggle
|
|
||||||
// { name: 'chat', params: { message: '<Bob> Hello World!' } },
|
|
||||||
{ name: 'position_look', params: { x: 6.5, y: 65.62, stance: 67.24, z: 7.5, yaw: 0, pitch: 0, onGround: true } }
|
|
||||||
// TODO: add more packets for better quality data
|
|
||||||
]
|
|
||||||
|
|
||||||
for (const supportedVersion of mc.supportedVersions) {
|
for (const supportedVersion of mc.supportedVersions) {
|
||||||
const mcData = require('minecraft-data')(supportedVersion)
|
const mcData = require('minecraft-data')(supportedVersion)
|
||||||
const version = mcData.version
|
const version = mcData.version
|
||||||
|
const positionFlags = mcData.isNewerOrEqualTo('1.21.3') ? { flags: { onGround: true, hasHorizontalCollision: false } } : { onGround: true }
|
||||||
|
const testDataWrite = [
|
||||||
|
{ name: 'keep_alive', params: { keepAliveId: 957759560 } },
|
||||||
|
// TODO: 1.19+ `chat` -> `player_chat` feature toggle
|
||||||
|
// { name: 'chat', params: { message: '<Bob> Hello World!' } },
|
||||||
|
{ name: 'position_look', params: { x: 6.5, y: 65.62, stance: 67.24, z: 7.5, yaw: 0, pitch: 0, ...positionFlags } }
|
||||||
|
// TODO: add more packets for better quality data
|
||||||
|
]
|
||||||
|
|
||||||
describe('benchmark ' + supportedVersion + 'v', function () {
|
describe('benchmark ' + supportedVersion + 'v', function () {
|
||||||
this.timeout(60 * 1000)
|
this.timeout(60 * 1000)
|
||||||
const inputData = []
|
const inputData = []
|
||||||
|
|
|
@ -59,7 +59,8 @@ for (const supportedVersion of mc.supportedVersions) {
|
||||||
'server-port': PORT,
|
'server-port': PORT,
|
||||||
motd: 'test1234',
|
motd: 'test1234',
|
||||||
'max-players': 120,
|
'max-players': 120,
|
||||||
// 'level-type': 'flat',
|
'level-type': 'flat',
|
||||||
|
'generate-structures': 'false', // 12m
|
||||||
'use-native-transport': 'false' // java 16 throws errors without this, https://www.spigotmc.org/threads/unable-to-access-address-of-buffer.311602
|
'use-native-transport': 'false' // java 16 throws errors without this, https://www.spigotmc.org/threads/unable-to-access-address-of-buffer.311602
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if (err) reject(err)
|
if (err) reject(err)
|
||||||
|
@ -191,7 +192,6 @@ for (const supportedVersion of mc.supportedVersions) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 1.19+
|
// 1.19+
|
||||||
console.log('Chat Message', data)
|
|
||||||
const sender = JSON.parse(data.senderName)
|
const sender = JSON.parse(data.senderName)
|
||||||
const msgPayload = data.formattedMessage ? JSON.parse(data.formattedMessage) : data.plainMessage
|
const msgPayload = data.formattedMessage ? JSON.parse(data.formattedMessage) : data.plainMessage
|
||||||
const plainMessage = client.parseMessage(msgPayload).toString()
|
const plainMessage = client.parseMessage(msgPayload).toString()
|
||||||
|
|
|
@ -57,7 +57,32 @@ const nbtValue = {
|
||||||
|
|
||||||
function getFixedPacketPayload (version, packetName) {
|
function getFixedPacketPayload (version, packetName) {
|
||||||
if (packetName === 'declare_recipes') {
|
if (packetName === 'declare_recipes') {
|
||||||
if (version['>=']('1.20.5')) {
|
if (version['>=']('1.21.3')) {
|
||||||
|
return {
|
||||||
|
recipes: [
|
||||||
|
{
|
||||||
|
name: 'minecraft:campfire_input',
|
||||||
|
items: [
|
||||||
|
903,
|
||||||
|
976
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
stoneCutterRecipes: [
|
||||||
|
{
|
||||||
|
input: {
|
||||||
|
ids: [
|
||||||
|
6
|
||||||
|
]
|
||||||
|
},
|
||||||
|
slotDisplay: {
|
||||||
|
type: 'item_stack',
|
||||||
|
data: slotValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (version['>=']('1.20.5')) {
|
||||||
return {
|
return {
|
||||||
recipes: [
|
recipes: [
|
||||||
{
|
{
|
||||||
|
@ -241,6 +266,13 @@ const values = {
|
||||||
suggestionType: 'minecraft:summonable_entities'
|
suggestionType: 'minecraft:summonable_entities'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
bitflags: function (typeArgs, context) {
|
||||||
|
const results = {}
|
||||||
|
Object.keys(typeArgs.flags).forEach(function (index) {
|
||||||
|
results[typeArgs.flags[index]] = true
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
},
|
||||||
soundSource: 'master',
|
soundSource: 'master',
|
||||||
packedChunkPos: {
|
packedChunkPos: {
|
||||||
x: 10,
|
x: 10,
|
||||||
|
@ -263,7 +295,49 @@ const values = {
|
||||||
isDebug: false,
|
isDebug: false,
|
||||||
isFlat: false,
|
isFlat: false,
|
||||||
portalCooldown: 0
|
portalCooldown: 0
|
||||||
|
},
|
||||||
|
MovementFlags: {
|
||||||
|
onGround: true,
|
||||||
|
hasHorizontalCollision: false
|
||||||
|
},
|
||||||
|
ContainerID: 0,
|
||||||
|
PositionUpdateRelatives: {
|
||||||
|
x: true,
|
||||||
|
y: true,
|
||||||
|
z: true,
|
||||||
|
yaw: true,
|
||||||
|
pitch: true,
|
||||||
|
dx: true,
|
||||||
|
dy: true,
|
||||||
|
dz: true,
|
||||||
|
yawDelta: true
|
||||||
|
},
|
||||||
|
RecipeDisplay: {
|
||||||
|
type: 'stonecutter',
|
||||||
|
data: {
|
||||||
|
ingredient: { type: 'empty' },
|
||||||
|
result: { type: 'empty' },
|
||||||
|
craftingStation: { type: 'empty' }
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
SlotDisplay: { type: 'empty' },
|
||||||
|
game_profile: {
|
||||||
|
name: 'test',
|
||||||
|
properties: [{
|
||||||
|
key: 'foo',
|
||||||
|
value: 'bar'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
optvarint: 1,
|
||||||
|
chat_session: {
|
||||||
|
uuid: '00112233-4455-6677-8899-aabbccddeeff',
|
||||||
|
publicKey: {
|
||||||
|
expireTime: 30,
|
||||||
|
keyBytes: [],
|
||||||
|
keySignature: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IDSet: { ids: [2, 5] }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValue (_type, packet) {
|
function getValue (_type, packet) {
|
||||||
|
|
Loading…
Reference in a new issue