Tutorial Island
TutorialIslandPlugin automates Tutorial Island start to finish. The manifest
registers it under config group n3tutorialisland; the plugin ships disabled by
default.
Architecture
TutorialIslandPlugin- lifecycle, overlay and side-panel registration, debug-stepping hotkeys, delegates each tick to the controller, exposes the latest snapshot.TutorialIslandController- pure per-tick decision tree; at most one action per tick. Holds varp tracking, fixed-sequenceTaskPipelines, halt state, the per-account seed/profile, and manual step state.TutorialIslandRuntime- interface that isolates every RuneLite/SDK read and action from the controller, so controller logic stays unit-testable.RuneLiteTutorialIslandRuntime- live adapter implementing the runtime againstInteractionApi,sdk.query,sdk.client, and the walker.TutorialStage- enum plus the purefromVarp(int)mapping from progress varp to a named stage.TutorialConstants- widget/object IDs, NPC/object names, the step-to-tab map, and area bounding boxes.TutorialAccountProfile- pure, seeded per-account profile: gather targets, appearance click counts, and action-gap ticks.TutorialNameGenerator- seeded name generator with username-file and CSV word-list inputs (ported from the AIOAccountNameGenerator).TutorialIslandSnapshot- immutable overlay-safe view of stage, varp, status text, halt reason, manual mode, gather targets, and the chosen username.TutorialIslandOverlay- brandedN3Overlayrendering the snapshot.TutorialIslandPanel- brandedN3PluginPanelwith Step Action, Step Stage, and Resume controls.UsernameGenerator- the original random name generator; retained with tests but no longer used by the controller (superseded byTutorialNameGenerator).
Core behavior
onGameTick calls TutorialIslandController.onGameTick() and stores the
returned snapshot. The global ActionPacer and Walker advance from
PacketUtilsPlugin.onGameTick; see Suite Wiring.
The plugin registers with Break Handler and is active there only while auto mode
is running, the tutorial is incomplete, and the controller is not halted. Manual
step mode stops break tracking; Resume re-enters active break tracking. A due
or active break releases the input lock and skips the controller tick before any
tutorial action.
Progress is driven entirely by varp 281 (TutorialConstants.VARP_TUTORIAL_PROGRESS):
- Read the current varp each tick.
- On a varp change, reset fixed-sequence pipelines and log the transition when
debugLoggingis on. - Map the varp to a
TutorialStagevia the pureTutorialStage.fromVarp. - Dispatch the stage to its handler, which performs at most one interaction.
The stage advances only as a function of varp change, never on a timer. A varp
of 1000 or higher maps to COMPLETE. Several raw values collapse to the same
stage (for example 20 and 60 both map to SURVIVAL_TALK); the switch in
fromVarp is the authority for that mapping.
Stage flow
fromVarp covers the full tutorial in order: name entry and appearance,
Gielinor Guide, Survival Expert (woodcutting, fishing, firemaking, cooking),
Master Chef (dough, bread), Quest Guide, mining and smithing, the Combat
Instructor (melee then ranged on rats), bank and poll booths, the Account Guide,
Brother Brace (prayer), and the Magic Instructor (cast Wind Strike on a
chicken), ending in COMPLETE.
Two stages need a runtime decision the varp alone cannot give:
- varp
1returnsNAME_ENTRY; the controller switches toAPPEARANCEwhen the appearance arrows are already on screen. - varp
650returnsCAST_WIND_STRIKE; the controller casts whenever a chicken is in range and only walks toward the cast area when none is found (cast-first, no hard area gate).
Sub-steps split across ticks
Some stages spread work over several ticks to keep one action per tick:
- Name entry: click field, type username, look up name, set name. The three button clicks fire via raw op-1 (see "Interface clicks" below).
- Appearance: click each arrow group a seeded number of times (
TutorialAccountProfile.appearanceClicksForArrow), then confirm. - Ranged setup: continue dialogue, open inventory, wield shortbow, wield arrows, attack.
- Equipment stats: open the equipment tab, click the stats panel (raw op-1), then wield the dagger.
The fixed-order sequences above are driven by TaskPipeline; transient InteractionResult
statuses such as pacing or temporarily missing widgets retry the current step and do not
advance it. Observation loops such as dialogue, gathering, walking, and casting remain
plain per-tick handlers because the live tutorial varp and game state own their progress.
Before dispatch, TutorialIslandController drains any visible Continue prompt or dialogue
option. This includes the rev-239 packed Continue widget 12648448 (193:0), whose live
adapter uses a direct widget interaction after the normal lookup and recursive widget-root
fallbacks. Every issued action is recorded with its returned InteractionStatus; paced,
temporarily missing target/widget, and movement-in-progress results retry, while terminal
results halt with the stage, varp, action, status, and target in the snapshot/log.
Interface clicks (raw op-1)
Several Tutorial Island interface components carry no named menu action - the name
field, the "look up"/"set name" buttons, the smithing dagger entry, and the worn-equipment
stats button. The action-name path (WidgetActions.interact(...)) resolves the action
string to a 1-based op index and fails with ACTION_NOT_FOUND when there is none, so those
clicks silently never queued. The controller now calls runtime.clickWidgetOp1(group, child)
for them, which maps to WidgetActions.clickOp(packedId, 1) and fires op-1 directly, bypassing
action-name resolution. The op index is assumed to be 1 for each; confirm on a live run.
Doors and walk-before-talk
Room transitions go through walkOpeningDoors(area): when the player is outside the target
area and the collision walker has pulled up stationary adjacent to an object exposing an
"Open" action, it opens that object once; otherwise it walks toward the area. Door state is
reset only when the tutorial varp changes, so a visible door cannot be toggled repeatedly.
The helper covers the Survival Expert, Master Chef, Quest Guide, Brother Brace, and Magic
Instructor approaches. The saved Quest Guide anchors remain (3072,3090,0) → (3086,3126,0);
the house door is 9716 and the outer tutorial door is 9710.
Talk stages that can be reached from out of range (SURVIVAL_TALK, QUEST_GUIDE_TALK,
COMBAT_TALK, COMBAT_TALK_2, BROTHER_BRACE_TALK) go through walkToOrTalk(npc): talk when
the NPC is reachable, otherwise step toward its location first.
Making bread dough (MAKE_DOUGH) is guarded: it skips when Bread dough is already in the
inventory or the player is animating, which prevents repeated flour/water combines on every
tick. The item names (Pot of flour, Bucket of water) are best-effort for the current rev.
Halt conditions
The controller halts when it cannot make progress:
- The name/appearance widget stays absent for more than 20 ticks.
- An
UNHANDLEDvarp persists for more than 60 ticks. - The walker reports
PATH_NOT_FOUNDfor the mining area.
Reaching COMPLETE also stops the controller, with no halt reason set. The halt
reason surfaces in the overlay snapshot.
Per-account seed and profile
On the first logged-in tick the controller derives a per-account seed and builds a
TutorialAccountProfile. The seed comes from seedOverride when non-zero,
otherwise from a SplitMix64 mix of the account key (client.getUsername(),
falling back to the local player name). The profile draws gather targets,
appearance click counts, and action-gap ticks from that seed, so the same account
always produces the same character and gathering pattern while different accounts
diverge.
actionGapTicks() returns 0 to 2 extra idle ticks inserted before each dispatched
action in auto mode, so dispatch cadence varies per account.
Multi-gather
Each gathering skill can over-collect before the tutorial advances. The controller
gates woodcutting, fishing, and mining on inventoryCount against the profile's
seeded target, not a simple "has one" check:
- Woodcutting (
handleWoodcutting, varp70): visible dialogue is drained before the chop gate, then the player keeps chopping untilLogsreacheschopTarget. The pure-talk varps20/60use the separate talk-onlyhandleSurvivalTalkand never chop (chopping at varp60soft-locked the talk that advances60->70). - Fishing: nets until
Raw shrimpsreachesfishTarget. - Mining: mines until
Tin ore/Copper orereachesmineTarget.
With a skill's toggle off the target is fixed at 1, matching the original collect-one-then-advance behaviour.
Multi-gather assumes the tutorial varp does not force-advance after the first resource pickup. Confirm on a live run; if the varp advances mid-gather, the count gate is moot and the over-collection will not happen.
Debug stepping
The controller runs in NORMAL or MANUAL mode. In manual mode it pauses before
each dispatch and the status reads Paused (manual). Three hotkeys and three panel
buttons drive it:
- Step Action (
stepActionHotkey): dispatch exactly one action, then pause. - Step Stage (
stepStageHotkey): keep dispatching until the tutorial varp changes, then pause. - Resume (
resumeHotkey): leave manual mode and dispatch automatically.
Set startPaused to begin in manual mode. The per-account action gap applies only
in auto mode.
Username generation
TutorialNameGenerator.generate(seed, pool, prefixes, suffixes) picks one of four
seeded strategies: a direct pool pick, prefix+suffix+number, prefix+number, or
suffix+number. Empty word lists fall back to bundled defaults. parseWordList
splits the CSV config values; loadUsernamePool reads one name per line from the
username file, skipping blank lines and # comments, and returns an empty list on
any read error. The controller seeds generation with the account seed, so a given
login reproduces the same name.
UsernameGenerator.generate(Random) (the original generator) stays in the tree with
its tests but the controller no longer calls it.
Branding
The overlay extends N3Overlay and the side panel extends N3PluginPanel, so both
carry the amber n3 brand pill and status dot. The plugin registers a
NavigationButton with a deliberately blank icon from TutorialIslandPlugin.navIcon()
- a transparent 16×16
BufferedImagewith no reference toN3Brandingorn3.png. The nav button does not load the n3 logo: the earlierN3Branding.scaledLogo(16)call ran insidestartUp()and throwsIllegalStateExceptionon any brand-asset load/decode failure, which RuneLite treats as a failed plugin start. Loading a blank icon keeps start-up safe (NavigationButton.builder()still requires a non-null icon atbuild()). The plugin-list[n3]marker (N3PluginListBranding) and the panel header logo (HeaderPill) are unaffected - both already degrade safely on asset failure. The panel's Step Action, Step Stage, and Resume buttons call the matching controller delegates, andrefreshUipushes each tick's snapshot to the panel.
Configuration
Config group n3tutorialisland:
showOverlay- show the status overlay (default true).debugLogging- log stage transitions and unhandled varp values (default false).
Multi-gather section:
chopMultiple,fishMultiple,mineMultiple- enable over-collection per skill (default false).multiGatherMin,multiGatherMax- inclusive bounds for the seeded gather target (default 2 and 5).
Debug stepping section:
startPaused- begin in manual mode (default false).stepActionHotkey,stepStageHotkey,resumeHotkey- manual stepping hotkeys (default unset).
Identity section:
usernameFile- absolute path, or a file under~/.runelite/n3Plugins/tutorialisland/.namePrefixes,nameSuffixes- comma-separated word lists for generated names.seedOverride- fixed per-account seed; 0 derives the seed from the account name.
ID verification
The IDs in TutorialConstants were checked against the rev238 gameval
sources. These are confirmed:
| Constant | Value | gameval authority |
|---|---|---|
VARP_TUTORIAL_PROGRESS | 281 | VarPlayerID.TUTORIAL |
NAME_WIDGET_GROUP | 558 | InterfaceID.TUTORIAL_DISPLAYNAME |
NAME_INPUT_CHILD | 6 | Live-verified display-name entry component on rev239 |
NAME_TEXT_CHILD | 12 | TutorialDisplayname.NAME_TEXT (0x022e_000c) |
NAME_LOOKUP_CHILD | 18 | TutorialDisplayname.LOOK_UP_NAME (0x022e_0012) |
NAME_SETNAME_CHILD | 19 | TutorialDisplayname.SET_NAME (0x022e_0013) |
APPEAR_PARENT_GROUP | 679 | InterfaceID.PLAYER_DESIGN |
APPEAR_ACCEPT_CHILD | 74 | PlayerDesign.CONFIRM (0x02a7_004a) |
FAMILIARITY_WIDGET_GROUP | 929 | Live-verified Past Experience interface on rev239 |
FAMILIARITY_EXPERIENCED_CHILD | 7 | Live-verified Experienced player option with Select action |
SMITHING_WIDGET_GROUP | 312 | InterfaceID.SMITHING |
SMITHING_DAGGER_CHILD | 9 | Smithing.DAGGER (0x0138_0009) |
EQUIP_STATS_WIDGET_GROUP | 387 | InterfaceID.WORNITEMS |
EQUIP_STATS_CHILD | 1 | Wornitems.EQUIPMENT (0x0183_0001) |
DIALOGUE_WIDGET_GROUP | 219 | InterfaceID.CHATMENU |
RAT_GATE_OBJECT_ID | 9719 | ObjectID.NEWBIEDOOR5_L |
The original plugin shipped the four name/appearance child indices wrong
(NAME_TEXT_CHILD, NAME_LOOKUP_CHILD, NAME_SETNAME_CHILD, APPEAR_ACCEPT_CHILD);
they were corrected to the gameval values above.
Tutorial Island has no account-bootstrap integration. Bootstrap requires side tabs that the tutorial has not unlocked yet and would prevent controller ticks, including manual Step Action requests.
Still unconfirmed, pending a live run with the widget inspector:
POLL_WIDGET_GROUP = 229isInterfaceID.MESSAGEBOX, a generic message box;POLL_WIDGET_CHILD = 1is unverified.- Area bounding boxes in
TutorialConstants. - Op index 1 for the actionless interface clicks (name field/lookup/set-name, smithing dagger, equipment stats).
- Object and NPC names (
Tree,Fire,Range,Furnace,Anvil,Gate, and the rest). The post-2023-07-12 tree rename did not touch the tutorial, but confirm the names resolve.
The TAB_FOR_STEP step-to-tab map was realigned 2026-05-31 to the canonical
varp 281 sequence: 3→Settings,
30→Inventory, 50→Skills, 230→Quests, 390→Equipment, 430→Combat, 560→Prayer,
580→Friends, 630→Magic. The talk-only steps 530/532 were removed from the map. 531
("open the account-management tab") stays mapped to Tab.LOGOUT as a best-effort placeholder
because the Tab enum has no account-management value - confirm this one on a live run.
Testing
JUnit 4 tests cover the package, including controller result/retry and door-transition tests:
TutorialStageTest- the fullfromVarpmapping (including varps200,671,680), theCOMPLETEthreshold, andUNHANDLEDdefaults.TutorialConstantsTest- pinsTAB_FOR_STEPto the canonical varp 281 tabs and asserts the talk-only steps530/532are absent.UsernameGeneratorTest- length, digit placement, reproducibility, variation.TutorialAccountProfileTest- seeded gather targets, min/max bounds, toggle-off pinning, action-gap and appearance-click bounds, per-account variation.TutorialNameGeneratorTest- the four strategies, reproducibility,parseWordList, andloadUsernamePool.TutorialIslandControllerTest- multi-gather gating, manual step mode, seeded name generation, raw op-1 interface clicks (smithing/equipment/name field), walk-before-talk when an NPC is unreachable, the talk-only Survival Expert handler not chopping at varp60, the make-dough guard, and cast-first Wind Strike, driven throughFakeTutorialIslandRuntime.TutorialIslandPluginTest- the nav-button icon seam:navIcon()is non-null, 16×16TYPE_INT_ARGB, and never throws (independent ofn3.png).
The raw op-1 helper itself is covered by WidgetActionsTest (null-widget and hidden-widget guards on clickOp).
FakeTutorialIslandRuntime implements the runtime interface with mutable read
fields and recorded actions, so the controller is tested with no MockedStatic.
GameStateGuard reads the client via N3Client.getClient(), which returns null
in the test JVM.
Live validation (pending)
Name entry and appearance, every guide and skill station in fromVarp order,
the melee and ranged rat fights, bank and poll booth use via hint arrows, the
prayer and magic stations, and a clean COMPLETE on a fresh account. Confirm
every hypothesised ID in TutorialConstants before relying on a run. Also confirm:
- The tutorial varp does not force-advance mid-gather, so multi-gather over-collects to the target before progressing.
- The appearance arrow widgets resolve so seeded click counts land on real arrow groups.
- Two accounts with different logins receive different names and appearances.
- Manual stepping pauses and steps action-by-action and stage-by-stage as expected.
- The raw op-1 clicks land on the right action for the name field/lookup/set-name, the smithing dagger, and the equipment-stats button.
walkOpeningDoorsopens room-transition doors so the walker does not stall against them, andwalkToOrTalkcloses the gap to out-of-range NPCs.- The magic finale completes: varps
620–680continue the dialogue, cast-first Wind Strike lands on a chicken, and the671/680teleport advances toCOMPLETEwithout an UNHANDLED halt. MAKE_DOUGHcombines flour and water exactly once (item names resolve on the current rev).
Tutorial Island Decision Tree
The following diagram visualizes the varp-281 driven stage routing and sub-step execution flow of the Tutorial Island controller: