'use strict'; /** * 协议自检:核对 mineflayer 写出的 `teleport_confirm` 包在 1.21.4 上是否存在、 * 字段名是否匹配。 * * 背景:部分服务端在收到 `player_position` 后会每 tick 重发位置包, * 直到客户端回一个 teleport_confirm 确认。若 mineflayer 因为版本字段名不一致 * 而写不出这个包,就会形成「服务端一直传送、客户端一直走不动」的死循环。 */ const mcData = require('minecraft-data')('1.21.4'); const toServer = mcData.protocol.play.toServer; const mappings = toServer.types.packet[1][0].type[1].mappings; console.log('=== 1.21.4 客户端 → 服务端 中与传送/位置相关的包名 ==='); for (const [id, name] of Object.entries(mappings)) { if (/teleport|position|confirm/i.test(name)) { console.log(` ${id.padStart(3)} ${name}`); } } console.log('\n=== 客户端 ← 服务端 中与传送/位置相关的包名 ==='); const toClientMappings = mcData.protocol.play.toClient.types.packet[1][0].type[1].mappings; for (const [id, name] of Object.entries(toClientMappings)) { if (/teleport|position/i.test(name)) { console.log(` ${id.padStart(3)} ${name}`); } } console.log('\n=== teleport_confirm / position_look 的字段定义(客户端 → 服务端)==='); function dumpPacketFields(packetName) { // protocol 结构:types.packet = ['container', [nameField, paramsField]] // paramsField.type = ['switch', { compareTo: 'name', fields: { 包名: [字段...] } }] const paramsField = toServer.types.packet[1][1]; const fields = paramsField.type[1].fields; const def = fields[packetName]; if (!def) { console.log(` (没有名为 ${packetName} 的包)`); return; } console.log(` ${packetName}: ` + def.map((f) => `${f.name}:${JSON.stringify(f.type)}`).join(', ')); } dumpPacketFields('teleport_confirm'); dumpPacketFields('position'); dumpPacketFields('position_look'); console.log('\n=== 客户端 ← 服务端 position 包的字段定义 ==='); function dumpToClientFields(packetName) { const paramsField = mcData.protocol.play.toClient.types.packet[1][1]; const def = paramsField.type[1].fields[packetName]; if (!def) { console.log(` (没有名为 ${packetName} 的包)`); return; } console.log(` ${packetName}: ` + def.map((f) => `${f.name}:${JSON.stringify(f.type)}`).join(', ')); } dumpToClientFields('position'); console.log('\n=== mineflayer 实际使用的包名 / 字段名 ==='); const fs = require('fs'); const path = require('path'); const physics = fs.readFileSync(path.join(__dirname, 'node_modules', 'mineflayer', 'lib', 'plugins', 'physics.js'), 'utf8'); const lines = physics.split('\n'); lines.forEach((line, index) => { if (/teleport_confirm|teleportId|teleport_id/.test(line)) { console.log(` physics.js:${index + 1} ${line.trim()}`); } });