使用Mineflayer(Node.js)实现玩家跟随功能时出现库源码错误
问题:使用mineflayer-pathfinder实现跟随玩家时触发TypeError错误
我尝试用Node.js的mineflayer库做一个自动跟随玩家的机器人,但运行时触发了mineflayer-pathfinder库的错误。我的代码如下:
const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder') const GoalFollow = goals.GoalFollow const bot = mineflayer.createBot({ host: 'PRIVATE', username: 'TRASHCAN' }) bot.loadPlugin(pathfinder) function followPlayer() { const player = p => p.type === "player"; const mcData = require('minecraft-data')(bot.version); const movements = new Movements(mcData); bot.pathfinder.setMovements(movements); const goal = new GoalFollow(player.entity, 3) bot.pathfinder.setGoal(goal, true); } const prefix = ",s" const password = 'REMOVED' const login = `/login ${password}` const { mineflayer: mineflayerViewer } = require('prismarine-viewer') bot.once('spawn', () => { mineflayerViewer(bot, { port: 3007, firstPerson: true }) // port is the minecraft server port, if first person is false, you get a bird's-eye view bot.chat(login) bot.on('whisper', (username, message) => { if (message.startsWith(prefix) && username === 'Hitrocol') { bot.chat(message.split(',TRASHCAN_')[1]); } if (message.content === ',TRASHCAN_LOGIN' && username === 'Hitrocol') { bot.chat(login) } }) }) function lookAtNearestPlayer() { const playerFilter = (entity) => entity.type === 'player' const playerEntity = bot.nearestEntity(playerFilter); if (!playerEntity) return; const pos= playerEntity.position; bot.lookAt(pos); } bot.on('physicsTick', lookAtNearestPlayer); bot.on('physicsTick', followPlayer);
预期机器人能自动跟随玩家,但出现以下错误(mineflayer和mineflayer-pathfinder都是最新版本):
/Users/aarav/node_modules/mineflayer-pathfinder/lib/movements.js:42 this.blocksCantBreak.add(registry.blocksByName.chest.id) ^ TypeError: 无法读取未定义的属性(读取'blocksByName') at new Movements (/Users/aarav/node_modules/mineflayer-pathfinder/lib/movements.js:42:39) at EventEmitter.followPlayer (/Users/aarav/Downloads/codingshit/untitled folder/index.js:15:21) at EventEmitter.emit (node:events:529:35) at tickPhysics (/Users/aarav/node_modules/mineflayer/lib/plugins/physics.js:81:11) at Timeout.doPhysics [as _onTimeout] (/Users/aarav/node_modules/mineflayer/lib/plugins/physics.js:70:7) at listOnTimeout (node:internal/timers:569:17) at process.processTimers (node:internal/timers:512:7) Node.js v18.18.0
解决方案
错误原因分析
- Movements构造参数错误:新版mineflayer-pathfinder的
Movements类需要传入bot实例作为第一个参数,而不是直接传mcData。 - 玩家实体获取错误:
followPlayer里的player是一个过滤函数,不是实际的玩家实体,player.entity根本不存在,会导致GoalFollow初始化失败。 - 事件绑定不合理:把
followPlayer绑定到physicsTick事件会被高频调用(每游戏 tick 一次),重复初始化Movements和设置路径,不仅浪费性能,还会引发异常。
修复后的代码
const mineflayer = require('mineflayer'); const { pathfinder, Movements, goals } = require('mineflayer-pathfinder') const GoalFollow = goals.GoalFollow const bot = mineflayer.createBot({ host: 'PRIVATE', username: 'TRASHCAN' }) bot.loadPlugin(pathfinder) // 初始化Movements(只需一次) let movements; bot.once('spawn', () => { const mcData = require('minecraft-data')(bot.version); movements = new Movements(bot, mcData); // 传入bot实例作为第一个参数 }) function followPlayer() { // 获取最近的玩家实体 const playerFilter = (entity) => entity.type === 'player'; const playerEntity = bot.nearestEntity(playerFilter); if (!playerEntity) { bot.pathfinder.setGoal(null); // 没有玩家时清空路径目标 return; } bot.pathfinder.setMovements(movements); const goal = new GoalFollow(playerEntity, 3); // 传入实际的玩家实体 bot.pathfinder.setGoal(goal, true); } const prefix = ",s" const password = 'REMOVED' const login = `/login ${password}` const { mineflayer: mineflayerViewer } = require('prismarine-viewer') bot.once('spawn', () => { mineflayerViewer(bot, { port: 3007, firstPerson: true }) bot.chat(login) bot.on('whisper', (username, message) => { if (message.startsWith(prefix) && username === 'Hitrocol') { bot.chat(message.split(',TRASHCAN_')[1]); } if (message === ',TRASHCAN_LOGIN' && username === 'Hitrocol') { // 修正message.content的错误,whisper事件的message是字符串 bot.chat(login) } }) }) function lookAtNearestPlayer() { const playerFilter = (entity) => entity.type === 'player' const playerEntity = bot.nearestEntity(playerFilter); if (!playerEntity) return; const pos = playerEntity.position; bot.lookAt(pos); } // 合理控制跟随逻辑的执行频率,避免高频重复调用 let tickCount = 0; bot.on('physicsTick', () => { lookAtNearestPlayer(); tickCount++; if (tickCount % 20 === 0) { // 每1秒(20个游戏tick)执行一次跟随逻辑 followPlayer(); tickCount = 0; } });
额外修复点
- 修正了whisper事件中的
message.content错误:whisper事件的第二个参数message是字符串,不是对象,直接判断message === ',TRASHCAN_LOGIN'即可。 - 将Movements的初始化移到
spawn事件中,只执行一次,避免重复创建。 - 调整followPlayer的调用频率,减少不必要的性能消耗。
内容的提问来源于stack exchange,提问作者Adelto isbest
相关产品推荐
相关产品推荐

