test(chargen): Campaign CC gate round 1 re-test 2 — R3-8 name-field exhaustive dump + closeout docs
R3-8: dumped EVERY property present on 0x10000402 (not just P0x17) across every state, cross-referenced against UIElement_Text::OnSetAttribute's complete case list (no UIElement_TextInput class exists in retail — the name field is a plain UIElement_Text/m_filter-bearing field). The full recognized-property space has no placeholder/prompt mechanism independent of P0x17. The BaseElement/prototype-inheritance hypothesis is also ruled out — the existing regression test already probes the fully-merged ElementInfo (post BaseElement resolution) and finds nothing. The only StringInfo-kind property present, 0x49, resolves to "Your name can be 32 characters long and cannot contain numbers or symbols." — but 0x49 is part of the same five-property tooltip family ISSUES #409/GF-16 already document client-wide (0x48's own DID, 0x21000041, is the EXACT tooltip popup LayoutDesc #409 cites) — a hover tooltip, not an in-field placeholder. No code change, per this batch's own "do not invent a placeholder" contract — third independent negative result on this question via three different mechanisms. The lead should request a live retail screenshot before any further investigation. Also carries the shared live-DAT regression suite for R3-1 through R3-7 (CharacterCreationLiveDatTests.cs holds tests spanning multiple findings in one file, so they land together) and the RE-TEST 2 findings-doc closeout writeup for all eight items. App suite live-DAT env 5358/3 -> 5372/3 (+14, zero regressions). Runtime 1735/0 unchanged (untouched this round). Full solution: 14578 tests / 4 skips / 0 failures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
2886f79f37
commit
91f84dec9f
2 changed files with 562 additions and 1 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Campaign CC connected gate — round 1 findings (2026-08-16)
|
||||
|
||||
## RE-TEST 2 (build `1.0.2-cc.k`, post-E/F/G/closeout) — findings R3-1..R3-9
|
||||
## RE-TEST 2 (build `1.0.2-cc.k`, post-E/F/G/closeout) — findings R3-1..R3-8
|
||||
|
||||
Heritage PASSES. Remaining, with retail side-by-side screenshots:
|
||||
|
||||
|
|
@ -40,6 +40,250 @@ Heritage PASSES. Remaining, with retail side-by-side screenshots:
|
|||
is also empty, STOP and request a live retail screenshot of the field
|
||||
before any further work.
|
||||
|
||||
**RE-TEST 2 fix batch (2026-08-16, R3-1..R3-8) is CODE-COMPLETE, pending the
|
||||
user's visual gate.** All eight findings investigated and fixed except R3-8
|
||||
(genuinely no dat-authored placeholder mechanism exists — see its own
|
||||
disposition below). App suite live-DAT env 5358/3 → 5372/3 (+14, zero
|
||||
regressions); Runtime 1735/0 unchanged (untouched this round); full
|
||||
solution 14578 tests / 4 skips / 0 failures (0 Core/Content changes this
|
||||
round, so those suites are unaffected by construction, not merely by
|
||||
measurement). No client launches.
|
||||
|
||||
- **R3-1/R3-2 FIXED.** Root cause: Batch E's `UiButton.DrawBlockLabel`/
|
||||
`WrapBlockLines` auto-wrapped ANY caption that didn't fit its box width —
|
||||
live-DAT-probed, this is the WRONG mechanism. `UIElement_Text::
|
||||
CalcJustification @0x00467260` (shared by the horizontal/vertical
|
||||
branches) shows retail's real per-glyph break decision — BOTH the
|
||||
width-triggered wrap AND the explicit-newline break — sits behind ONE
|
||||
gate keyed on the `OneLine` flag passed into `GlyphList::Recalculate`;
|
||||
nothing in the decomp confines a caption's wrap width to a SIBLING
|
||||
element's rect (the ValueBox confinement Batch E added for the
|
||||
coexisting-value-label shape). Live-DAT evidence: the Coordination
|
||||
attribute-slider label (`0x100002ed`) authors `OneLine=true` (so it
|
||||
should never wrap, regardless of width — decomp-confirmed, not just
|
||||
measurement); the Skills credits button's "Available Skill Credits"
|
||||
caption measures 193px against its OWN full 231px button width (fits
|
||||
comfortably) — the 113px confined width Batch E fed into the wrap
|
||||
decision was never a real retail quantity. Fixed by making
|
||||
`UiButton.WrapBlockLines` split ONLY on the explicit (already-
|
||||
normalized) `\n` — never width-based — a strict superset of the
|
||||
pre-Batch-E single-line draw for every already-correct caption, and the
|
||||
exact "Attribute\n Credits" authored-break shape still works unchanged.
|
||||
The `ValueBox` confinement computation itself STAYS in
|
||||
`UiButton.OnDraw` (still feeds the Center-alignment tx formula and the
|
||||
now-unreachable-for-wrap clip rect for the rare multi-line+ValueBox
|
||||
case) — deliberately not deleted, since it's harmless now that nothing
|
||||
reads it for the wrap decision, and removing it would be unrelated
|
||||
scope. **Known residual risk, NOT re-solved here:** the original
|
||||
Batch E root-cause diagnosis for R2-2/R2-3 ("24dits"/"Credit0Credits")
|
||||
was that the caption's own unconfined single-line render visually
|
||||
overlapped the coexisting value label's rect (live-DAT-measured: the
|
||||
Skills credits caption's rendered span reaches x≈196, the value box
|
||||
starts at local x=116). Removing the WRAP does not reintroduce a
|
||||
confinement CLIP either (deliberately — see `DrawBlockLabel`'s own doc
|
||||
for why inventing a new clip boundary here would be exactly the
|
||||
guessing this project forbids), so this specific button's caption and
|
||||
value MAY visually overlap again in the live client. This was NOT
|
||||
something the current re-test (R3-2) flagged as broken — it only
|
||||
reported the wrap — so no action was taken beyond documenting the risk
|
||||
for the user's own re-check.
|
||||
Files: `src/AcDream.App/UI/UiButton.cs` (`DrawBlockLabel`,
|
||||
`WrapBlockLines`, `OnDraw`'s Label block). Tests: `UiButtonTests.cs`
|
||||
(`WrapBlockLines_LongSingleParagraph_NeverWordWraps` replaces the retired
|
||||
Batch E word-wrap expectation; new
|
||||
`WrapBlockLines_SingleWordNarrowerThanBoxButWiderThanOffsetAdjustedWidth_StaysOneLine`);
|
||||
2 new live-DAT pins in `CharacterCreationLiveDatTests.cs`
|
||||
(`CoordinationAttributeLabel_AuthorsOneLineTrue`,
|
||||
`SkillsCreditsButton_CaptionFitsFullWidth_ValueChildStartsAtMidpoint`).
|
||||
|
||||
- **R3-3 FIXED.** Root cause: the title (`0x100003fb`, Y=435 H=100) and
|
||||
description (`0x100003fc`, Y=460 H=100) panes' own AUTHORED boxes
|
||||
overlap by 75px, live-DAT-measured — retail relies on VERTICAL
|
||||
JUSTIFICATION, not disjoint rects, to keep them visually separate.
|
||||
Neither pane authors dat property `0x15` (live-DAT-confirmed absent on
|
||||
both), so both fall to this port's shared unauthored-VJustify default —
|
||||
currently `Center`. Byte-tracing retail's real ctor default
|
||||
(`UIElement_Text::UIElement_Text @0x004685ff`,
|
||||
`m_eVerticalJustification = 4`) against `UIElement_Text::
|
||||
CalcJustification @0x00467260`'s ACTUAL enum semantics (`ecx_5==1` →
|
||||
Center; `ecx_5==3||5` → the far edge/Bottom; anything else, INCLUDING
|
||||
the ctor's own default of 4 → the near edge/Top) shows the correct
|
||||
unauthored default is **Top, not Center** — a genuine, client-wide
|
||||
enum-mapping bug in this port (`ElementReader.cs`'s import-time switch,
|
||||
`DatWidgetFactory.cs`'s build-time switch, and `ElementInfo.VJustify`'s
|
||||
field default all currently resolve an absent `0x15` to Center). Under
|
||||
the CORRECT Top default both panes render near their own box's TOP edge
|
||||
(25px apart — no collision); under the current Center default both
|
||||
cluster toward the middle of their overlapping boxes (collision).
|
||||
**Scoped fix, not the systemic one:** `CharacterCreationSkillsPage`'s
|
||||
constructor now force-sets `VerticalJustify = VJustify.Top` on both
|
||||
panes directly, rather than fixing the shared mapping/default. The
|
||||
shared bug is CLIENT-WIDE (every DAT-imported `UiText` reaching the
|
||||
`Centered`/`RightAligned`/`OneLine` static paths or the multi-line
|
||||
honored-justification path) and could regress already-shipped, visually
|
||||
-verified, FROZEN surfaces (vitals numbers, chat, main game UI, Options
|
||||
panel) that may rely on the CURRENT Center default — fixing it properly
|
||||
needs its own dedicated investigation + full regression sweep, filed as
|
||||
**ISSUES.md #410** and register **AD-104**.
|
||||
Files: `src/AcDream.App/UI/Layout/CharacterCreationSkillsPage.cs`
|
||||
(constructor). Tests: new
|
||||
`CharacterCreationUiControllerTests.SkillsPage_InfoBoxPanes_ForceTopVerticalJustify_ToAvoidTitleDescriptionOverlap`
|
||||
(fixture); new live-DAT
|
||||
`CharacterCreationLiveDatTests.SkillsInfoBoxTitleAndDescription_AuthoredBoxesOverlap`
|
||||
(pins the overlap premise itself, so a future DAT re-extract that makes
|
||||
the boxes genuinely disjoint is visible).
|
||||
|
||||
- **R3-4/R3-7 FIXED (single shared mechanism, confirmed).** Root cause:
|
||||
retail authors TWO DISTINCT `UIElement_Scrollbar` thumb shapes.
|
||||
`DatWidgetFactory.BuildScrollbar`'s existing vertical-thumb detection was
|
||||
built against chat's own scrollbar (`0x10000012`) — a 3-slice composite
|
||||
where the thumb CHILD carries no media of its own and three Type-3
|
||||
grandchildren supply the top-cap/middle/bottom-cap sprites. The chargen
|
||||
Skills listbox scrollbar (`0x100003f8`), Summary's OVERVIEW listbox
|
||||
scrollbar (`0x10000401`), the Summary how-to box's scrollbar
|
||||
(`0x100002e7`), AND the shade slider (`0x10000321`) all instead author a
|
||||
SIMPLE single-sprite thumb: the same structural child (Type 1, id 1, not
|
||||
the inc/dec button) carries its OWN direct Normal/Normal_rollover/
|
||||
Normal_pressed (or, for the shade slider, a single DirectState) media
|
||||
and has ZERO children — the 3-slice-only search found nothing for this
|
||||
shape, so every `Thumb*Sprite` stayed 0 regardless of overflow. Fixed by
|
||||
falling back to the thumb's own `DefaultImage` when the slice search
|
||||
finds nothing — additive; a thumb WITH real slice children (chat) is
|
||||
unaffected. This ONE fix covers R3-4's three listbox thumbs AND R3-7
|
||||
AND, as a natural consequence (same code path, same structural shape),
|
||||
the shade-slider indicator half of R3-5(c) — no separate fix was needed
|
||||
for the shade slider.
|
||||
**Process note:** the ORIGINAL live-DAT probe for this investigation
|
||||
mis-reported the shade slider's own thumb child (and, separately, the
|
||||
swatch/gradCircle elements investigated for R3-5/R3-6) as authoring
|
||||
"zero media" — a `string.Join(",", StateMedia.Keys)` display artifact
|
||||
(a single `""` DirectState key joins to an EMPTY STRING, indistinguishable
|
||||
from zero entries in a printed diagnostic — not a code defect, a
|
||||
diagnostic-only mistake caught and corrected mid-investigation by
|
||||
re-probing with an exact `.Count`/dictionary-content check instead of a
|
||||
joined string).
|
||||
Files: `src/AcDream.App/UI/Layout/DatWidgetFactory.cs`
|
||||
(`BuildScrollbar`). Tests: new `DatWidgetFactoryTests.cs`
|
||||
(`Type11_VerticalScrollbar_SingleSpriteThumbWithNoSliceChildren_SetsThumbSprite`,
|
||||
`Type11_VerticalScrollbar_ThumbWithSliceChildren_StillUsesSliceMedia`
|
||||
negative companion); 3 new live-DAT pins in
|
||||
`CharacterCreationLiveDatTests.cs`
|
||||
(`SkillsListboxScrollbar_SingleSpriteThumbShape_BuildsWithNonZeroThumbSprite`,
|
||||
`ShadeSlider_ThumbAuthorsItsOwnDirectStateSprite_BuildsWithNonZeroThumbSprite`);
|
||||
existing `ChatFixture_ScrollbarImportsInheritedMediaRoles` (3-slice shape)
|
||||
re-verified unaffected.
|
||||
|
||||
- **R3-5/R3-6 CODE-COMPLETE.** Root cause, re-derived from
|
||||
`gmCGAppearancePage::DoColorSpots @0x0047d850` and `DoGradDisk
|
||||
@0x0047da90`: retail does NOT multiply-tint the swatch/grad-circle's
|
||||
authored sprite. It builds a FRESH composited surface once
|
||||
(`CreateLocalSurface` + `Blit`), then calls `SurfaceWindow::ReplaceColor`
|
||||
against old-color `RGBAColor(0,0,0,1)` (opaque black — the spot
|
||||
template's own placeholder fill, live-DAT-PIXEL-confirmed: the
|
||||
37x44 "spot" resource has a genuine solid-black CENTER region and a
|
||||
genuine non-black RING/border region) — swapping every EXACT opaque-black
|
||||
pixel for the swatch's real color while leaving the ring untouched. A
|
||||
multiply-tint (Batch G's mechanism) is architecturally wrong here: black
|
||||
multiplied by ANY color stays black (never recolors the center at all),
|
||||
and multiplying the ring's own non-black pixels shifts their hue,
|
||||
corrupting them — exactly the reported "we tint the ring" symptom.
|
||||
Beyond-count swatches (R3-5b) use a COMPLETELY DIFFERENT authored
|
||||
resource (enum `0x1000000f`, "blank" — live-DAT-pixel-confirmed almost
|
||||
no black pixels at all, i.e. genuinely different art, not "the spot with
|
||||
its center left un-recolored") shown UNTINTED — and retail's own
|
||||
`pColor->SetVisible(1)` is UNCONDITIONAL for all 9 swatches (never
|
||||
hidden, only the CONTENT differs). For Eyes (R3-6), `DoGradDisk`'s Eyes
|
||||
branch (`arg2=1`) blits the "grad plug" icon (enum `0x10000010`)
|
||||
UNTINTED (`Blit_Normal`, no color argument at all) — and, re-reading
|
||||
`SetSelection @0x0047e260`'s own Eyes/non-Eyes tail
|
||||
(`@0x0047e859-0047e878`), NEITHER branch ever calls
|
||||
`m_pGradCircle->SetVisible` — only `DoGradDisk` (swaps the source image)
|
||||
and `m_pShadeScroll->SetVisible` (a DIFFERENT element) are touched, so
|
||||
the disc itself is NEVER hidden for Eyes — a correction to this port's
|
||||
prior `_gradCircle.Visible = !isEyes` line (and its own now-renamed
|
||||
test).
|
||||
**Mechanism ported faithfully** via a new `ChargenColorSpotComposer`
|
||||
(CPU-side decode-once + per-color bake-and-cache-once, uploaded through
|
||||
the existing `TextureCache.UploadRgba8` seam — the SAME "decode,
|
||||
recolor by exact-match, upload, cache" shape `AcDream.App.UI.
|
||||
IconComposer.GetSpellComponentIcon` already established for item icons,
|
||||
just matching black instead of white) and a new opt-in
|
||||
`UiButton.ColorKeyFaceResolver`/reuse of the EXISTING
|
||||
`UiDatElement.RuntimeImageTexture` seam — both additive, zero behavior
|
||||
change for any element that doesn't set them. `Tint` itself is
|
||||
UNCHANGED in meaning (still the "this swatch's color is X" signal every
|
||||
existing test reads) for the swatches; the grad circle's own Tint STAYS
|
||||
a genuine multiply for the non-Eyes case, matching retail's OWN
|
||||
`Blit_Multiply` there (the ONE place a multiply tint is actually
|
||||
correct). Wired as a fourth late-bound composition seam
|
||||
(`SwatchTextureSource`), same pattern and same site as the existing
|
||||
three color-computation seams (`PalSetSource`/`ClothingTableSource`/
|
||||
`PaletteColorSource`), constructed in `LivePresentationComposition.cs`
|
||||
once `TextureCache` exists.
|
||||
**STOPPED item, same shape as Batch G's own two STOPPED items:** this
|
||||
is CODE-COMPLETE and unit/live-DAT-tested (including a real pixel-level
|
||||
proof that the spot template genuinely has a black center + non-black
|
||||
ring, and that the blank template genuinely doesn't), but has NOT been
|
||||
visually verified in the live client this round (no client launches per
|
||||
this batch's own constraint) — the user's connected gate is owed.
|
||||
Files: `src/AcDream.App/UI/Layout/ChargenColorSpotComposer.cs` (new),
|
||||
`src/AcDream.App/UI/UiButton.cs` (`ColorKeyFaceResolver`, `OnDraw`),
|
||||
`src/AcDream.App/UI/Layout/CharacterCreationAppearancePage.cs`
|
||||
(`SwatchTextureSource`, `BuildSwatchTextureResolver`, the swatch/
|
||||
gradCircle refresh block), `src/AcDream.App/UI/Layout/
|
||||
CharacterCreationUiController.cs` + `src/AcDream.App/UI/
|
||||
RetailUiRuntime.cs` (pass-through seam), `src/AcDream.App/Composition/
|
||||
LivePresentationComposition.cs` (composition-root wiring). Tests: new
|
||||
`ChargenColorSpotComposerTests.cs` (3 pure byte-level tests for the
|
||||
exact-match recolor), 4 live-DAT tests in `CharacterCreationLiveDatTests.cs`
|
||||
(`ColorSpotAndGradDiskResources_ResolveToExpectedDimensions`,
|
||||
`SpotTemplate_HasBlackCenterAndNonBlackRing_BlankTemplateHasNeitherBlack`),
|
||||
8 `CharacterCreationAppearancePageSwatchColorTests.cs` assertions updated
|
||||
(`Visible` now always true; `EyesPart_GradientDiscStaysHiddenAndUntinted`
|
||||
renamed+rewritten to `EyesPart_GradientDiscStaysVisibleButUntinted_ShowsPlugIconInstead`).
|
||||
|
||||
- **R3-8 DISPOSITION: genuinely nothing authored — no code change, per
|
||||
this batch's own contract ("DO NOT invent a placeholder").** Dumped
|
||||
EVERY property present on `0x10000402` (not just P0x17) across every
|
||||
state, cross-referenced against `UIElement_Text::OnSetAttribute`'s
|
||||
COMPLETE case list (there is no `UIElement_TextInput` class in retail —
|
||||
the name field is a plain `UIElement_Text`/`m_filter`-bearing field,
|
||||
`DynamicCast(0xc)`-confirmed in `gmCGSummaryPage::InitializePage`; the
|
||||
task's own reference to that class name doesn't exist in the named
|
||||
decomp). The full recognized-property space (every id `0x14`-`0x29`
|
||||
plus the sparse high ids `0xC7`/`0xCB`/`0xCC` for
|
||||
TruncateTextToFit/LoseFocusOnEscape/LoseFocusOnAcceptInput) has NO
|
||||
mechanism for a placeholder/prompt string independent of the committed
|
||||
P0x17 caption. The BaseElement/prototype-inheritance hypothesis is ALSO
|
||||
ruled out — not by assumption, but because the EXISTING regression test
|
||||
(`SummaryNameField_AuthorsNoP0x17OnAnyState`) already probes the FULLY
|
||||
MERGED `ElementInfo` (post `LayoutImporter`'s BaseElement resolution,
|
||||
confirmed by reading `ElementReader.Merge`/`UiStateInfo.Merge`'s own
|
||||
"derived overrides, else inherit base" property-bag semantics) and finds
|
||||
no P0x17 anywhere. The live dump found exactly ONE StringInfo-kind
|
||||
property on the whole element: **`0x49`, resolving to "Your name can be
|
||||
32 characters long and cannot contain numbers or symbols."** — but
|
||||
`0x49` is part of the SAME five-property tooltip family ISSUES.md
|
||||
#409/GF-16 already documents client-wide (`0x47` tooltip behavior
|
||||
enum = `0x10000487`, `0x48` the tooltip popup LayoutDesc DID =
|
||||
`0x21000041` — the EXACT DID #409 cites, `0x49` the tooltip TEXT,
|
||||
`0x4B` tooltip-enabled = true) — a HOVER TOOLTIP describing naming
|
||||
rules, not an in-field placeholder, and #409's tooltip system is
|
||||
unshipped so this text is authored but never shown anywhere yet. The
|
||||
field's 8 children are the SAME gold-frame family (`0x100002DE-E3`/
|
||||
`0x100000E8`/`0xEA`) GF-12 already renders — reinforcing GF-15's
|
||||
existing hypothesis that the `[ Name` the user perceives is this frame's
|
||||
own bracket-style chrome around an empty box, not text content.
|
||||
**Batch A's closure and Batch E's re-check both stand; this is the
|
||||
THIRD independent negative result on the same question via three
|
||||
different mechanisms (retail code, DAT P0x17, now the complete property
|
||||
space + inheritance chain).** No further code-side avenue remains — the
|
||||
lead should request a live retail screenshot of the field per the
|
||||
batch's own contract before any further investigation.
|
||||
Test: `CharacterCreationLiveDatTests.SummaryNameField_AuthorsNoP0x17OnAnyState`
|
||||
extended with the exhaustive `0x49`-is-the-tooltip assertion (a
|
||||
regression pin, not just a probe finding).
|
||||
|
||||
## ROUND 1 RE-TEST (build `1.0.2-cc.i`, post-Batches B/C/D) — findings R2-1..R2-8
|
||||
|
||||
User's second visual pass with retail side-by-side screenshots (heritage
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue