use goToGoal, better movement selection and error handling

This commit is contained in:
MaxRobinsonTheGreat 2025-08-14 18:40:13 -05:00
parent 0d8719f8ef
commit 5aa4aa4e06
2 changed files with 39 additions and 36 deletions

View file

@ -4,7 +4,7 @@ import pf from 'mineflayer-pathfinder';
import Vec3 from 'vec3'; import Vec3 from 'vec3';
import settings from "../../../settings.js"; import settings from "../../../settings.js";
const blockPlaceDelay = settings.block_place_delay || 10; const blockPlaceDelay = settings.block_place_delay == null ? 0 : settings.block_place_delay;
const useDelay = blockPlaceDelay > 0; const useDelay = blockPlaceDelay > 0;
export function log(bot, message) { export function log(bot, message) {
@ -506,7 +506,7 @@ export async function pickupNearbyItems(bot) {
let pickedUp = 0; let pickedUp = 0;
while (nearestItem) { while (nearestItem) {
bot.pathfinder.setMovements(new pf.Movements(bot)); bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(new pf.goals.GoalFollow(nearestItem, 0.8), true); await goToGoal(bot, new pf.goals.GoalFollow(nearestItem, 0.8));
await new Promise(resolve => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
let prev = nearestItem; let prev = nearestItem;
nearestItem = getNearestItem(bot); nearestItem = getNearestItem(bot);
@ -549,7 +549,7 @@ export async function breakBlockAt(bot, x, y, z) {
movements.canPlaceOn = false; movements.canPlaceOn = false;
movements.allow1by1towers = false; movements.allow1by1towers = false;
bot.pathfinder.setMovements(movements); bot.pathfinder.setMovements(movements);
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4)); await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
} }
if (bot.game.gameMode !== 'creative') { if (bot.game.gameMode !== 'creative') {
await bot.tool.equipForBlock(block); await bot.tool.equipForBlock(block);
@ -727,7 +727,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
let pos = targetBlock.position; let pos = targetBlock.position;
let movements = new pf.Movements(bot); let movements = new pf.Movements(bot);
bot.pathfinder.setMovements(movements); bot.pathfinder.setMovements(movements);
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4)); await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
} }
await bot.equip(block, 'hand'); await bot.equip(block, 'hand');
@ -952,6 +952,10 @@ export async function giveToPlayer(bot, itemType, username, num=1) {
* @example * @example
* await skills.giveToPlayer(bot, "oak_log", "player1"); * await skills.giveToPlayer(bot, "oak_log", "player1");
**/ **/
if (bot.username === username) {
log(bot, `You cannot give items to yourself.`);
return false;
}
let player = bot.players[username].entity let player = bot.players[username].entity
if (!player) { if (!player) {
log(bot, `Could not find ${username}.`); log(bot, `Could not find ${username}.`);
@ -1011,7 +1015,7 @@ export async function giveToPlayer(bot, itemType, username, num=1) {
export async function goToGoal(bot, goal) { export async function goToGoal(bot, goal) {
/** /**
* Navigate to the given goal, attempting minimally destructive movements. * Navigate to the given goal. Use doors and attempt minimally destructive movements.
* @param {MinecraftBot} bot, reference to the minecraft bot. * @param {MinecraftBot} bot, reference to the minecraft bot.
* @param {pf.goals.Goal} goal, the goal to navigate to. * @param {pf.goals.Goal} goal, the goal to navigate to.
**/ **/
@ -1025,30 +1029,18 @@ export async function goToGoal(bot, goal) {
const destructiveMovements = new pf.Movements(bot); const destructiveMovements = new pf.Movements(bot);
let final_movements = null; let final_movements = destructiveMovements;
let movements = [
{name: 'nonDestructive', movements: nonDestructiveMovements},
{name: 'destructive', movements: destructiveMovements}
];
const pathfind_timeout = 1000; const pathfind_timeout = 1000;
try { if (await bot.pathfinder.getPathTo(nonDestructiveMovements, goal, pathfind_timeout).status === 'success') {
for (let i = 0; i < movements.length; i++) { final_movements = nonDestructiveMovements;
const movement = movements[i].movements; log(bot, `Found non-destructive path.`);
const path = await bot.pathfinder.getPathTo(movement, goal, pathfind_timeout);
if (path && path.path && path.path.length > 0 && path.status !== 'noPath') {
final_movements = movement;
log(bot, `Using ${movements[i].name} movements.`);
break;
} }
else if (await bot.pathfinder.getPathTo(destructiveMovements, goal, pathfind_timeout).status === 'success') {
log(bot, `Found destructive path.`);
} }
if (!final_movements) { else {
log(bot, `Could not find a path to ${username}.`); log(bot, `Could not find a path to goal, attempting to navigate anyway using destructive movements.`);
return false;
}
} catch (err) {
log(bot, `Could not find a path: ${err.message}.`);
return false;
} }
const doorCheckInterval = startDoorInterval(bot); const doorCheckInterval = startDoorInterval(bot);
@ -1059,9 +1051,9 @@ export async function goToGoal(bot, goal) {
clearInterval(doorCheckInterval); clearInterval(doorCheckInterval);
return true; return true;
} catch (err) { } catch (err) {
log(bot, `Could not find a path: ${err.message}.`);
clearInterval(doorCheckInterval); clearInterval(doorCheckInterval);
return false; // we need to catch so we can clean up the door check interval, then rethrow the error
throw err;
} }
} }
@ -1168,9 +1160,16 @@ export async function goToPosition(bot, x, y, z, min_distance=2) {
try { try {
await goToGoal(bot, new pf.goals.GoalNear(x, y, z, min_distance)); await goToGoal(bot, new pf.goals.GoalNear(x, y, z, min_distance));
log(bot, `You have reached at ${x}, ${y}, ${z}.`);
clearInterval(progressInterval); clearInterval(progressInterval);
const distance = bot.entity.position.distanceTo(new Vec3(x, y, z));
if (distance <= min_distance+1) {
log(bot, `You have reached at ${x}, ${y}, ${z}.`);
return true; return true;
}
else {
log(bot, `Unable to reach ${x}, ${y}, ${z}, you are ${Math.round(distance)} blocks away.`);
return false;
}
} catch (err) { } catch (err) {
log(bot, `Pathfinding stopped: ${err.message}.`); log(bot, `Pathfinding stopped: ${err.message}.`);
clearInterval(progressInterval); clearInterval(progressInterval);
@ -1235,7 +1234,10 @@ export async function goToPlayer(bot, username, distance=3) {
* @example * @example
* await skills.goToPlayer(bot, "player"); * await skills.goToPlayer(bot, "player");
**/ **/
if (bot.username === username) {
log(bot, `You are already at ${username}.`);
return true;
}
if (bot.modes.isOn('cheat')) { if (bot.modes.isOn('cheat')) {
bot.chat('/tp @s ' + username); bot.chat('/tp @s ' + username);
log(bot, `Teleported to ${username}.`); log(bot, `Teleported to ${username}.`);
@ -1287,7 +1289,7 @@ export async function followPlayer(bot, username, distance=4) {
if (bot.modes.isOn('cheat') && bot.entity.position.distanceTo(player.position) > 100 && player.isOnGround) { if (bot.modes.isOn('cheat') && bot.entity.position.distanceTo(player.position) > 100 && player.isOnGround) {
await goToPlayer(bot, username); await goToPlayer(bot, username);
} }
const is_nearby = bot.entity.position.distanceTo(player.position) <= distance + 1; const is_nearby = bot.entity.position.distanceTo(player.position) <= distance + 2;
if (is_nearby) { if (is_nearby) {
clearInterval(doorCheckInterval); clearInterval(doorCheckInterval);
doorCheckInterval = null; doorCheckInterval = null;
@ -1334,7 +1336,7 @@ export async function moveAway(bot, distance) {
} }
} }
await bot.pathfinder.goto(inverted_goal); await goToGoal(bot, inverted_goal);
let new_pos = bot.entity.position; let new_pos = bot.entity.position;
log(bot, `Moved away from nearest entity to ${new_pos}.`); log(bot, `Moved away from nearest entity to ${new_pos}.`);
return true; return true;
@ -1528,7 +1530,7 @@ export async function tillAndSow(bot, x, y, z, seedType=null) {
if (bot.entity.position.distanceTo(block.position) > 4.5) { if (bot.entity.position.distanceTo(block.position) > 4.5) {
let pos = block.position; let pos = block.position;
bot.pathfinder.setMovements(new pf.Movements(bot)); bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4)); await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
} }
if (block.name !== 'farmland') { if (block.name !== 'farmland') {
let hoe = bot.inventory.items().find(item => item.name.includes('hoe')); let hoe = bot.inventory.items().find(item => item.name.includes('hoe'));
@ -1574,7 +1576,7 @@ export async function activateNearestBlock(bot, type) {
if (bot.entity.position.distanceTo(block.position) > 4.5) { if (bot.entity.position.distanceTo(block.position) > 4.5) {
let pos = block.position; let pos = block.position;
bot.pathfinder.setMovements(new pf.Movements(bot)); bot.pathfinder.setMovements(new pf.Movements(bot));
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4)); await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
} }
await bot.activateBlock(block); await bot.activateBlock(block);
log(bot, `Activated ${type} at x:${block.position.x.toFixed(1)}, y:${block.position.y.toFixed(1)}, z:${block.position.z.toFixed(1)}.`); log(bot, `Activated ${type} at x:${block.position.x.toFixed(1)}, y:${block.position.y.toFixed(1)}, z:${block.position.z.toFixed(1)}.`);

View file

@ -354,6 +354,7 @@ export async function isClearPath(bot, target) {
let movements = new pf.Movements(bot) let movements = new pf.Movements(bot)
movements.canDig = false; movements.canDig = false;
movements.canPlaceOn = false; movements.canPlaceOn = false;
movements.canOpenDoors = false;
let goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1); let goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1);
let path = await bot.pathfinder.getPathTo(movements, goal, 100); let path = await bot.pathfinder.getPathTo(movements, goal, 100);
return path.status === 'success'; return path.status === 'success';