> ## Documentation Index
> Fetch the complete documentation index at: https://runelite.zip/llms.txt
> Use this file to discover all available pages before exploring further.

# Developer Tools

> Packet debugging, overlays, configuration, and shared UI utilities.

# Developer Tools

The Developer Tools plugin bundles packet debugging, overlay utilities, configuration helpers, and shared UI components for n3 plugin development.

:::info\[Verification boundary]

This page describes the committed source. It does not certify revision-sensitive RuneLite UI, packet, or in-game outcomes; treat those as live-client verification pending unless the page records direct evidence.

:::

## Packet Debugging

Packet Utils enables `PacketTrace` and `NativeActionTrace` for its runtime session and disables or clears them during shutdown. Both store bounded in-memory buffers. You can use their programmatic `setEnabled(...)` methods for focused tests and diagnostics, but Logger console visibility is not the capture lifecycle switch.

`PacketReflection.sendPacket(...)` is staged and fail-closed. Failures identify the first failed stage: mapping resolution, node creation, buffer resolution, payload write, or enqueue. The method returns a failed stage as `PacketSendResult`; it skips later stages.

`RevisionHealthCheck` is read-only, but PacketUtils uses its result as a start-up gate. It checks the live revision, reflection shapes, every production `PacketDef`, and the decoded fixed/variable packet length. It never downloads or repairs mappings. A passing result proves only those structural checks in the current process. Controlled live packet behavior remains separate evidence.

### Packet trace

```java theme={null}
PacketTrace.setEnabled(true);
List<PacketTraceEvent> events = PacketTrace.snapshot();
PacketTrace.clear();
```

Every packet event includes both the reflection packet identity and a stable semantic `actionType`. This keeps revision-specific names useful without making operators decode them to understand the action family. Current action types cover `CC_OP`, item, player, NPC, ground-item, game-object, widget-target, movement, mouse, dialog, continuation, and heading actions. For example:

```
[PACKET] PacketReflection EVENT_MOUSE_CLICK/bb action=MOUSE_CLICK [...]
[PACKET] PacketReflection IF_BUTTONX/bu action=CC_OP [...]
```

Packet Utils Logger displays the session-scoped packet/native capture owned by the centralized Developer Tools runtime. `PacketReflection.sendPacket(...)` records the returned staged result for mapping resolution, node creation, buffer resolution, payload writing, enqueue, and success without changing fail-closed send behavior. You observe native n3 invocations and RuneLite `MenuOptionClicked` events throughout the Packet Utils session, even while the Logger console is hidden. Native widget menu dispatches record their exact `MenuAction` such as `CC_OP`, option, operation index, widget index/ID, and item ID. RuneLite menu events retain option, target, `MenuAction`, identifier, and both parameters. Capture does not consume menu events or add client-thread dispatch.

The collapsed Packet Utils **Logging** section also provides disabled-by-default **Log client telemetry** and **Log spammy telemetry** settings. Client telemetry observes RuneLite-managed mouse, wheel, keyboard, focus, canvas-size, game-state, widget-drag, and client-tick callbacks. Mouse movement, mouse dragging, and client ticks require both settings; other telemetry requires only **Log client telemetry**. Each callback reads the current settings, so disabling telemetry takes effect without restarting Packet Utils. Typed characters are stored as `<redacted>`, while pressed and released key events retain their character metadata. Telemetry uses `ClientTelemetry` as its action source and `CONFIRMED` as its status.

Telemetry shares the 256-entry `NativeActionTrace` buffer and the existing chronological Logger and Agent Server rendering. High-frequency telemetry can therefore evict older native-action rows. It does not create a second buffer, consume input events, or write to the issued-action clipboard.

Native widget and bank-close operations reach the vanilla client through `ReflectionMenuDispatcher`. Its runtime resolver and disk cache operate independently of `PacketReflection.sendPacket(...)` and the offline artifact analyzer on this page. See [`menu-action-dispatch.md`](menu-action-dispatch.md).

Packet Utils exposes **Copy issued actions to clipboard**, which is disabled by default. When enabled, the plugin copies each `DISPATCHED` native/menu event in the same stable one-line shape used by the action logger. Walker NPC and object dispatches are captured directly as well, because reflection packet sends do not necessarily emit a RuneLite `MenuOptionClicked` event. NPC rows include the requested action, NPC name, definition ID, and current scene index. For example:

```
Walker.NpcAction [Travel, Primio, npcId=12888, index=27706] DISPATCHED - Queued NPC action
```

The plugin copies only issued/native actions recorded through the normal trace path and only when they have `DISPATCHED` status, so later success/confirmation trace events do not overwrite the issued-action evidence. Client telemetry uses a separate package-internal retention path and never reaches the clipboard sink. Clipboard ownership or headless runtime failures never change interaction results. Disabling the option stops clipboard writes without clearing Logger buffers.

Logger output is session-only and its console starts hidden whenever Packet Utils starts. You toggle it from the Developer Tools tab or the panel-less **Toggle Logger** client title-bar button. Both controls operate the same 220-pixel output console attached below RuneLite's existing content pane. The Developer Tools tab manages the minimum Logback level, Logback/Packets/Actions-and-Menus visibility, auto-scroll, and clear controls; the attached console remains output-only. Hiding Logger unmounts only the console; capture continues and the bounded session buffers remain available until you clear them or Packet Utils shuts down. Logger filtering never changes the global Logback threshold; the `::logger` command remains available for that separate purpose.

Scene geometry, Animation IDs, and the other render utilities remain RuneLite canvas overlays. ID Menu Option remains a RuneLite menu-event utility rather than rendering inside the attached console.

### Health check

```java theme={null}
HealthCheckResult result = RevisionHealthCheck.run();
log.info(result.toSummary());
```

Important entries include the live client/revision, mapping label, writer/factory/buffer shapes, enqueue and menu dispatch, and one length-validated entry for every mouse, movement, widget, object, NPC, player, ground-item, and dialog packet definition. The report flags deliberately unavailable packets as `UNSUPPORTED` and does not block otherwise healthy supported mappings.

## Revision 240 artifact analysis

Run the ASM analyzer with the exact injected client:

```powershell theme={null}
.\gradlew.bat analyzeRevision240 `
  -PinjectedClientJar=build\tmp\runelite-1.12.38-plan\injected-client-1.12.38.jar `
  --console plain --no-daemon
```

`-PvanillaGamepackJar=<path>` is optional and adds vanilla/injected inventory correlation; it does not supply or override injected-client mappings.

The tool writes the report to `build/reports/revision240/mapping-report.txt`. It records class inventories, Packet Utils core members, Profiles fields and account-mode constants, login index field/decoder/encoder, mouse timestamp fields, packet-node release, separate client-packet storage and packet-node length transforms, packet lengths, control-flow-bounded write sequences, derived byte transforms, operand provenance, client-packet call sites, exact reachable menu actions, and script-opcode predicates. Ambiguous write paths are reported separately and are not used as mapping evidence.

The launcher `RuneLite.jar` is not either analysis artifact. It contains `net.runelite.launcher.Launcher`. A modern five-class Jagex bootstrap jar is also not a decrypted vanilla gamepack and cannot provide vanilla-to-injected correlation.

Revision 240 dialog mappings are derived from the client script-opcode handler:

* 3104 count → `js.cy`, length 4
* 3105 name → `js.cz`, variable length
* 3106 string → `js.cb`, variable length
* 3115 object → `js.ab`, length 2

The project compiles against RuneLite `1.12.38` at revision 240. The supported packet catalog uses mapping label `2026-09-03-rev240-11238-release-artifact-derived`. RuneLite publishes the injected artifact at `https://repo.runelite.net/net/runelite/injected-client/1.12.38/injected-client-1.12.38.jar`; its SHA-256 is `7FDEDF1194261CC5B99FAA35E0D2B4E45B6D56665402CCBDE7F3AA6207C3F947`, and release commit `b505980edd4576104368874d4597bca7b7c463a1` identifies the matching source. The 2026-09-03 analyzer run confirmed revision 240. RuneLite 1.12.38 changes `PacketBufferNode.release()` from `jl.va(Ljl;)V` to `jl.hm(Ljl;)V` and changes the `getOpPlayerT` widget-parameter transform to `r 8,v,r 24,r 16`; the other packet construction, queue, profile, mouse, menu dispatcher, and production packet mappings remain artifact-compatible.

Upstream RuneLite 1.12.36 introduced `Widget.getSubOps()` directly on `net.runelite.api.widgets.Widget` (commit `6075cc4`). `WidgetPackets.resolveSubOps(Widget)` inspects `widget.getSubOps()` first before falling back to `ItemComposition.getSubops()`, ensuring non-item widgets (such as portal configurations and dialogue menus) properly resolve sub-actions for `IF_SUBOP` dispatch.

The artifact pass derives all 39 production packet rows. It includes inlined and static-helper buffer writes, exact menu-action reachability, the `js.da` movement payload, `getOpPlayerT` bytecode transform `r 8,v,r 24,r 16` for widget parameters, and `SET_HEADING` as `js.ed` with transform `a 128`.

The user confirmed on 2026-08-26 that the rebuilt n3Plugins artifact launches in the current RuneLite 1.12.37 client. This confirms launch compatibility. Revision-health output, mapping-label health, packet behavior, complete plugin discovery, and shared-sidebar initialization still require direct observation.

Production code contains no Java constants class for obfuscated names. The artifact-backed values live in `src/main/resources/com/n3plugins/PacketUtils/reflection/revision-mappings/rev240.properties`. `RevisionMappings.load(revision)` first checks the local cached evidence file at `~/.runelite/cache/revision-evidence-240.json`. When the local cache exists and matches the expected schema, revision, and mapping label, it loads directly from the local cache. If the local cache is absent or drifted, `loadBundled(revision)` reads the bundled properties from `openOwnedResource` (which directly inspects the sideloaded suite `~/.runelite/sideloaded-plugins/n3Plugins.jar` and code source jar), parses properties with UTF-8 BOM safety, and writes the verified local cache to disk. `Revision240ArtifactTest` verifies packet transforms and operand provenance; it does not guess them at runtime.

### Maintaining mappings for a RuneLite update

Treat the revision properties resource and production packet catalog as outputs of artifact-backed analysis, not constant-pool guesses. For a new revision:

1. Save the exact released injected-client artifact under `REFERENCE_RESOURCES/injected_clients/` and record its provenance.
2. Run the revision analyzer against that artifact. The current task is `analyzeRevision240`; a new revision needs an equivalent explicit analysis target rather than silently reusing revision 240 assumptions.
3. Review `mapping-report.txt`, update only properties supported by bytecode and call-site evidence, and leave ambiguous packets unsupported.
4. Run `Revision240ArtifactTest` (or the new revision's equivalent), the reflection/Profile suites, and the normal build.
5. Perform controlled in-client checks for every changed packet family before declaring the mapping production-ready.

### Evidence boundaries

* Analyzer and artifact tests prove bytecode structure in the supplied artifacts.
* Unit tests prove staged failure propagation and catalog consistency.
* You need a decrypted vanilla gamepack for true vanilla/injected correlation.
* You need in-client tests for mouse, movement, widget, object, NPC, player, ground-item, dialog, and sailing behavior.

## Overlays And Config

### Config keys

* `copyIssuedActionsToClipboard`: disabled by default; copies dispatched SDK/RuneLite actions to the system clipboard without changing action acceptance or Logger retention. Walker NPC output includes NPC ID and live scene index.
* `logClientTelemetry`: disabled by default; records observational mouse, keyboard, focus, canvas-size, game-state, widget-drag, and non-spammy client events in the existing bounded action trace.
* `logSpammyTelemetry`: disabled by default and subordinate to `logClientTelemetry`; additionally records mouse movement, mouse dragging, and client ticks.

You access the **Developer Tools** tab via Packet Utils without duplicating its controls in Main Settings. The tab renders `DevToolsConfig` settings for the Swing inspector hotkey and notifications, followed by the developer utilities. Overlay buttons like Animation IDs render through RuneLite's canvas overlay manager. ID Menu Option remains a right-click menu helper.

The distributed fat JARs must contain `FlatInspector` and `FlatUIDefaultsInspector` from FlatLaf Extras while leaving FlatLaf core to RuneLite. Packaging coverage enforces this boundary. The Swing Inspector and Swing Defaults controls were live-confirmed functional with the rebuilt normal fat JAR on 2026-08-16.

The Developer Tools tab provides opt-in mouse recording, analysis, derived profile saving, selected-widget path preview, and cancellation. The plugin stores raw sessions below `n3/mouse/recordings/<profile-id>/` and derived statistics-only profiles below `n3/mouse/profiles/`. The synthetic-mouse overlay renders a bounded planned/traversed path, target bounds, landing point, and recorder indicator through the normal overlay lifecycle. It starts no animation thread. `Record mouse menu metadata` is disabled by default; the plugin never records keyboard and n3 synthetic events, and it emits menu context as a separate semantic recording row rather than attaching it to physical input.

Logger visibility and filtering are session-only utilities rather than persisted Packet Utils config items. Use its tab controls to select the displayed Logback level and source streams; you toggle the same Logger state via the client title-bar button. Packet trace, native-action, and menu capture are enabled for the Packet Utils runtime session. The persisted telemetry settings only control whether observational client callbacks join the existing action trace. Toggling Logger changes console visibility, not capture lifetime.

### Overlay utility

`OverlayUtils.drawTile(...)` centralizes scene tile drawing.

```java theme={null}
OverlayUtils.drawTile(client, graphics, point, Color.MAGENTA, 25, "1", new BasicStroke(1));
```

#### Guidelines

* Keep overlay utilities rendering-only.
* Keep plugin state in the plugin or action layer.
* Add new overlay helpers only when a concrete overlay needs them.

### Shared panel UI

Use `com.n3plugins.ui` for shared n3 plugin panel styling:

* `N3Theme` defines the amber suite accent `#F59E0B`, shared foreground colors, borders, and dark card backgrounds.
* `Section` renders rounded dark cards and supports an optional description line under the amber section title.
* `N3PluginPanel.addAction(...)` creates styled `N3Button` pill buttons. The first panel action is primary and uses amber text.
* `HeaderPill` draws the bundled n3 brand icon before the plugin name, while preserving the amber pill, status dot, and status string behavior.

### Brand image resource

`src/main/resources/com/n3plugins/ui/brand/n3.png` is the packaged n3 brand asset. Runtime code must load it from the jar through `com.n3plugins.ui.brand.N3Branding`. Do not depend on any machine-local image after build.

### Plugin-list branding

The pinned RuneLite 1.12.38 API still does not expose an icon field on `@PluginDescriptor`. The plugin list uses a small Swing decorator:

* `PacketUtilsPlugin` owns `N3PluginListBranding` as shared runtime setup.
* The decorator runs on the Swing EDT with a timer, scans visible windows for `net.runelite.client.plugins.config.PluginListItem` labels, detects the `[n3]` marker, applies the scaled bundled icon, strips the visible marker, and marks decorated labels with client properties.
* Shutdown stops the timer and restores any still-visible decorated labels to their original text/icon state.

### Validation notes

* Automated tests cover image loading/scaling and Swing component-tree decoration, double-decoration avoidance, and restore behavior.
* Manual RuneLite validation is required for plugin-list refresh/search, tooltips, pinned plugin behavior, and in-panel visual quality.
