feat(ui): importer Fix C — per-element dat FontDid resolver (studio path); character level uses its retail font
DatWidgetFactory.Create now accepts an optional fontResolve: Func<uint,UiDatFont?> parameter. When supplied and the element has a non-zero FontDid, the element receives its own dat font instead of the shared global datFont fallback. Null = original single-font behavior (the live GameWindow path passes null — provably unchanged). LayoutImporter.Build/BuildFromInfos/Import all thread the optional resolver down to the factory. RenderStack gains a lazy font cache (ConcurrentDictionary, pre-seeded with VitalsDatFont + LargeDatFont) and a ResolveDatFont(uint) method. StudioWindow wires stack.ResolveDatFont into LayoutSource so every studio import gets per-element fonts. GameWindow import calls left passing null (follow-up todo). CharacterStatController font-hack cleanup (diagnosed via one-shot console dump then removed): - Name (0x10000231): dat FontDid = 18px font — remove datFont override (null) - Heritage/PkStatus: dat FontDid = 14px fonts — remove override - LevelCaption: dat FontDid = 16px — remove override (same font, no visual change) - Level (0x1000023B): dat FontDid = 36px (the big retail gold font) — was forced to rowDatFont/LargeDatFont (18px); now drops to null so the dat 36px font drives - TotalXpLabel/TotalXp: dat FontDid = 16px — remove override - FooterTitle (0x1000024E): dat FontDid = 20px — remove datFont override - KEEP: synthesized elements (XP meter overlays, 9 attribute rows, tab sprites) still use datFont directly since they have no dat origin All Label/LabelTwoLine/LabelLeft/LabelProvider helpers updated: null = keep build-time dat font; non-null = controller explicit override (backward-compat). 8 new tests in DatWidgetFactoryFontResolveTests: - null resolver → DatFont == global datFont - FontDid=0 → resolver not called - resolver returns null → fallback to global datFont - resolver called with element's FontDid - controller DatFont override wins after build - LayoutImporter.Build threads fontResolve to factory - meter element fires resolver for non-zero FontDid - BuildFromInfos without fontResolve param = original behavior Build + all 710 App tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6e0be4bd34
commit
a0d33956f6
7 changed files with 360 additions and 66 deletions
|
|
@ -45,9 +45,15 @@ public static class DatWidgetFactory
|
|||
/// Returns (0,0,0) when the texture is not yet uploaded.</param>
|
||||
/// <param name="datFont">Retail UI font for the meter's "cur/max" number overlay.
|
||||
/// May be null pre-load — the meter falls back to the debug bitmap font.</param>
|
||||
/// <param name="fontResolve">Optional font resolver: FontDid → <see cref="UiDatFont"/>
|
||||
/// (or null when the font can't be loaded). When non-null, any element whose
|
||||
/// <see cref="ElementInfo.FontDid"/> is non-zero gets ITS OWN dat font applied instead of
|
||||
/// the shared <paramref name="datFont"/> fallback. Null = original behavior (use
|
||||
/// <paramref name="datFont"/> for every element).</param>
|
||||
/// <returns>The widget for this element. Never null — every type produces a widget.</returns>
|
||||
public static UiElement? Create(ElementInfo info,
|
||||
Func<uint, (uint, int, int)> resolve, UiDatFont? datFont)
|
||||
Func<uint, (uint, int, int)> resolve, UiDatFont? datFont,
|
||||
Func<uint, UiDatFont?>? fontResolve = null)
|
||||
{
|
||||
// Retail Type 3 = UIElement_Field (reg :126190), but in acdream's CURRENT layouts
|
||||
// (vitals 0x2100006C / chat 0x21000006) Type-3 elements are sprite-bearing chrome +
|
||||
|
|
@ -60,16 +66,23 @@ public static class DatWidgetFactory
|
|||
// actually carries a factory-built editable Type-3 field (and UiField grows a
|
||||
// background-media draw + an opt-in editable flag at that point). UiField (the widget)
|
||||
// still ships — it just isn't wired into the factory switch yet.
|
||||
// Resolve this element's own dat font if a resolver is provided and the element
|
||||
// has a FontDid. Falls back to the shared datFont when not set (FontDid==0) or
|
||||
// when the resolver returns null (font missing from dats).
|
||||
UiDatFont? elementFont = datFont;
|
||||
if (fontResolve is not null && info.FontDid != 0)
|
||||
elementFont = fontResolve(info.FontDid) ?? datFont;
|
||||
|
||||
UiElement e = info.Type switch
|
||||
{
|
||||
1 => new UiButton(info, resolve), // UIElement_Button (reg :125828)
|
||||
6 => new UiMenu(), // UIElement_Menu (reg :120163)
|
||||
7 => BuildMeter(info, resolve, datFont), // UIElement_Meter
|
||||
0xD => new UiViewport(), // UIElement_Viewport — 3-D mini-scene blit leaf
|
||||
11 => new UiScrollbar(), // UIElement_Scrollbar (reg :124137)
|
||||
12 => BuildText(info, resolve), // UIElement_Text (reg :115655)
|
||||
0x10000031u => new UiItemList(resolve), // UIElement_ItemList — toolbar/inventory/paperdoll slots
|
||||
_ => new UiDatElement(info, resolve), // generic fallback (incl. Type 3 chrome/containers)
|
||||
1 => new UiButton(info, resolve), // UIElement_Button (reg :125828)
|
||||
6 => new UiMenu(), // UIElement_Menu (reg :120163)
|
||||
7 => BuildMeter(info, resolve, elementFont), // UIElement_Meter
|
||||
0xD => new UiViewport(), // UIElement_Viewport — 3-D mini-scene blit leaf
|
||||
11 => new UiScrollbar(), // UIElement_Scrollbar (reg :124137)
|
||||
12 => BuildText(info, resolve, elementFont), // UIElement_Text (reg :115655)
|
||||
0x10000031u => new UiItemList(resolve), // UIElement_ItemList — toolbar/inventory/paperdoll slots
|
||||
_ => new UiDatElement(info, resolve), // generic fallback (incl. Type 3 chrome/containers)
|
||||
};
|
||||
|
||||
// Propagate position + size (pixel-exact from the dat).
|
||||
|
|
@ -250,7 +263,13 @@ public static class DatWidgetFactory
|
|||
/// defaults — the build-time value is just the starting point, not a lock.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private static UiText BuildText(ElementInfo info, Func<uint, (uint, int, int)> resolve)
|
||||
/// <param name="elementFont">The font to seed on the widget. When a font resolver was
|
||||
/// provided and the element's FontDid resolved successfully, this is that element-specific
|
||||
/// font; otherwise it is the shared global fallback. Controllers that call
|
||||
/// <see cref="ImportedLayout.FindElement"/> and set <see cref="UiText.DatFont"/> afterward
|
||||
/// still override this — the build-time value is just the starting point.</param>
|
||||
private static UiText BuildText(ElementInfo info, Func<uint, (uint, int, int)> resolve,
|
||||
UiDatFont? elementFont = null)
|
||||
{
|
||||
uint bg = info.StateMedia.TryGetValue(
|
||||
!string.IsNullOrEmpty(info.DefaultStateName) ? info.DefaultStateName
|
||||
|
|
@ -276,6 +295,11 @@ public static class DatWidgetFactory
|
|||
Centered = centered,
|
||||
RightAligned = rightAligned,
|
||||
VerticalJustify = vJustify,
|
||||
// Seed the dat-driven font. When a font resolver was supplied and the element
|
||||
// carries a non-zero FontDid, elementFont is the element-specific dat font; otherwise
|
||||
// it is the shared global fallback. Controllers that call FindElement and explicitly
|
||||
// set DatFont afterward STILL override this (backward-compat guarantee).
|
||||
DatFont = elementFont,
|
||||
};
|
||||
|
||||
// Font color from dat property 0x1B (ColorBaseProperty).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue