I am working on a Minecraft bot in JavaScript using Mineflayer-Pathfinder.
I am seeing strange behavior. Before I call bot.pathfinder.setGoal(), I set the movement rules using pathfinder.setMovements(). However, when I do this, it seems like it takes the bot a few seconds for the movement rules to actually update. For the first few seconds as the bot carries out its goal, it sprints and does wild parkour moves to get to the target. This causes the bot to get rubber banded really bad on the server, and throws it off the path. Then, suddenly, it starts following the rules I set. Walking slowly, no parkour, etc.
The temporary workaround I found was to just set a delay before calling setGoal. I’ve found it can take at least 2 seconds for the bot to obey the rules set. However, the fact that I’m using timing for something like this tells me that I’ve likely done something critically wrong.
One thing I tried is to await for a path_update or path_reset after setting the movements, but it never seems to trigger….
await new Promise(res => bot.once('path_reset', res));
Nowhere else in my codebase am I setting the movements to anything different from the rules I set in my buildConstrainedMovments().
// helper to construct Movments
export function buildConstrainedMovements(bot, mcData) {
const m = new Movements(bot, mcData);
m.canDig = false;
m.allowWater = false;
m.allowSprinting = false;
m.allow1by1towers = false;
m.allowParkour = false;
m.canOpenDoors = true;
m.maxDropDown = 5;
if (!m.blocksToAvoid) m.blocksToAvoid = new Set();
const avoidNames = [
'cobweb','sweet_berry_bush','powder_snow','campfire','soul_campfire','fire','magma_block','scaffolding',
...Object.keys(mcData.blocksByName).filter(n => /trapdoor/.test(n))
];
for (const name of avoidNames) {
const b = mcData.blocksByName[name];
if (b) m.blocksToAvoid.add(b.id);
}
m.liquidCost = 100;
return m;
}
// Child functions of makePearlPuller
/**
* Create a pearl-pulling helper bound to a bot instance.
* Usage:
* const pullPearl = makePearlPuller(bot, cfg, logger);
* await pullPearl('Notch', { x: 0, y: 64, z: 0 });
*/
export function makePearlPuller(bot, cfg, logger) {
// Helper functions...
bot.on('goal_reached', async (goal) => {
if (!activePull) return;
// Handle goal reached...
});
return async function pullPearl(username, homeCoords) { // <- Problem function
if (activePull) return Promise.resolve();
return new Promise(async (resolveOuter) => {
_resolvePearlRun = resolveOuter; // scope in parent function
try {
const moves = await buildConstrainedMovements(bot, mcData);
await bot.pathfinder.setMovements(moves);
// ... Here I figure out where the coordinates to an active ender pearl is, and populate best with the coordinates
// For some reason, if I don't wait a couple seconds, the bot ignores the movement rules set and starts sprinting,
// doing parkour, etc.
// bot.pathfinder.setGoal(new GoalNear(best.x, best.y, best.z, 2)); <- Won't work
setTimeout(() => {
try {
bot.pathfinder.setGoal(new GoalNear(best.x, best.y, best.z, 2));
} catch (e) {
logger?.warn?.('[pearl] setGoal failed:', e?.message || e);
activePull = null;
finishPull();
}
}, 3000);
} catch (err) {
logger?.error?.('[pearl] unexpected error:', err);
activePull = null;
finishPull();
}
});
};
}
Node Version: v18.19.1
Packages:
minecraft-data: 3.99.1
mineflayer: 4.20.0
mineflayer-pathfinder: 2.4.5