fix(chargen): Campaign CC gate round 1 Batch A — GF-15 input, GF-5 skills rows, GF-13 GM toggles
GF-15 (the gate blocker): the Summary name field and Finish button were
NOT structurally broken — live repro over the project's own local ACE
test server showed clicks correctly focus the field and land characters.
The real bug only surfaces after the first dialog opens: pressing Finish
empty successfully creates the NoName RetailMessageDialogView (visible,
correct 400x95 geometry) but it renders nothing and silently absorbs
every click across the whole canvas. Root cause: CharacterCreationUiController.Tick
and CharacterManagementUiController.Tick both call UiRoot.BringToFront(Root)
unconditionally every frame (needed so chargen stays above the occluded
management screen, AP-229); a dialog root is a direct sibling under the
same UiRoot, and RetailWindowManager.BringToFront is "highest ZOrder among
siblings + 1" — whichever BringToFront runs last in a frame wins.
RetailDialogFactory.Tick never re-asserted its own dialogs' z-order, so
the next frame's screen Tick buried the dialog behind the screen's opaque
backdrop while it stayed the registered Modal with exclusive input
priority. Fixed by having RetailDialogFactory.Tick re-raise every open
dialog (in open-order) each tick, matching retail's always-on-top dialog
behavior. Live-verified the complete user sequence end to end: click
field, type, press Finish empty, dialog now visibly renders, OK dismisses
cleanly, field still typable afterward. The "[ Name" prefill question is
closed as a non-bug: neither CharGenState::RandomizeCharacter nor
gmCGSummaryPage::InitializePage write text into the field in the decomp;
retail's field is genuinely empty on open, matching acdream already.
GF-5: CharacterCreationSkillsPage.RebuildRows resolved the wrong listbox
template (Templates[0], retail's own 3-child bucket-header row) and
required the root to be a UiButton (it's a plain container). Byte-traced
gmCGSkillsPage::DoSkillRecords + tagSkillRecord's copy-ctor field order
to map every child id in the real row (Templates[1]): name, level/cost
text, and the two real per-row up/down arrow buttons. Wired the arrows to
retail's own plain-click dispatch, retiring (narrowing) AP-213's
click-to-advance/double-click-retreat single-button substitution.
GF-13: dat property 0x3B (Invisible) was never read by the importer.
Elements 0x10000403/0x10000494 ("Non-Admin"/"Non-Envoy") author it true.
A blast-radius sweep found 1,083 elements client-wide author the same
flag, so this fix stays chargen-scoped only (ElementInfo.Invisible /
UiElement.AuthoredInvisible are pure data additions; only
CharacterCreationUiController acts on them, by the authored flag, not a
hardcoded id list). General importer-wide honor filed as ISSUES.md #408;
register row AP-230 records the split.
Gates: solution build green; App 5266/3 skips/0 failed; Runtime 1735/0;
full-solution run 0 failures anywhere. Register: AP-230 filed, AP-213
narrowed. ISSUES: #408 filed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6699e0f88c
commit
1d9de5e095
11 changed files with 823 additions and 78 deletions
|
|
@ -24,6 +24,53 @@ What does NOT go here:
|
|||
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
|
||||
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
|
||||
|
||||
## #408 — General importer-wide honor of dat property 0x3B (Invisible) is unshipped (1,083 elements client-wide)
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** LOW-MEDIUM (cosmetic — extra/leaked elements render where retail hides them; no gameplay/wire impact)
|
||||
|
||||
Found while fixing GF-13 (Campaign CC gate round 1, Batch A, 2026-08-16):
|
||||
acdream's `LayoutImporter`/`DatWidgetFactory` never read dat property
|
||||
`0x3B` (Invisible — `BoolBaseProperty`), which retail's
|
||||
`UIElement::OnSetAttribute @0x00462d80` case 8
|
||||
(`GetPropertyName()-0x33==8`) honors on EVERY element via
|
||||
`SetVisible(value==0)`. The blast-radius sweep this fix's investigation
|
||||
ran found **1,083 elements client-wide** author `P0x3B=true` — far
|
||||
beyond the two chargen-Summary GM labels (`0x10000403`
|
||||
"Non-Admin"/`0x10000494` "Non-Envoy") the user actually reported.
|
||||
|
||||
The fix (`fix(chargen): Campaign CC gate round 1 Batch A`) added the data
|
||||
plumbing everywhere (`ElementInfo.Invisible`, read in
|
||||
`ElementReader.ApplyCanonicalLegacyProjection`; `UiElement.AuthoredInvisible`,
|
||||
set in `LayoutImporter.BuildWidget`) but deliberately does NOT act on it
|
||||
in the shared importer path — only `CharacterCreationUiController`
|
||||
(`HideAuthoredInvisibleElements`) walks its own mounted subtree and
|
||||
hides what it finds, chargen-scoped only. Register row AP-230 records
|
||||
the split.
|
||||
|
||||
Honoring the flag client-wide (setting `UiElement.Visible = false`
|
||||
directly in `LayoutImporter.BuildWidget` when `info.Invisible` is true,
|
||||
or an equivalent central chokepoint) is straightforward, but 1,083
|
||||
elements is its own visual-regression surface: any one of them could be
|
||||
an element some OTHER screen currently relies on being visible despite
|
||||
authoring the flag (e.g. a state-conditional visibility toggle that
|
||||
happens to leave `0x3B=true` on its default/direct state while a
|
||||
controller separately manages `Visible` at runtime). This needs its own
|
||||
sweep — dump the 1,083 ids grouped by owning LayoutDesc/screen, spot-check
|
||||
a representative sample per screen against retail, then flip the
|
||||
importer-wide switch with a dedicated visual gate — not a one-line
|
||||
change folded into an unrelated fix.
|
||||
|
||||
Fix direction: (1) enumerate the 1,083 ids per LayoutDesc (a live-DAT
|
||||
probe test, similar to `SpewBoxLayoutDumpDiagnostic`); (2) for each
|
||||
distinct screen/LayoutDesc, confirm honoring the flag doesn't hide
|
||||
something the runtime currently manages visibility of dynamically at that
|
||||
SAME element id (would double-drive `Visible`); (3) flip the honor in
|
||||
`LayoutImporter.BuildWidget` (mirroring the chargen-scoped code path
|
||||
already proven live) and delete `CharacterCreationUiController`'s own
|
||||
narrow `HideAuthoredInvisibleElements`/AP-230 in the same commit; (4) run
|
||||
a full-client visual matrix, not just chargen.
|
||||
|
||||
## #407 — Windowed resolution offering starves on RDP/virtual displays (video-mode gating)
|
||||
|
||||
**Status:** DONE (`e601a496`, 2026-08-16 — same gate round, user-directed immediate fix)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -15,20 +15,90 @@ ISSUES.md; this doc is the six-page batch.
|
|||
description text that would confirm is itself broken, GF-2). ALSO: the
|
||||
open-roll's own rolled heritage shows NO lit dot on entry — every dot
|
||||
dark in the acdream screenshot.
|
||||
- **GF-5 Skills page empty.** Nothing renders except the screen-description
|
||||
textbox — no skill rows, no credits display. (CC5's residual round wired
|
||||
`TemplateResolver` into the SKILLS page too — yet live rows are absent.)
|
||||
- **GF-5 Skills page empty — FIXED (Campaign CC gate round
|
||||
1, Batch A).** Root cause was `CharacterCreationSkillsPage.RebuildRows`
|
||||
resolving `Templates[0]` (retail's own 3-child bucket-HEADER row,
|
||||
`0x100002F4`) instead of `Templates[1]` (the REAL skill row,
|
||||
`0x100002FF`, live-DAT-probe-confirmed 7 children) and requiring the
|
||||
resolved root to be a `UiButton` (it's a plain container). Byte-traced
|
||||
against `gmCGSkillsPage::DoSkillRecords @0x004817e0` +
|
||||
`tagSkillRecord`'s copy-constructor field order to map every child id:
|
||||
name (`0x10000301`), `pSkillLevelText` (`0x10000302`), `pUpCostText`
|
||||
(`0x10000303`), `pSkillUpButton` (`0x10000304`), `pSkillDownButton`
|
||||
(`0x10000305`), `pDownCostText` (`0x10000306`). Fixed to resolve
|
||||
`Templates[1]`, wire the real per-row up/down arrow buttons to
|
||||
`ListenToElementMessage @0x004814c0`'s own plain-click dispatch
|
||||
(`IncreaseSkillLevel`/`DecreaseSkillLevel`), retiring AP-213's click-to-
|
||||
advance/double-click-retreat single-button substitution (narrowed, not
|
||||
fully retired — the flat-list-vs-four-bucket half stays). The credits-
|
||||
caption clobber (`SkillsPage.cs:81-82`, now different line numbers) is
|
||||
UNCHANGED — Batch C's scope.
|
||||
- **GF-9 Appearance color swatches do nothing observable.** Clicking a
|
||||
color produces no visible change (model recolor absent). Could be a dead
|
||||
dispatch or could be working-but-invisible (AP-216 authored-art swatches
|
||||
+ a recolor that fails); investigate, don't guess.
|
||||
- **GF-11a Town description text does not change** when switching towns.
|
||||
- **GF-13 Summary shows "-Non-admin or Non-envoy" below the name** — an
|
||||
acdream-only text leak; retail's summary list has no such rows.
|
||||
- **GF-15 Summary name entry DEAD + Finish unpressable.** Cannot type into
|
||||
the name field at all; Finish cannot be pressed. Also the field is not
|
||||
prefilled with retail's `[ Name` placeholder. This blocks the entire
|
||||
create flow — the gate cannot proceed past Summary.
|
||||
- **GF-13 Summary shows "-Non-admin or Non-envoy" below the name — FIXED
|
||||
(Campaign CC gate round 1, Batch A) — this commit.** Root cause: dat
|
||||
property `0x3B` (Invisible — `UIElement::OnSetAttribute @0x00462d80`
|
||||
case 8) was never read by the importer at all; elements `0x10000403`
|
||||
("Non-Admin") and `0x10000494` ("Non-Envoy") both author it `true`
|
||||
(live-DAT-probe-confirmed, path `0x100003CC > 0x100003D0 > 0x100003D6 >
|
||||
{0x10000403,0x10000494}`). Blast-radius sweep found **1,083 elements
|
||||
client-wide** author the same flag — a blanket importer-wide honor is
|
||||
its own visual gate, filed as ISSUES.md #408. This fix is CHARGEN-SCOPED
|
||||
ONLY: `ElementInfo.Invisible`/`UiElement.AuthoredInvisible` are pure
|
||||
data additions (read/stored everywhere, acted on nowhere by the shared
|
||||
importer path), and `CharacterCreationUiController.HideAuthoredInvisibleElements`
|
||||
walks its own mounted subtree once at construction and hides whatever
|
||||
the dat itself marked hidden — by the authored flag, not a hardcoded id
|
||||
list. Register AP-230 records the scoped-vs-general split.
|
||||
- **GF-15 Summary name entry DEAD + Finish unpressable — FIXED
|
||||
(Campaign CC gate round 1, Batch A) — this commit, LIVE-VERIFIED end to
|
||||
end.** The live-repro investigation (offline `ACDREAM_OPEN_CHARGEN=1`
|
||||
alone does NOT open the chargen screen — `RuntimeCharacterCreationState`
|
||||
only activates via `LiveSessionController.StartAsync`'s authenticated-
|
||||
connect path, `LiveSessionController.cs:791`; the repro required a real
|
||||
connect to the project's own local ACE test server) showed the FIRST
|
||||
click into the name field correctly focuses it and typing correctly
|
||||
lands characters — the modal/pick/focus mechanics the earlier static
|
||||
investigation examined were never broken. The REAL cause only surfaces
|
||||
after the FIRST dialog opens: pressing Finish with an empty name
|
||||
successfully creates the NoName `RetailMessageDialogView`
|
||||
(`visible=true`, live-DAT-probe-confirmed nonzero popup/message/button
|
||||
geometry — 400x95 popup, correctly centered) but it renders NOTHING and
|
||||
silently absorbs every subsequent click across the WHOLE canvas,
|
||||
including clicks aimed at the name field or Finish button underneath.
|
||||
Root cause: `CharacterCreationUiController.Tick()` (and
|
||||
`CharacterManagementUiController.Tick()`) call `UiRoot.BringToFront(Root)`
|
||||
UNCONDITIONALLY every frame while their screen is open (needed so
|
||||
chargen stays above the occluded character-management screen
|
||||
underneath, register AP-229); a dialog's root is a direct sibling of
|
||||
those screen roots under the same `UiRoot`, and
|
||||
`RetailWindowManager.BringToFront` is a simple "highest ZOrder among
|
||||
siblings + 1" — whichever sibling's own `BringToFront` call runs LAST in
|
||||
a frame wins. `RetailDialogFactory.Tick()` never re-asserted its own
|
||||
open dialogs' z-order, so the VERY NEXT frame's screen `Tick()` (which
|
||||
always runs before the dialog factory's own `Tick()` in
|
||||
`RetailUiRuntime.Tick(double)`'s per-frame sequence) silently buried the
|
||||
dialog behind the screen's opaque backdrop — while the dialog remained
|
||||
the registered `UiRoot.Modal` and kept EXCLUSIVE input priority
|
||||
(`OnMouseDown`'s Modal-vs-bounds gate is independent of render/z-order).
|
||||
Fixed by having `RetailDialogFactory.Tick()` re-raise every open dialog
|
||||
(in `_openOrder`, so the most recently opened stays topmost) every tick,
|
||||
matching retail's real always-on-top dialog behavior. Live-verified the
|
||||
COMPLETE user sequence after the fix: click name field (focuses), type
|
||||
(lands), press Finish empty (NoName dialog now VISIBLY renders: "You
|
||||
must enter a name for this character!"), click OK (dismisses cleanly,
|
||||
`Modal` clears), click the field again (still focusable/typable). The
|
||||
`[ Name` prefill question is CLOSED, not a bug: byte-verified neither
|
||||
`CharGenState::RandomizeCharacter @0x005c6d80` nor
|
||||
`gmCGSummaryPage::InitializePage @0x0047bbf0` ever write text into the
|
||||
name field (`InitializePage` only sets the input filter) — retail's
|
||||
field is genuinely code-empty on a freshly-rolled character, matching
|
||||
acdream's existing (correct) behavior; the `[ Name` the user saw was
|
||||
most likely the field's own bracket-style empty-state chrome (GF-2/GF-12
|
||||
textbox-decoration family), not a missing name-prefill feature.
|
||||
|
||||
## Presentation families (retail parity)
|
||||
|
||||
|
|
@ -72,8 +142,12 @@ ISSUES.md; this doc is the six-page batch.
|
|||
GF-10 zoom art) — the AP-222 measured mechanism (state media authored
|
||||
vs applied) across widget kinds.
|
||||
4. Preview backdrop (GF-7/GF-14) — what gmCG3DView clears/draws.
|
||||
5. Input routing on Summary (GF-15) — focus/typing path on the stacked
|
||||
chargen screen.
|
||||
5. ~~Input routing on Summary (GF-15) — focus/typing path on the stacked
|
||||
chargen screen.~~ CLOSED: focus/typing routing was never broken (live-
|
||||
verified); the real cause was `RetailDialogFactory` never re-asserting
|
||||
its open dialogs' z-order against the chargen/char-management screens'
|
||||
own per-tick `BringToFront` — see GF-15's own entry above. Batch A
|
||||
fixed it.
|
||||
|
||||
## Process
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue