fix(chargen): Campaign CC CC5 review fix round — F1-F14
Opus dual-lens review of 34e3a534+a975efd1 returned architectural PASS-with-items / retail-fidelity FAIL. Every finding fixed: - F1 (BLOCKER): deleted CharacterCreationSummaryPage's dead _suppressNextFieldEvent latch. UiField.SetText never raises OnFocusLost/OnSubmit, so the latch never had anything genuine to suppress — it stayed armed until the player's own next real commit and silently ate their typed name. - F2: byte-re-derived gmCharGenMainUI::RecvNotice_ CharGenVerificationResponse @0x004e9030's jump table — Pending is an explicit switch case landing on the SAME NameDBDown label as Corrupt/DatabaseDown, and Undef/out-of-range falls through the function's own unsigned-underflow default arm to that identical label. Retail's dispatch has NO silent branch. ApplyCreationResponse now produces a real rejection for Pending/Undef instead of a silent reset; ReconcileDialogs maps them to NameDBDown. Corrects the wrong "retail swallows Pending" claim everywhere it was repeated (plan doc, Core.Net doc comment, Runtime doc comments). - F3: skill rows now use the key/value template with CharGenState::GetSkillScore @0x005C4B50 as the value (ported via the new RetailSkillFormula.CalculateChargenScore / ChargenSkillScoreResolver, wired through a new GetSkillScore binding), not template 0/name-only; bucket headers are unconditional. Writing this fix's own regression test surfaced a second, more severe bug: CharacterCreationSummaryPage never wired _list.TemplateResolver at all, so RebuildListbox has been a silent no-op since CC5 shipped — fixed by threading templateResolver through the page's constructor, matching every sibling UiTemplateListBox owner. - F4: added the missing _errorMessageDialogContext one-outstanding guard to the 0xF643 rejection dialog, matching MakeErrorMessageDialog's own guard @0x004e8cc4 and the other four sibling dialogs' shape (registered in CloseAllDialogs, suppress- callback checked). - F5: the Summary preview camera now seeds/re-derives retail's zoomed-OUT eye (byte-decoded (0,-2.5,0.95) at gmCGSummaryPage:: InitializePage ~0x0047bd14-0x0047bd44) instead of Appearance's zoomed-in default, via a new ChargenPreviewController useZoomedOutEye flag. - F6: retired AP-225 outright — re-derived the ListenToElementMessage length gate is NUL-inclusive, so MaxNameLength=32 was always byte-correct, not merely internally consistent. - F7: amended AP-221 to cover the Summary preview's duplicate one-shot-composition binding gap (CC5 duplicated the pattern instead of closing it). - F8: byte-decoded GetRandomReal @0x00563940's fmul operand at 0x007cd650 — an 8-byte double, not a 4-byte float — is EXACTLY 1.0/32767.0, not 1/32768. Added RollShadeLocked (_random.Next(32768) * (1.0/32767.0)) and switched all six shade rolls onto it. - F9: evaluated porting retail's exact empty-name-commit no-op (NUL-inclusive length==1 skips SetName entirely) and rejected it — it would fight the F1 field-sync model by spontaneously reverting an emptied field on the next unrelated revision bump. Kept the clear, documented the tradeoff, filed AP-227. - F11: filed AP-226 documenting retail's static pcProfessions/pcGender/ pcHeritage/pcTown label tables versus acdream's DAT-sourced labels, including the non-human-heritage-renders-bare-"Heritage:" retail quirk. - F12: added exclude-current determinism (count-2 lists), Random- clears-name, repeat-identical-rejection-reshows, and RebuildListbox content tests (the last one found F3's TemplateResolver bug). - F13: threaded an optional Random through GameRuntimeDependencies -> LiveSessionController -> RuntimeCharacterCreationState, matching the existing TimeProvider injection shape, closing the Slice-K determinism hazard on a bot-reachable Randomize* command family. - F14: RandomizeCharacterLocked now assigns _heritageId unconditionally before the TryGetHeritage gate, matching retail's SetHeritageGroup @0x005C67A0 (mHeritageGroup written before the DAT lookup). Gates: Runtime 1726/0 (was 1722/0), App 5242/3 skips (was 5240/3), Headless 166/0, Core.Net 993/994 (the one failure, NakEmissionTests LossSoak, is a known pre-existing flake — passes standalone), full solution Release build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a975efd1d5
commit
0c8e1e7df1
14 changed files with 720 additions and 141 deletions
|
|
@ -56,18 +56,27 @@ namespace AcDream.Core.Net.Messages;
|
|||
/// <c>CharacterGenerationVerificationResponse</c> enum
|
||||
/// (<c>ACE.Server/Network/Enum/CharacterGenerationVerificationResponse.cs</c>),
|
||||
/// which is itself retail's own dialog dispatch table
|
||||
/// (<c>Handle_CharGenVerificationResponse@0x0055E8B0</c>): <c>NameInUse</c> →
|
||||
/// <c>ID_Character_Err_NameReserved</c>, <c>NameBanned</c> →
|
||||
/// <c>ID_Character_Err_NameBanned</c>, <c>Corrupt</c>/<c>DatabaseDown</c> →
|
||||
/// <c>ID_Character_Err_NameDBDown</c>, <c>AdminPrivilegeDenied</c> →
|
||||
/// <c>ID_Character_Err_NameAdminDenied</c>. <c>Pending</c>/<c>Undef</c>
|
||||
/// retail treats as a silent state reset with no dialog — notably ACE sends
|
||||
/// (<c>Handle_CharGenVerificationResponse@0x0055E8B0</c> +
|
||||
/// <c>gmCharGenMainUI::RecvNotice_CharGenVerificationResponse@0x004e9030</c>'s
|
||||
/// own jump table). <b>CC5 review-fix round F2 (2026-08-16) correction:</b>
|
||||
/// every non-Ok code shows a dialog — there is no silent branch.
|
||||
/// <c>NameInUse</c> → <c>ID_Character_Err_NameReserved</c>,
|
||||
/// <c>NameBanned</c> → <c>ID_Character_Err_NameBanned</c>,
|
||||
/// <c>AdminPrivilegeDenied</c> → <c>ID_Character_Err_NameAdminDenied</c>,
|
||||
/// and <c>Pending</c>/<c>Corrupt</c>/<c>DatabaseDown</c>/<c>Undef</c>/any
|
||||
/// unrecognized code ALL resolve to <c>ID_Character_Err_NameDBDown</c> —
|
||||
/// <c>Pending</c> is an explicit switch case landing on that same label,
|
||||
/// and <c>Undef</c>/out-of-range falls through
|
||||
/// <c>RecvNotice_CharGenVerificationResponse</c>'s own
|
||||
/// <c>(arg2-1) > 6</c> unsigned-underflow default arm to the identical
|
||||
/// label. This corrects an earlier (wrong) reading of the decomp that
|
||||
/// treated Pending/Undef as a silent state reset — notably ACE sends
|
||||
/// <c>Pending</c> for a disabled-Olthoi rejection
|
||||
/// (<c>CharacterHandler.CharacterCreateEx</c>,
|
||||
/// <c>olthoi_play_disabled</c> branch), so that specific rejection is
|
||||
/// invisible to the retail-faithful client too; this is a retail quirk to
|
||||
/// port as-is, not a bug to fix. Dialog presentation itself is CC5's job
|
||||
/// (App layer), not this Core.Net type's.
|
||||
/// <c>olthoi_play_disabled</c> branch), so that specific rejection now
|
||||
/// correctly surfaces the NameDBDown dialog, matching retail, instead of
|
||||
/// silently resetting verification state. Dialog presentation itself is
|
||||
/// CC5's job (App layer), not this Core.Net type's.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class CharGenVerificationResponse
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue