Skip to main content

Widget And Item SDK APIs

Verification boundary

This page documents the committed source. Treat revision-sensitive RuneLite UI, packet, or in-game outcomes as pending live-client verification unless the page records direct evidence.

com.n3plugins.sdk.widgets contains lower-level widget and item helpers used by workflow builders, and plugin runtimes. These helpers are packaged SDK utilities, not RuneLite plugins.

Use the result-aware Api.actions.* classes when you need detailed failure statuses. Use these SDK APIs when a boolean/query surface is enough or when you are implementing a workflow Services adapter.

Core Widget API

Widgets is the raw widget boundary.

WidgetCatalog is the revision-aware name and address index. It loads current gameval InterfaceID declarations plus deprecated RuneLite WidgetID and WidgetInfo declarations from widget_mappings_2026-09-03-rev240.tsv. The resource header pins RuneLite 1.12.38, game revision 240, and upstream commit b505980edd4576104368874d4597bca7b7c463a1. findExact, search, findByPackedId, findAliases, and findByViewMode are discovery operations. resolveAddress and requireAddress fail closed for ambiguous, incomplete, or reference-only targets. A reference-only or LIVE_PENDING declaration can resolve only when its packed target also has a current authoritative actionable mapping.

WidgetMapping exposes the qualified name, namespace, raw and decomposed values, mapping kind, view mode, authority, aliases, disposition, and live status. WidgetAddress is the complete actionable group/child target with an optional dynamic index. Current gameval mappings outrank deprecated reference declarations; source consistency is not live evidence.

Packed widget IDs in production code should come from a safe catalog address via WidgetCatalog.resolveAddress(...) / requireAddress(...), or from current RuneLite gameval InterfaceID / generated ComponentID constants. The SDK no longer ships a local monolithic widget-index class. Do not turn a searchable reference-only raw value into an action target without live evidence.

Catalog methods:

  • getInstance()
  • getMappings()
  • findExact(String)
  • search(String)
  • findByPackedId(int)
  • findAliases(String)
  • findByViewMode(WidgetViewMode)
  • resolveAddress(String) / requireAddress(String)

Widgets methods (reads):

  • get(packedId), get(groupId, childId), get(WidgetAddress)
  • search()

Raw widget writes live in WidgetActions: click(), interact(...), interactOnWidget(source, destination), clickOp(...), and the resumePause / resumeCount / resumeString / resumeName input primitives.

Tests inject a mock client with Widgets.setClientForTesting(client) and restore it with Widgets.resetClientForTesting().

Inventory And Item Entries

Inventory exposes inventory reads and item-widget actions:

  • getItems()
  • find(itemId)
  • count(itemId)
  • contains(itemId)
  • getEmptySlots()

Inventory writes belong in Api.actions.InventoryActions / UseItemActions.

ItemEntry is the value type returned by inventory, bank, shop, and GE helpers. It carries itemId, name, quantity, and the backing Widget. Calling interact(actions...) dispatches to the backing widget.

Production / Make-X / Smithing Reads

Production is the read-only side of the Make-X and legacy Smithing (Group 312) interfaces. It mirrors the useful read affordances exposed by bot-client production helpers without moving gameplay writes out of Api.actions.production.ProductionActions.

Use it to inspect the current interface before deciding which result-aware action to queue:

if (Production.isOpen()) {
Optional<ProductionProduct> shortbow = Production.findProduct("Shortbow");
Optional<ProductionQuantity> quantity = Production.selectedQuantity();

shortbow.ifPresent(product -> log.debug(
"Make option {} at child {} exposes actions {}",
product.getName(),
product.getChildIndex(),
product.getActions()));
}

Methods:

  • isOpen()
  • isEnterInputOpen()
  • products()
  • findProduct(itemId) and findProduct(name)
  • selectedProduct()
  • quantityButtons()
  • quantityButton(quantity)
  • selectedQuantity()
  • makeXQuantity()

ProductionProduct carries the one-based visible option index, item ID, product name, packed widget ID, child index, selected-state heuristic, visible action labels, and backing widget. ProductionQuantityButton carries the ProductionQuantity, packed widget ID, child ID, text, visibility, selected-state heuristic, and backing widget.

Product names are the item/widget names displayed by the Make-X interface. Some interfaces show an ingredient or intermediate widget name that is not exactly the item eventually produced. Selected product and selected quantity are widget-state heuristics and remain live-verification pending on the target RuneLite revision.

Writes still belong in ProductionActions:

InteractionResult result = ProductionActions.selectQuantity(ProductionQuantity.ALL);
if (result.succeeded()) {
result = ProductionActions.chooseOption("Shortbow");
}

Minigame / Grouping Reads

Minigames reads both minigame teleport entry surfaces. Grouping uses destination group 76, dropdown widget 4980747, and final teleport widget 4980768. Magic uses spell widget 14286855 and destination rows under group 951; selecting a Magic destination row performs the teleport. Teleport writes stay in Api.actions.minigame.MinigameTeleportActions.

