Skip to main content

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

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 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. 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:
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

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:
-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.

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.