Packet Debugging
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.
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 startup 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:
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.
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:
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:
.\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:
- Save the exact released injected-client artifact under
REFERENCE_RESOURCES/injected_clients/and record its provenance. - 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. - Review
mapping-report.txt, update only properties supported by bytecode and call-site evidence, and leave ambiguous packets unsupported. - Run
Revision240ArtifactTest(or the new revision's equivalent), the reflection/Profile suites, and the normal build. - 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.