Skip to main content

Automation API

Verification boundary

revision-sensitive RuneLite UI, packet, or in-game outcomes; treat those as live-client verification pending unless the page records direct evidence.

Automation code uses exactly two surfaces:

  • com.n3plugins.Api.actions.* — result-aware writes that return InteractionResult (e.g. BankActions.withdraw, DialogActions.chooseOption, MagicActions.cast).
  • com.n3plugins.sdk.query.* — read-only state access with fluent filters (e.g. Bank.search(), Inventory.getItems(), Dialogue.getOptions()).

There is no unified facade layer. Earlier sdk/widgets *Api classes (e.g. BankActions, Dialogue, Widgets, PrayerActions) were redundant delegation layers and have been removed; call the query or actions class directly.

Plugins that need ordered once-per-tick choices can compose these surfaces with sdk.combat.TickDecisionList. The list controls evaluation order and blocking; action APIs continue to own pacing and dispatch. See tick-decisions.md for the contract and combat examples.

if (Bank.isOpen() && Inventory.contains(ItemID.NATURE_RUNE)) {
BankActions.withdrawNoted(ItemID.NATURE_RUNE, 100);
}
Dialogue.DialogueOption option = Dialogue.getOptions().stream()
.filter(o -> o.getText().contains("Yes"))
.findFirst().orElse(null);

Spell names and packed widget IDs

MagicActions.resolveSpellInfo(name) resolves a non-blank friendly spell name to its packed widget ID. It derives its authoritative inventory from Api.actions.Spell. Each enum value contributes its normalized enum name and its InterfaceID-backed getWidgetId() value.

Optional<Integer> highAlchemy = MagicActions.resolveSpellInfo("High Level Alchemy");
if (!highAlchemy.isPresent()) {
// Unsupported, misspelled, or unavailable name: do not dispatch a widget action.
return;
}

int packedWidgetId = highAlchemy.get();
// Equals InterfaceID.MagicSpellbook.HIGH_ALCHEMY for this spell.

The resolver normalizes friendly punctuation, case, and the spell_ prefix before lookup. When an exact normalized match fails, the resolver retains its suffix matching for compatible friendly names. Treat an empty result as a configuration or input error. Do not replace it with a raw packed ID or a custom widget lookup.

Bank withdrawal with loadouts

BankActions.withdraw(InventoryLoadout, maxActions) withdraws missing loadout items with a depletion listener and an action cap:

loadout.setItemDepletionListener(item -> replan(item.getItemId()));
InteractionResult result = BankActions.withdraw(loadout, 10);

Ground-item action aliases

TileItemActions.resolveGroundActionIndex(actions...) maps friendly ground-item action aliases ("Take", "Pick up", "Op1".."Op5", ordinals) to menu action indices.

When to use which surface

  • Api.actions.* — writes that need InteractionResult status (e.g. distinguishing PACED / TARGET_NOT_FOUND from a real failure, or bridging into a TaskPipeline via StepResult.fromInteraction).
  • sdk.query.* — read-only scene, inventory, bank, equipment, dialogue, minigame, or production state with fluent filters (see query-helpers.md`).

All write paths route through the same ActionPacer gate, maintaining consistent pacing across all surfaces (see sdk-pipeline-guide.md §2).