InteractionResult
InteractionResult is the standard return type for mutating action APIs. Its fields tell you what the runtime saw:
succeeded() and failed(). Never compare messages.
Status reference
The execution pipeline
A dispatched action is not proof the game state changed. Observe the expected widget, interface, or actor state on a later tick before your workflow advances.ActionResolver
ActionResolver matches menu actions and returns one-based RuneLite action indexes. It strips RuneLite text tags, trims whitespace, ignores null and empty actions, and matches case-insensitively.
ActionResolver.hasAction(...) inside query predicates instead of looping over action arrays yourself:
describeRequested(...) repeats the raw caller input in the message. Never index into composition action arrays with filtered-list arithmetic; sparse entity action arrays (for example Gemstone Crabs) break that assumption. Index directly into the raw array and clean values through ActionResolver.
Menu dispatch
com.n3plugins.PacketUtils.reflection owns native menu dispatch through MenuDispatcher. The production singleton, ReflectionMenuDispatcher, invokes the vanilla client’s static obfuscated menu-action method. It does not call an injected Client.menuAction(...) API method.
Current native-menu consumers:
WidgetActionsfor listener-backedCC_OPoperations.BankActions.close()for the client-local close operation.
Resolution and caching
The first dispatch for a client revision checks a disk cache at.runelite/cache/menu-action-plan.json. On a miss, MenuActionAsmResolver analyzes the runtime client bytecode with ASM data-flow analysis, accepting an invocation only when its descriptor reads exactly (IIIIIILjava/lang/String;Ljava/lang/String;II[BSIJ])V and every operand traces to a logical argument or a modeled transformation. Multiple calls, incomplete bindings, unsupported transformations, or descriptor drift fail closed.
Cache schema version 2 records the revision, source hook, bytecode fingerprint, descriptor, and typed bindings. A revision or fingerprint mismatch, malformed plan, or missing method invalidates the entry and triggers re-resolution. Cache writes are best-effort: a read-only home directory leaves ASM-resolved methods working, and the next start scans again. Delete the file to force resolution.
Failure semantics
ReflectionMenuDispatcher throws IllegalStateException when the client drops offline, resolution fails, or invocation fails. WidgetActions and BankActions convert that exception to PACKET_NOT_QUEUED and skip recording the action in the pacer.
Synthetic dispatch path
When synthetic mouse is enabled and the target projects onto the canvas, the runtime plans a humanized mouse path, installs a one-shot menu entry, and completes with a native canvas click. Otherwise dispatch goes straight through the reflection dispatcher. See the humanization and safety playbook for the synthetic input boundary.Menu entry snapshots (diagnostics only)
Thecom.n3plugins.sdk.menu package captures immutable snapshots of the client’s current menu entries for failure analysis:
entries() captures the current entries as an immutable list and returns an empty list when the client or entries disappear. firstMatching(option, target) matches normalized, case-insensitive text and treats a null argument as a wildcard. diagnostics() formats entries as option -> target strings for logging. Snapshots expose option, target, identifier, type, parameters, item ID, world view ID, and deprioritization state.
Blocking events
BlockingEventActions handles the blockers that appear before normal automation can run: the welcome screen, death dialogues, and viewport layout.
The class carries no credentials and performs no auto-login. In tests without RuneLite’s injector, client lookup fails closed with
CLIENT_NOT_READY.
Run blocker checks before your automation each tick. If a blocker appears, handle it and skip the rest of the tick so competing actions never queue:
setResizableMode(...) acts conservatively. Treat it as a state check and surface the failure to the operator when the layout is incompatible.