docs(ui): Fix 4 — dat UIState model has no Group visibility encoding; CharacterStatController hacks are correct
Investigation (2026-06-26): the character footer three sibling groups (0x10000240/241/247)
all carry DefaultState=0x10000011 (StatManagement_Footer_Default) — the dat does NOT
differentiate them by visibility. Parent 0x1000022F has States {Default, Text, Meter}
with PassToChildren=true, but each child group registers all three states with
IncorporationFlags=None and Media=0, so state-propagation produces no visual change
on any group. Retail gmStatManagementUI uses hardcoded element-id dispatch for
0x10000240/241/247 — the groups are never hidden/shown via the dat state mechanism
(decomp gmStatManagementUI::GetFooterTitleLabel @0x004f0170).
Tab-page containers (0x1000022B/22C/10000539) have DefaultState=Undef — no visibility
encoding. Tab visibility is managed purely at runtime by gmTabUI.
IncorporationFlags (DatReaderWriter): {None, PassToChildren, X, Y, Width, Height,
ZLevel} — no Visible flag. The importer cannot set initial Group visibility from
the dat; the controller is the correct and only place. CharacterStatController
HideAllById footer pass and ContainsWidget page-visibility walk are retail-faithful
and must be kept.
No logic changes — comment-only documentation. Build green, 710 App tests green.
Studio screenshots: character footer shows State-A by default with no overlap;
vitals and toolbar unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ed626f4250
commit
1b9dd6c7a8
2 changed files with 38 additions and 0 deletions
|
|
@ -333,6 +333,19 @@ public static class CharacterStatController
|
|||
// the LAST copy of each id; the others live in the VISIBLE Attributes page and must
|
||||
// also be hidden.
|
||||
//
|
||||
// WHY this cannot be done in the importer (dat state-model audit 2026-06-26):
|
||||
// All three group elements have DefaultState = StatManagement_Footer_Default
|
||||
// (0x10000011) — the dat does NOT differentiate them by visibility. The parent
|
||||
// element (0x1000022F) has a States map {Default, Text, Meter} with PassToChildren=
|
||||
// true, but each child group also registers all three states (IncFlags=None,
|
||||
// Media=0) — meaning the state-propagation produces no media change on any group.
|
||||
// Retail's gmStatManagementUI uses hardcoded element-id dispatch
|
||||
// (GetChildRecursive(this, 0x10000240) for Default, 0x10000241 for Text, 0x10000247
|
||||
// for Meter) to access the right group's children at runtime — the groups themselves
|
||||
// are never hidden/shown via the dat state mechanism. The controller is the correct
|
||||
// and only place for this visibility management. See retail decomp
|
||||
// gmStatManagementUI::GetFooterTitleLabel @0x004f0170.
|
||||
//
|
||||
// Strategy: walk the Attributes page (the root child that contains the NameId anchor)
|
||||
// and hide every UiDatElement whose ElementId matches B or C. The page-visibility
|
||||
// pass hides everything in the Skills/Titles pages, so we only need to act on the
|
||||
|
|
@ -368,6 +381,12 @@ public static class CharacterStatController
|
|||
}
|
||||
|
||||
// ── Active-page selection (fixes the dark-overlay) ─────────────────────
|
||||
// WHY this cannot be done in the importer (dat state-model audit 2026-06-26):
|
||||
// The three tab-page content areas (0x1000022B Attributes, 0x1000022C Skills,
|
||||
// 0x10000539 Titles) all have DefaultState = Undef (0) — the dat carries no
|
||||
// visibility encoding for tabs. Tab visibility is managed at runtime by gmTabUI
|
||||
// via SetVisible(bool) on the page containers. The controller is the correct
|
||||
// and only place for initial tab-page selection.
|
||||
if (layout.FindElement(NameId) is { } anchor && layout.Root is { } root)
|
||||
{
|
||||
foreach (var page in root.Children)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue