acdream/docs/research/2026-08-16-campaign-cc-test-script.md
Erik 9cf6c52283 feat(chargen): Campaign CC slice CC7 — end-to-end create flow + connected checklist
Create button un-ghosts: retail's exact gate (gmCharacterManagementUI::
UpdateButtons @0x004ec240, roster count < allowed slot count) ported into
RuntimeCharacterSelectionButtons.CanCreate; the button's OnClick opens the
chargen screen through the same CharacterCreationUiController.Open() seam
the ACDREAM_OPEN_CHARGEN=1 dev path already used. Exit/Back confirm on
chargen needed no new return-path code — character-management is never
hidden while chargen is open on top of it — verified end-to-end by a new
cross-controller test rather than left as an inspection claim.

Full-flow test coverage: a new comprehensive test decodes every 0xF656
field (including the trailing checksum, recomputed via the production
CharacterCreate.ComputeChecksum) against a fully populated creation
(heritage/gender/all appearance slots/template/explicit skill command/
town/name); a new Theory drives the remaining six 0xF643 rejection codes
through the real wire decode path, closing the gap between the
already-covered isolated state-machine Theory and an actual WorldSession
round trip.

Launcher payload cycle: two new tests drive a real Runtime create/reject
through the real SessionStatusWriter (wired exactly as
LiveSessionRuntimeFactory/HeadlessSessionHost do in production) and read
the result back with the real Launcher.Core StatusFileTailer/
StatusEventParser — closing the one gap CC2's own per-layer tests never
reached. No gap was found in production wiring itself: GameWindow already
constructs a real, non-null SessionStatusWriter for both hosts.

Also fixes 4 pre-existing LiveSessionControllerTests assertions that
compared a full RuntimeCharacterSelectionButtons record and would have
failed once CanCreate started being computed; corrects register row
AP-211 to reflect that its own predicted resolution (the Create-button
gate landing) has now happened — both layers are intentionally kept as
retail-matching enforcement plus defense-in-depth, not one superseding
the other.

Adds docs/research/2026-08-16-campaign-cc-test-script.md, the user's
connected-gate script covering both the launcher and dev-shortcut launch
paths, the six-page create flow, every Finish outcome, and the known
cosmetic/behavioral divergences (AP-212/213/215/216/217/218/219/220/222/
224/226/228) so they aren't mistaken for new bugs during the gate.

Gates: full solution Release build green; Runtime 1735/0 (was 1726/0,
+9), App 5256/3 skips (was 5254/3, +2), Headless 166/0 (unchanged),
Launcher.Core 324/0, one full-solution pass across every project clean
(no known flakes reproduced this run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 02:35:21 +02:00

17 KiB

Campaign CC connected-gate test script

Status: the campaign is CODE-COMPLETE (CC1-CC7) and this script is its connected-gate contract. Every step below is the user's own eyes on the running client — nothing here was run automatically. No automated live character creation has been run against ACE (see §CC-Not-Automated) — the first LIVE create is deliberately left to this gate.

This script covers TWO ways to reach the chargen screen: the real launcher flow (Campaign LA's product path) and the developer shortcut (ACDREAM_RETAIL_UI=1 + ACDREAM_OPEN_CHARGEN=1, still available and still useful for a fast create-only iteration loop). Both land on the exact same screen and Runtime owner — there is no second code path being tested.

Local ACE connection details (per CLAUDE.md): host 127.0.0.1, port 9000, account testaccount / testpassword. Use a FRESH character name per attempt (ACE does not forget names within a session) — CC-<yourinitials>-<n> is a good scheme, e.g. CCAB1, CCAB2.


§CC1 — reaching the screen

Path A — the launcher (product path)

  1. Launch AcDream.Launcher (already installed/updated per Campaign LA's own gates — this script does not re-run first-run setup or the update flow; see docs/research/2026-08-14-campaign-la-test-script.md if either is in question).
  2. Open Check for updates. Confirm it reports the client already current (no install prompt) — Campaign LA's own gates already proved the install/update mechanics; this step just confirms nothing is stale before the character-creation gate.
  3. Confirm (or create) a profile pointed at 127.0.0.1:9000, testaccount / testpassword.
  4. Click GUI — character select. The retail character-management screen (gmCharacterManagementUI) opens — the flat character list, World name, Enter/Delete/Restore buttons, and the Create button.

Path B — the developer shortcut

$env:ACDREAM_DAT_DIR   = "$env:USERPROFILE\Documents\Asheron's Call"
$env:ACDREAM_RETAIL_UI = "1"
$env:ACDREAM_LIVE      = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Release

Confirm the SAME character-management screen appears. ACDREAM_OPEN_CHARGEN=1 (add it to the block above) is the CC4-era interim seam that opens the chargen screen directly on startup, skipping the Create click — still useful for a fast create-only loop, but Path A/B above is now the REAL path and should be exercised at least once per gate.

The Create button

  1. With at least one free character slot (roster count below the account's allowed slot count — most test accounts have several free slots), confirm Create is ENABLED (not greyed out).
  2. Click Create. The chargen screen (gmCharGenMainUI) opens directly on the Heritage page — no confirmation, no loading screen. The character-management screen you were just on is not closed or hidden; it simply sits behind the new screen (this matters for the Exit step below).
  3. If your account's roster is completely full (rare on a fresh test account — every slot occupied), confirm Create is instead GREYED OUT and does nothing when clicked. This is retail's own gate (gmCharacterManagementUI::UpdateButtons) — a full roster ghosts Create exactly like Enter/Delete grey out for an unselected row.

Leaving the screen (Back-at-Heritage and Exit)

  1. On the Heritage page (the first page), click Back. Confirm a confirmation dialog appears asking whether to leave character creation (same text/shape as the Exit button below — Back-at-Heritage and Exit share retail's one DoExit confirmation).
  2. Click Exit (top of the screen, available on every page). Confirm the SAME confirmation dialog appears.
  3. Confirm the dialog (accept). The chargen screen closes. You are back at the character-management screen you started from — roster, World name, and any prior selection are exactly as you left them (character management was never hidden, so there is nothing to "restore").
  4. Click Cancel on a repeat Exit attempt instead — confirm the dialog closes and chargen stays open, untouched.

What to report for §CC1

  • Create's enabled/greyed state matching the free-slot count you actually have.
  • Whether clicking Create opens chargen with no lag/flash/black frame.
  • Whether returning from Exit shows the character list exactly as it was (no re-flicker, no lost highlight, no stale World name).

§CC2 — the six-page create flow

The screen does NOT open blank. gmCharGenMainUI's own constructor rolls a full random character (heritage, gender, appearance, clothing, template, start area) before the Heritage page ever draws — acdream ports this faithfully (AP-214, retired). Expected retail quirk: the gender shown on the Appearance page is the FLIP of the roll — the Appearance page's own init code reads the just-rolled gender and immediately swaps it to the opposite one. If you open chargen and see (say) a female Aluvian with the Appearance page showing "Male" selected, that is CORRECT, not a bug — do not report it.

Heritage page

  1. Confirm one of the 13 heritage buttons is already highlighted (the opening roll) — Human heritages (Aluvian/Gharu'ndim/Sho/Viamontian), Tumerok, Gearknight, Lugian, Empyrean, Penumbraen, Shadowbound, Undead, Olthoi, and OlthoiAcid should all be selectable and each show its own description text (starting skills, bonus-skills paragraph where retail has one — Lugian/Olthoi/OlthoiAcid have none, that's retail-correct).
  2. Click Random. Confirm the highlighted heritage changes to a uniformly-picked one of the 13 — this is AP-212's documented approximation (retail's own Heritage-page Random rolls with retail's own distribution; acdream picks uniformly over every installed heritage). Not a bug to report unless the button does nothing or crashes.
  3. Select Olthoi or OlthoiAcid. Confirm the Profession, Skills, and Town tabs are hidden (Olthoi variants skip straight to a fixed Custom template with no attribute/skill/town choices) and the screen auto-advances past them.

Profession page

  1. Select a NON-Olthoi heritage. Confirm 7 template buttons (Custom + 6 presets) and 6 attribute sliders (Strength/Endurance/Coordination/ Quickness/Focus/Self).
  2. Drag a slider. Confirm the numeric readout updates live and the Available-credits counter decreases/increases correspondingly.
  3. Click a preset template (not Custom). Confirm all 6 sliders jump to that preset's values and Available credits updates to match.
  4. Click Random. Confirm heritage/template selection changes (AP-212 — uniform pick, not retail's own weighted roll).

Skills page

  1. Confirm ONE flat listbox of skills, each row showing name, current level, and train/specialize costs (AP-213 — retail groups these into four sorted buckets; acdream's flat list is a presentation simplification, not a rules difference — do not report the flat ordering as a bug).
  2. Click a trainable row. Confirm it advances (Untrained -> Trained -> Specialized) and the skill-credits meter decreases; a second click on an already-Specialized row does nothing further (no fourth state).
  3. Confirm Random is disabled/greyed on this page (retail's RandomizeSkills primitive is unported — AP-212's own documented gap).

Appearance page

  1. Confirm Face and Clothes sub-tabs, nine spin controls (hair, eyes, nose, mouth, skin under Face; headgear, shirt, trousers, footwear under Clothes), nine color swatches, a shade scrollbar, zoom/rotate buttons, and a live 3D preview playing an idle animation loop.
  2. Click a spin's left/right arrow zones. Confirm the selected style index advances/retreats and the preview model updates.
  3. Click a color swatch. Confirm the swatch shows a highlighted "selected" ring/border (AP-215 — acdream's own selection indicator, not retail's overlay mechanism; functionally equivalent).
  4. Click Zoom In. Confirm the preview freezes its pose (idle animation stops) and the camera tweens closer over about half a second. Click Zoom Out — animation resumes, camera tweens back out.
  5. Click Rotate Clockwise/Counter-Clockwise. Confirm the model spins continuously at a steady rate (about 3 seconds per full turn); clicking the SAME direction again stops it, clicking the OPPOSITE direction reverses it.
  6. Click Random (on either sub-tab). Confirm hair/eyes/nose/mouth/skin (Face) or headgear/shirt/trousers/footwear (Clothes) all re-roll together — this IS retail's real RandomizeAppearance/ RandomizeClothing primitive (CC5 ported it verbatim, not approximated).
  7. Select Gearknight, Olthoi, or OlthoiAcid on the Heritage page, then return to Appearance. Confirm the Clothes sub-tab and its four spins are unreachable, Nose/Mouth spins are hidden, and Eyes' arrows are disabled (fixed eyes for these forms).

Known cosmetic gaps on this page — expected, do not report as bugs unless noticeably worse than described: swatches show static art rather than the actual color they represent (AP-216); the gradient circle art next to the swatches never repaints to reflect the current color (AP-217); the four icon-only spins (hair/eyes/nose/mouth) show a plain number instead of an icon thumbnail, while the four clothing spins show real names (AP-215/ AP-218); on Olthoi/OlthoiAcid/Gearknight the Skin spin does not slide up to close the gap left by the hidden Nose/Mouth spins (AP-219); switching heritage INTO or OUT OF Gearknight does not automatically re-roll appearance/clothing the way retail does on that exact transition (AP-220); the currently-selected spin shows no distinct highlighted state versus the other eight (AP-222 — this is a MEASURED gap in acdream's own art, not yet attributed to a specific missing asset; report clearly if you can visually compare with retail here).

Town page

  1. Confirm four town buttons: Holtburg, Shoushi, Yaraq, Sanamar (not id order — that's retail's own literal ordering, ported faithfully), each with descriptive text.
  2. Click a town. Confirm it highlights and the description text updates.

Summary page

  1. Confirm a listbox showing Profession, Gender, Heritage, and Starting Town lines, an "Attributes" header, then Strength/Endurance/ Coordination/Quickness/Focus/Self/Health/Stamina/Mana/Skill Credits as paired rows, then Specialized and Trained skill name lists (retail also lists the two Untrained buckets; acdream's Summary omits them — AP-224, same class of cut as the Skills page's own AP-213).
  2. Confirm a static 3D preview of the character (no zoom/rotate controls on this page — retail has none here either).
  3. Click the name field and type a name. Confirm only letters, spaces, apostrophes, and hyphens are accepted (other characters are silently rejected keystroke-by-keystroke).
  4. Click Random on this page. Confirm a confirmation dialog appears first ("are you sure you want to randomize?"); confirming it re-rolls the ENTIRE character (heritage through name) using retail's real RandomizeCharacter primitive — the same one the screen-open roll uses.

What to report for §CC2

  • Any page that fails to render a control listed above, or where a control visibly does nothing when clicked.
  • Anything from the "known cosmetic gaps" list that looks MORE broken than described (e.g. a spin that doesn't advance at all, not just a missing highlight).
  • Any crash, freeze, or console error while navigating pages or the tabs.

§CC3 — Finish and its dialogs

Use a fresh, never-before-used character name for the happy path. For every scenario below, watch the console/log for [UI]/[CC]-prefixed lines — they help distinguish "nothing happened because the click didn't register" from "the request went out and ACE is thinking about it."

Happy path

  1. Complete a legal character (heritage, gender, template with credits fully spent, at least a default set of skills, a town, a fresh name).
  2. Click Finish on the Summary page. Confirm the screen closes almost immediately (no visible "please wait" dialog for a normal accept — ACE's Ok reply is fast) and you land DIRECTLY in the world as the new character — no return to character management, no fresh character list, matching retail's own "log straight in" behavior.
  3. If you back out to character management instead (e.g. via a later logout), confirm the new character now appears in the roster alongside any pre-existing ones, in the correct slot.

NameInUse (duplicate name)

  1. Create a SECOND character using the EXACT name you just used above.
  2. Click Finish. Confirm the ID_Character_Err_NameReserved dialog appears ("that name is in use" / similar text) and you stay on the chargen screen — Finish is clickable again afterward.
  3. Expected log noise (register AD-100): ACE sends the NameInUse rejection TWICE for the same request (a real ACE double-send bug, not an acdream defect). The FIRST reply drives the dialog above; the SECOND logs something like unexpected CharacterGenerationVerificationResponse in the console. That log line is EXPECTED here — do not report it as an error.

The credit-warning confirm flow

  1. Select the Custom template on the Profession page (leaves several attribute credits unspent) and complete the rest of the character.
  2. Click Finish. Confirm a warning dialog appears about unspent attribute credits, and Finish does NOT send anything yet.
  3. Confirm the dialog. Confirm the request now sends anyway, with the unspent credits — this is retail-correct (DoFinish's own confirm-arm skips the credit check entirely; ACE accepts an under-spent build).

The randomize warning flow

Already covered in §CC2's Summary-page step 4 above — confirm the warning appears BEFORE any randomization happens, and Cancel leaves the character completely untouched.

The exit warning flow

Already covered in §CC1's "Leaving the screen" section above.

NameTooLong

  1. On the Summary page, type or paste a name longer than 32 characters and commit it (press Enter, or click elsewhere to move focus away from the field).
  2. Confirm the ID_CharGen_NameTooLong dialog appears and the field reverts to its previous (shorter) value — the field itself does not cap your typing at 32 characters as you go; the rejection only fires on commit. That is retail-correct, not a bug.

What to report for §CC3

  • Whether the happy path truly lands you in-world with no intermediate screen.
  • The exact dialog text shown for each rejection (useful for a later string-table audit even if it looks right).
  • Any case where Finish appears to do nothing at all (no dialog, no console line, no world entry) — that would be a real regression, not one of the documented cosmetic gaps above.

§CC4 — ACE-side landmines (not acdream defects)

  • Heritage-priced skill over-deduction — LATENT, will not fire with the installed EoR DAT. ACE's PlayerFactory.CreatePlayer has a real overcharge bug when specializing a skill priced by the active heritage's own skill list (versus the global skill table). It was measured against the installed EoR data and found unreachable — every heritage's one priced skill (Arcane Lore) has a heritage NormalCost of 0, which makes ACE's overcharge exactly zero. You should NOT be able to trigger a FailedToSpecializeSkill rejection from a retail-legal build during this gate. If you somehow do, that is worth flagging immediately — it would mean the installed DAT's costs differ from what was measured.
  • Disabled-Olthoi create -> Pending -> NameDBDown dialog is retail-correct. If your local ACE has Olthoi character creation disabled (a server config option), attempting to create an Olthoi/ OlthoiAcid character will surface the ID_Character_Err_NameDBDown dialog via a Pending response code. This is retail's OWN behavior (ACE's olthoi_play_disabled branch sends Pending, and retail's dispatch has no silent branch for it) — not a "the client swallowed my request" bug.

§CC-Not-Automated

No automated test in this repository has created a character against a LIVE ACE server. Every field-shape and response-code assertion in Campaign CC's test suite runs against a real WorldSession and hand-built response packets (see tests/AcDream.Runtime.Tests/Session/LiveSessionControllerCharacterCreationTests.cs) — the wire bytes and the state machine are proven byte-for-byte, but the FIRST character ever created against a real, running ACE process is whatever you create during this gate. Server state (what names exist, what heritages are enabled, what the account's slot count is) is entirely yours to observe; this script deliberately does not assume any of it in advance.