Query helpers
Start from a static container and chain filters:
Common filters:
withAnyAction, withoutAction, nameContainsIgnoreCase, withTextContainsIgnoreCase, idIn(Collection), withMappedName(String) (item, NPC, tile objects), exists, count, single, limit, sorted, walkable (tile objects and ground items), and geTradeable. StringMatchers centralizes tag-stripping and case-insensitive matching.
- Never use
first()as a nearest-target policy. Scene collection order is not a distance ranking. Usewalkable().nearestToPoint(anchor)for a stable work area ornearestByPath()for the shortest reachable target from the player. - Name predicates strip tags for you. Inventory and equipment widgets return styled names like
<col=ff9040>Steel axe</col>; pass bare strings. - Mapped names resolve through
IdMapRegistry. A mapped base name such asAncient sceptrematches its released variants. Item name filters fall back to the item-definition API when a widget carries only an ID. geTradeable()is the market filter. The oldertradeAble()remains for source compatibility and delegates to it.ItemContainers.search(...)snapshots any container as immutableContainerItemvalues. Each call copies live state; take a freshsearch(...)per independent assertion.ProjectileQueryandGraphicsObjectQuerysnapshot on everysearch()rather than tick-caching. Reuse one query object to chain filters within a tick.
Event snapshots
com.n3plugins.sdk.events exposes passive, bounded recent-event snapshots. Packet Utils registers SdkEvents with the RuneLite event bus during startup and unregisters it at shutdown; consumers read snapshots and never own the bus wiring.
Snapshots carry client tick and wall-clock timestamps. The tracker retains up to 128 events per kind. Inventory-delta cursors must be persisted once per observation cycle;
isGapDetected() means output may have been lost and requires resynchronization. Login, hop, and connection loss clear retained item deltas without resetting the sequence, so an old cursor never matches a later session. Unknown containers stay distinct from known-empty ones.
Scenario and replay foundation
The same package carries the offline simulation foundation used by tests and tooling:EventEnvelope<T>carries a stable payload, deterministic sequence and tick metadata, and source provenance.StimulusDispatcherroutes envelopes to the first supportingStimulusHandlerunder an explicitDispatchMode(SYNC,ASYNC,DRY_RUN), deduplicating by event ID per session.ScenarioRunneroperates tick-driven: dispatch once, then verify state on later ticks. Posting an event never counts as proof the target processed it.EventReplayServicereplays a recordedEventTimelinethrough the dispatcher under aReplayPolicy.StateFixtureServicemanages named state fixtures with atomic apply/rollback for deterministic scenario setup.
Utility actions
UtilityEventActions collects one-shot utility writes:
All methods are result-aware. Handle the
toggleAcceptAid failure explicitly rather than assuming the setting changed.
Game variables
GameVars (com.n3plugins.sdk.client) reads raw varbits and varplayers without Api dependencies:
getVarbit(id)andgetVarPlayer(id)return 0 when the client reads null.getVarPlayerBit(id, bitIndex)returns false when the client reads null.
net.runelite.api.Varbits and VarPlayer constants as arguments. Revision-pinned named identifiers live in the suite’s GameVarsRegistry, which DevTools and rune-pouch consumers use instead of local constants classes.
ID maps
IdMapRegistry (com.n3plugins.sdk.idmaps) loads generated item, NPC, and object name/ID lookups. Bundled maps ship on the classpath; a complete revision cache under .runelite/n3Plugins/id-maps/rev-<revision>/ takes precedence when its manifest matches the active client revision.
ItemQuery.withMappedName(...), NPCQuery.withMappedName(...), and TileObjectQuery.withMappedName(...) resolve IDs through the registry and filter by ID, including RuneLite item variation groups for the current release. Refreshes happen through imports: after generating fresh JSON map files, IdMapRegistry.importGenerated(...) validates and copies them into the revision cache with a manifest. No startup scraping or external scripts are involved.
Progress reads
com.n3plugins.sdk.progress provides read-only quest and achievement-diary progress. These APIs read eligibility state; they do not perform quest steps or claim rewards.
QuestProgressApi
state(quest), isStarted(quest), isComplete(quest), progress(quest or name), all(), started(), completed(), findQuest(name) (normalized, punctuation-insensitive matching), and satisfies(requirement) for walker quest requirements.
DiaryProgressApi
progress(region, tier), all(), forRegion(region), tasks(region, tier), isComplete(task), and progress(task). Coverage is intentionally partial: the API exposes only explicitly mapped varbit and varplayer-backed tasks and never guesses unmapped ones.