MinigamesSnapshot snapshot = Minigames.snapshot();
if (snapshot.canTeleport()) {
Minigames.destination(MinigameTeleport.PEST_CONTROL)
.filter(MinigameTeleportOption::isVisible)
.ifPresent(option -> log.debug("Teleport widget {}", option.getWidgetId()));
}

Methods:

  • snapshot()
  • isOpen()
  • canTeleport()
  • cooldownValue()
  • lastTeleportUsage()
  • destinations()
  • destination(destination)
  • selectedDestination()

MinigamesSnapshot exposes whether the interface is open, which entry surfaces are open, whether the Grouping dropdown is expanded, whether the cooldown varbit currently permits teleporting, the raw cooldown varbit value, the raw last-teleport varplayer value, and destination button snapshots.

MinigameTeleportOption carries the destination enum, display name, packed widget ID, child ID, dynamic widget index, visibility, selected-state heuristic, and backing widget. Grouping selected-state comes from the collapsed selector; Magic destination rows are live rows and do not use the Grouping selector.

Bank And Equipment

Bank (sdk.query) owns bank reads and typed state; BankActions (Api.actions) owns writes. Bank reads:

  • isOpen()
  • getItems()
  • search()
  • count(itemId)
  • isNotedMode()
  • setWithdrawMode(noted) (write through BankActions.ensureWithdrawMode)

BankActions writes:

  • withdraw(itemId, amount), withdrawNoted(itemId, amount)
  • withdraw(InventoryLoadout) and withdraw(loadout, maxActions)
  • depositInventory(), depositEquipment()

Bank also exposes the typed bank state reads and stable widget descriptors so SDK callers do not need raw varbits or packed widget IDs:

  • snapshot()
  • withdrawMode() returning BankWithdrawMode
  • requestedQuantity()
  • placeholderMode() returning Optional<BankPlaceholderMode>
  • rearrangeMode() returning Optional<BankRearrangeMode>
  • supportedWidgets() and supportedWidget(name) returning BankWidget

BankWidget wraps the supported bank widget descriptors backed by current catalog addresses, including deposit inventory/equipment, equipment/settings buttons, containers, tabs, and scrollbar descriptors. Gameplay-changing clicks still belong in BankActions.click(BankWidget) or the existing result-aware bank actions.

Equipment exposes equipped item reads:

  • getItems()
  • get(slot)
  • isEquipped(itemId)

EquippedItem carries itemId, name, slot, and an optional backing Widget. Live equipment reads include the backing widget for interactions; snapshot-only test entries may leave it null.

Dialogue

Dialogue (sdk.query) exposes the read surface:

  • isPresent()
  • getHeader(), getText(), getOptions()
  • getContinueWidget()
  • snapshot()

Dialogue writes live in Api.actions.DialogActions: continueDialogue(), selectOption(indexOrText), selectOptionByIndex(index), resumeNumericInput(amount), resumeStringInput(value), resumeNameInput(value), plus the result-aware chooseOption / continueSpace / enterAmount family.

DialogueSnapshot logs whether dialogue is present, whether a continue prompt is visible, the header/body text, and parsed options. DialogueOption contains the option index, widget ID, stripped text, and text color.

For dialogue actions and the auto-continue plugin, see dialogue-helper.md.

Shop And Shop Inventory

Shop and ShopInventory (sdk.query) read the shop stock and the player's inventory panel while the shop interface is open. All shop buys belong in Api.actions.ShopActions: buyOne, buyFive, buyTen, buyFifty, and the result-aware buy(...) family. ShopBuyQuantity maps the SDK enum values to shop action strings through getAction().

For the result-aware shop actions, see shop.md.

Grand Exchange Inventory

GrandExchangeInventory (sdk.query) reads the inventory panel while the Grand Exchange interface is open. Offering items belongs in Api.actions.GrandExchangeActions.

For GE interface state and standalone GE actions, see grand-exchange.md.

Rune Pouch

RunePouch reads rune-pouch contents:

  • contains(itemId)
  • containsAll(itemIds)
  • hasAmount(itemId, amount)
  • quantity(itemId)

Magic/enchanting flows use it to decide whether inventory runes are still required.

Testing

Query classes expose test seams instead of adapters: Widgets.setClientForTesting(client), Bank.setClientForTesting(client), plus the setTestHooks(...) / resetTestHooks() pairs on Inventory, RunePouch, Production, Minigames, and Bank. Dialogue and widget write packet primitives are observable through WidgetActions.setResumePacketHooksForTesting(...) and WidgetActions.setDispatchHooksForTesting(...). Use those hooks in tests; do not mock static methods. This matches the suite rule in AGENTS.md (Section 11) that Mockito static mocking is not available in this project. See also BUILD_TEST_MATRIX.md for the full test standards.