Follow-up to the iteration-1 fixes. Live smoke on play.xmatic.team revealed the bot was spawning into a tree-less plain (no log within 32 blocks of spawn), looping wander→gather→no_target→wander forever inside a 16-block box. - runtime/actions.js: chopNearestTree search radius 32 → 64 (still no trees on this spawn, but a normal biome will be served well by it). wander now has a blind-walk fallback when pathfinder times out (look+forward+jump for 3 s) so the bot at least unsticks from leaves or pillars. Pathfinder timeout reduced 30 s → 15 s. - runtime/skills/explore-far.js: new explore.far skill — walks ~48 blocks in a quadrant (NE/SE/SW/NW, rotating per call) so successive hints actually circle the spawn instead of bouncing in place. Blind walk fallback included. - runtime/reflex.js: when the scheduler is told to wander twice in a row by gather.* recover hints, it now dispatches explore.far instead so the bot actually leaves the patch it's stuck in. Resets the consecutiveWanderHints counter on any success. - runtime/reflex.js (sleep): no longer dispatches when the bot has neither a bed in inventory NOR a known shelter/base location — saved one dispatch + 5-min cooldown per restart at night. - runtime/reflex.js (eat): inventory check + lastEatAt always updated fix the eat-spam loop observed live (every tick fired "eat" → "no food in inventory" → again). - runtime/skills/chop-logs.js: recognise "no log within ..." as no_target so the recover hint switches the bot to wander/explore. npm test 124/124. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.7 KiB
JavaScript
55 lines
1.7 KiB
JavaScript
// gather.logs — find the nearest log block matching the server's log
|
|
// registry, path to it, mine it. Wraps the existing actions.js primitive
|
|
// while exposing the survival-skill contract (preconditions, timeout,
|
|
// structured worldDelta, recovery hint).
|
|
|
|
import { chopNearestTree } from "../actions.js";
|
|
import { logs as logBlocks } from "./groups.js";
|
|
|
|
export const skill = Object.freeze({
|
|
id: "gather.logs",
|
|
title: "Gather logs",
|
|
timeoutMs: 60_000,
|
|
preconditions(ctx) {
|
|
if (!ctx?.bot) return { ok: false, code: "no_bot", detail: "bot missing" };
|
|
const known = logBlocks(ctx.bot);
|
|
if (known.size === 0) {
|
|
return { ok: false, code: "unsupported_version", detail: "no log blocks in registry" };
|
|
}
|
|
return { ok: true };
|
|
},
|
|
async execute(ctx) {
|
|
const res = await chopNearestTree(ctx.bot);
|
|
if (res.ok) {
|
|
return {
|
|
ok: true,
|
|
code: "done",
|
|
detail: res.detail,
|
|
worldDelta: {
|
|
choppedAt: res.detail?.at ?? null,
|
|
logType: res.detail?.logType ?? null,
|
|
},
|
|
};
|
|
}
|
|
const msg = String(res.detail ?? "");
|
|
const code = (msg.includes("no reachable log") || msg.includes("no log within"))
|
|
? "no_target"
|
|
: msg.includes("timed out")
|
|
? "timeout"
|
|
: "failed";
|
|
return { ok: false, code, detail: res.detail, worldDelta: null };
|
|
},
|
|
validate(ctx, result) {
|
|
return result.ok && !!result.worldDelta?.logType;
|
|
},
|
|
recover(ctx, result) {
|
|
// Tell the caller: if there was no reachable log, switching to wander
|
|
// for ~60 s is the right next move — same heuristic the autonomous
|
|
// reflex already uses.
|
|
if (result.code === "no_target") {
|
|
return { hint: "wander", reason: "no log within 32 blocks" };
|
|
}
|
|
return null;
|
|
},
|
|
});
|