fix(runtime/skills/chop-logs): skip unsafe log gathering near hostiles
This commit is contained in:
@@ -25,6 +25,14 @@ function withTimeout(promise, ms, label) {
|
|||||||
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UNSAFE_HOSTILE_DISTANCE = 8;
|
||||||
|
function nearbyUnsafeHostile(snapshot) {
|
||||||
|
const hostile = snapshot?.closestHostile;
|
||||||
|
const distance = Number(hostile?.distance);
|
||||||
|
if (!Number.isFinite(distance) || distance > UNSAFE_HOSTILE_DISTANCE) return null;
|
||||||
|
return { name: hostile?.name ?? "hostile", distance };
|
||||||
|
}
|
||||||
|
|
||||||
export const skill = Object.freeze({
|
export const skill = Object.freeze({
|
||||||
id: "gather.logs",
|
id: "gather.logs",
|
||||||
title: "Gather logs",
|
title: "Gather logs",
|
||||||
@@ -34,6 +42,17 @@ export const skill = Object.freeze({
|
|||||||
timeoutMs: 90_000,
|
timeoutMs: 90_000,
|
||||||
preconditions(ctx) {
|
preconditions(ctx) {
|
||||||
if (!ctx?.bot) return { ok: false, code: "no_bot", detail: "bot missing" };
|
if (!ctx?.bot) return { ok: false, code: "no_bot", detail: "bot missing" };
|
||||||
|
const unsafeHostile = nearbyUnsafeHostile(ctx.snapshot);
|
||||||
|
if (unsafeHostile) {
|
||||||
|
// When defend/flee is cooling down, don't let collectBlock spend its
|
||||||
|
// whole 60s timeout chopping beside a mob. no_target reuses the
|
||||||
|
// scheduler's existing short backoff for gather skills.
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
code: "no_target",
|
||||||
|
detail: `unsafe to gather logs: ${unsafeHostile.name} ${unsafeHostile.distance.toFixed(1)} blocks away`,
|
||||||
|
};
|
||||||
|
}
|
||||||
const known = logBlocks(ctx.bot);
|
const known = logBlocks(ctx.bot);
|
||||||
if (known.size === 0) {
|
if (known.size === 0) {
|
||||||
return { ok: false, code: "unsupported_version", detail: "no log blocks in registry" };
|
return { ok: false, code: "unsupported_version", detail: "no log blocks in registry" };
|
||||||
|
|||||||
@@ -37,6 +37,17 @@ test("preconditions gate execution", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("gather.logs precondition refuses nearby hostiles", async () => {
|
||||||
|
const bot = { registry: { blocksByName: { oak_log: { id: 1 } } } };
|
||||||
|
const res = await runSkill("gather.logs", {
|
||||||
|
bot,
|
||||||
|
snapshot: { closestHostile: { name: "drowned", distance: 6.1 } },
|
||||||
|
});
|
||||||
|
assert.equal(res.ok, false);
|
||||||
|
assert.equal(res.code, "no_target");
|
||||||
|
assert.match(res.detail, /unsafe to gather logs: drowned 6\.1 blocks away/);
|
||||||
|
});
|
||||||
|
|
||||||
test("preconditions that throw produce precondition_failed", async () => {
|
test("preconditions that throw produce precondition_failed", async () => {
|
||||||
const teardown = _registerForTest({
|
const teardown = _registerForTest({
|
||||||
id: "test.precondition-throw",
|
id: "test.precondition-throw",
|
||||||
|
|||||||
Reference in New Issue
Block a user