fix(chargen): Campaign CC CC6a review fix round — F1-F12
Addresses the CC6a dual-lens review (architectural PASS with reservations, retail fidelity PASS with reservations, merge after F1/F2/F3). F1 (BLOCKING) - AlternateSetup/setupId tested the wrong sentinel (0) instead of retail's INVALID_DID (0xFFFFFFFF, CharGenState::GetSetupID @0x005C5B22). A hair style storing that value would have been adopted as a literal Setup id, nulling Get<Setup> and killing the whole preview. Fixed both sites with a new InvalidDid constant; added two hand-built tests plus an installed-DAT sweep of every hair style across all 26 heritage/gender combinations (869 selections, zero unresolved Setup ids). F2 (BLOCKING) - TS-82's register row, ChargenClothingTable.cs's doc, and the plan's ledger row all understated Undead's measured clothing-coverage gap as "headgear/trousers/footwear" (3 slots) with a self-contradicting "4 of 4 non-shirt slots" aside. Corrected everywhere to the true measured ALL FOUR slots (headgear, trousers, shirt, footwear). F3 (BLOCKING) - the palette-math "three independent sources" claim overcounted: ACViewer's ClothingTableList.xaml.cs:97 computes a different expression for a different problem, and its vendored PaletteSet.cs is ACE's own file, not an independent implementation. Rewrote the evidence paragraph in ChargenPalSetMath.cs to the two sources that actually hold (decomp control flow + ACE's "Taken from acclient.c" port). F4 (MEDIUM) - ChargenPreviewEntityBuilder.TryBuild did unlocked dat reads; DatCollection is not thread-safe and every sibling dat-touching resolver in this layer takes a shared datLock. Added a required datLock parameter; every dat read now happens inside one lock, mirroring RetailPaperdollPoseApplicator.Apply's shape. F5 (LOW) - noted the pre-existing Streaming.LandblockBuildFactoryTests timing flake in the ledger so a future session doesn't chase it. F6 (LOW) - fixed ChargenPreviewCamera.cs's rotation doc, which cited a nonexistent identifier in a dimensionally-wrong expression; corrected to retail's actual DoRotation @0x0047CAC7 per-tick formula. F7 (LOW-MEDIUM) - the TS-82 measurement was WriteLine-only; pinned with real assertions (zero gaps for the 9 standard heritages, exactly the 4 measured Undead table ids on both genders). Kept the existing env-gated skip pattern (confirmed house convention). F8 (LOW) - the inner PalSet-miss loop recorded-and-continued past a miss; retail's own loop returns immediately on a miss (~0x005A7B32), aborting every remaining choice in that garment. Changed continue to break; added a test proving a subsequent present PalSet is correctly not applied. F9 (LOW) - fixed three dangling <see cref="...Compose"/> doc references (the method is TryCompose). F10 (LOW) - the packed (byte)(range/8) narrowing was unchecked; a real NumColors of 2048 happened to wrap to the correct "whole palette" 0 sentinel by unchecked-cast accident. Replaced with explicit PackOffset/ PackNumColors helpers that document the 2048->0 equivalence deliberately and throw on any other unrepresentable shape. F11/F12 (LOW, CC6b scope) - noted in the plan's CC6b row: the second m_alternateSetupID override source is unmodelled, and a shared RetailHeldPose helper is worth extracting before a fourth consumer. Test counts: Core.Tests 4772/1 skip (+5), Content.Tests 147/0 (+1), App.Tests 5121/6 skips (unchanged; F5's named flake did not reproduce) - zero failures, full solution Release build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
55bfd9ca82
commit
1774d8b298
11 changed files with 561 additions and 120 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue