execute_code - Cancellation now reaches inside the SDK via an AsyncLocalStorage scope: timeout, MCP cancel, or a newer call rejects pending waits and blocks further action packets, including those inside walkTo(). - One execution per bot: a new call supersedes the running one and starts once it has unwound; disconnect_bot does the same. - Cancelled user code parks on bot/sdk calls instead of throwing, so a catch-all loop can't spin and starve the server. - Console capture is routed per execution, so concurrent bots no longer clobber each other's output; leftover logs go to stderr. - Stale world state warns and still runs, so a stale client can be diagnosed. - Credentials are redacted from logs, results and launch messages. SDK - bot.mineRock() waits for ore plus Mining XP; interactLoc docs note that success can mean the action only started. - walkTo() takes options.timeout (default 120s), refuses stale state, and reports the real last position. - runScript uses the same cancellation scope for timeouts and signals. Docs trimmed of duplicated or stale execute_code text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2.6 KiB
Mining
Successful patterns for mining automation.
Finding Rocks
Rocks are locations (not NPCs). Filter for rocks with a "Mine" option:
The client names live rocks Rocks copper ore, Rocks tin ore, and so on.
Use /copper ore/i to find a rock; /^copper ore$/i matches the inventory item only.
Depleted rocks can appear as plain Rocks; select a live ore-specific rock again.
const state = sdk.getState();
const rock = state?.nearbyLocs
.filter((loc) => /rocks?/i.test(loc.name))
.filter((loc) => loc.optionsWithIndex.some((o) => /^mine$/i.test(o.text)))
.sort((a, b) => a.distance - b.distance)[0];
Mining Action
if (!rock) throw new Error("No mineable rock nearby");
const result = await bot.mineRock(rock);
if (!result.success) console.warn(result.reason, result.message);
For lower-level control, sendInteractLoc() only confirms client dispatch. Take
an XP/inventory baseline and wait for the intended change rather than sleeping
for an arbitrary duration.
Detecting Mining Activity
Animation ID 625 indicates active mining:
const animation = sdk.getState()?.player?.animId ?? -1;
const isMining = animation === 625;
const isIdle = animation === -1;
Note: Al Kharid mine is full of Lvl 14 scorpions. Combat 27+ with defensive style is enough to survive while mining. The scorpion fights actually train Defence passively.
Reliable Locations
| Location | Coordinates | Notes |
|---|---|---|
| SE Varrock mine | (3285, 3365) | Copper, tin, iron |
| Al Kharid mine | (3295, 3287) | Iron, coal, gold, silver, mithril, tin. Scorpions! |
| Lumbridge Swamp mine | - |
Getting to Al Kharid mine from Lumbridge: Pay 10gp toll at gate (3268, 3227), walk NE. Dialog sequence: continue → continue → "Yes, ok." (index 3) → continue.
Counting Ore
function countOre() {
const state = sdk.getState();
if (!state) return 0;
return state.inventory
.filter((i) => /ore$/i.test(i.name))
.reduce((sum, i) => sum + i.count, 0);
}
Drop When Full
const state = sdk.getState();
if (!state) throw new Error("No world state");
if (state.inventory.length >= 28) {
const ores = state.inventory.filter((i) => /ore$/i.test(i.name));
for (const ore of ores) {
await sdk.sendDropItem(ore.slot);
await new Promise((r) => setTimeout(r, 100));
}
}