Root cause of "bot just stands still": every gather.* skill was using
bot.findBlock({ matching: (b) => names.includes(b.name) }), and under
mineflayer 1.21.4 + ViaBackwards the Block objects fed into the
callback have a wrong .name field (Block.type / numeric id is still
correct — this is mineflayer issue #2347). Every search returned null,
every skill reported "no_target", reflex looped wander → tunnel-out
forever. The bot's logs said "dispatch ok" while the operator watched
it pace in circles.
Proven live with a new diag.match skill on play.xmatic.team:
findBlocks({matching: numericIds}) → 50 hits
findBlocks({matching: (b) => b.name === ...}) → 0 hits ← the bug
findBlock({matching: (b) => b.name === ...}) → null ← the bug
findBlock({matching: numericIds}) → dark_oak_log @ (606,62,110)
After this fix the same bot from the same spawn dispatches gather.logs
and reaches the chop loop ("chop: dark_oak_log at 606,62,110 (tool=fists)")
instead of returning "no reachable log within 64 blocks".
Changes:
- runtime/perception.js (new): findBlocksByName / findNearestBlockByName
centralise the numeric-id workaround for any future skill.
- runtime/actions.js: chopNearestTree, sleepInBed, placeCraftingTable now
use perception. Also load mineflayer-tool plugin alongside collectblock
(collectblock 1.6 hard-requires bot.tool to dispatch a dig).
- gather-stone, gather-wool, deposit-surplus rewritten to numeric-id
search. gather-wool also loads mineflayer-tool.
- diagnose-scan.js (new): two diagnostic skills — diag.scan reports
findBlocks counts per radius for common blocks; diag.match cross-tests
the four matcher styles so this regression can be re-proven on demand.
- runtime/skills/index.js: registers diag.scan + diag.match.
Memory: project_findblock_callback_broken_under_viabackwards.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
52 lines
2.1 KiB
JavaScript
52 lines
2.1 KiB
JavaScript
// World perception primitives.
|
|
//
|
|
// PROBLEM: under mineflayer 1.21.4 + ViaBackwards (this server runs
|
|
// Paper 26.1.x with VV/VB translating 1.21.5+ protocol down to 1.21.4),
|
|
// bot.findBlock and bot.findBlocks with a CALLBACK matcher silently
|
|
// return null/empty — the Block objects passed into the callback have a
|
|
// wrong `.name` field because the protocol-side block-id mapping has
|
|
// drifted from minecraft-data 1.21.4. Confirmed live 2026-05-26 via
|
|
// diag.scan: oak_log count in radius 16 = 46 with `matching: numericId`
|
|
// but 0 with `matching: (b) => b.name === "oak_log"`.
|
|
//
|
|
// Mineflayer issue #2347 (findBlocks fails under ViaBackwards) is the
|
|
// upstream bug; the workaround is to feed numeric block IDs from the
|
|
// bot's registry directly. This module centralises that workaround so
|
|
// every skill stops growing its own subtly-broken matcher closure.
|
|
|
|
export function nameToId(bot, name) {
|
|
return bot.registry?.blocksByName?.[name]?.id ?? null;
|
|
}
|
|
|
|
export function namesToIds(bot, names) {
|
|
const out = [];
|
|
for (const n of names) {
|
|
const id = nameToId(bot, n);
|
|
if (typeof id === "number") out.push(id);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// Find up to `count` blocks matching any of the given names. Returns an
|
|
// array of Vec3 positions, sorted by mineflayer (typically by Manhattan
|
|
// distance from the bot). Empty when no name resolves to a registry id.
|
|
export function findBlocksByName(bot, names, { maxDistance = 64, count = 32 } = {}) {
|
|
const ids = namesToIds(bot, names);
|
|
if (ids.length === 0) return [];
|
|
return bot.findBlocks({ matching: ids, maxDistance, count }) || [];
|
|
}
|
|
|
|
// Same as findBlocksByName but returns the nearest matching Block object
|
|
// (not a Vec3). Skips positions for which a custom predicate returns
|
|
// false — used by callers that need post-filter logic like blacklists.
|
|
export function findNearestBlockByName(bot, names, { maxDistance = 64, predicate } = {}) {
|
|
const positions = findBlocksByName(bot, names, { maxDistance, count: 32 });
|
|
for (const pos of positions) {
|
|
const blk = bot.blockAt(pos);
|
|
if (!blk) continue;
|
|
if (predicate && !predicate(blk)) continue;
|
|
return blk;
|
|
}
|
|
return null;
|
|
}
|