docs(D.2b): register AP-32 + IA-15 amend for importer; doc/test review fixes (N1/N4)
Process/quality items from the LayoutDesc-importer final review — no runtime behavior change. I1a — amend IA-15: the 8-piece chrome edge/corner→position mapping is no longer a guess. The LayoutImporter (ACDREAM_RETAIL_UI_IMPORTER) reads real LayoutDesc dat data and resolves positions + sprite ids directly; locked by the conformance fixture vitals_2100006C.json. Residual risk trimmed to anchor resolution at non-800×600 + controls.ini cascade. Pointers added to LayoutImporter.cs and the format-doc. I1b — add AP-32: the importer collapses the dat's nested meter structure (Type-7 → two Type-3 containers → three image-slice grandchildren each) into UiMeter's programmatic 3-slice fields instead of building those nodes generically and porting UIElement_Meter::DrawChildren. Standalone Type-0 text elements are also skipped (Plan 2). Retail oracles: UIElement_Meter::DrawChildren @0x46fbd0, UIElement_Text::DrawSelf @0x467aa0. I1c — AP section header 31 → 32. N1 — ElementReader.cs: comment at the Type-merge line explaining that a derived Type 0 (text element) inherits the base's Type 12 (style prototype), which DatWidgetFactory skips; safe for Plan 1 because vitals numbers render via UiMeter.Label. Format-doc §10: correct the "render as UiDatElement" sentence to "skipped entirely" (Type-0 → inherits Type-12 via Merge → factory returns null). N4 — new conformance test VitalsTree_TextLabel_InheritsFontDidFromBaseLayout: walks the raw ElementInfo tree from the fixture and asserts at least one element carries FontDid==0x40000000, proving Resolve()'s inheritance merge fired against real dat data. FixtureLoader gains LoadVitalsInfos() that returns the raw tree without calling Build. Tests: 36 pass (was 35), 0 errors, 0 warnings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2b653b8fc0
commit
4dcc90cb51
5 changed files with 69 additions and 6 deletions
|
|
@ -24,6 +24,19 @@ public static class FixtureLoader
|
|||
/// dat font — sufficient for conformance checks on tree structure and slice ids.
|
||||
/// </summary>
|
||||
public static ImportedLayout LoadVitals()
|
||||
{
|
||||
var root = LoadVitalsInfos();
|
||||
return LayoutImporter.Build(root, _ => (0u, 0, 0), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the committed <c>vitals_2100006C.json</c> fixture into a raw
|
||||
/// <see cref="ElementInfo"/> tree WITHOUT calling <see cref="LayoutImporter.Build"/>.
|
||||
/// Use this when the test needs to inspect the resolved <see cref="ElementInfo"/>
|
||||
/// tree directly (e.g. inheritance-resolution checks) without exercising the
|
||||
/// widget factory.
|
||||
/// </summary>
|
||||
public static AcDream.App.UI.Layout.ElementInfo LoadVitalsInfos()
|
||||
{
|
||||
var fixturePath = Path.Combine(AppContext.BaseDirectory, "UI", "Layout", "fixtures", "vitals_2100006C.json");
|
||||
if (!File.Exists(fixturePath))
|
||||
|
|
@ -35,9 +48,7 @@ public static class FixtureLoader
|
|||
ReadOnlySpan<byte> span = bytes;
|
||||
if (span.Length >= 3 && span[0] == 0xEF && span[1] == 0xBB && span[2] == 0xBF)
|
||||
span = span[3..];
|
||||
var root = JsonSerializer.Deserialize<AcDream.App.UI.Layout.ElementInfo>(span, _opts)
|
||||
return JsonSerializer.Deserialize<AcDream.App.UI.Layout.ElementInfo>(span, _opts)
|
||||
?? throw new InvalidOperationException($"fixture deserialized to null: {fixturePath}");
|
||||
|
||||
return LayoutImporter.Build(root, _ => (0u, 0, 0), null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,4 +93,49 @@ public class LayoutConformanceTests
|
|||
var (file, _) = datElem.ActiveMedia();
|
||||
Assert.Equal(0x060074C3u, file);
|
||||
}
|
||||
|
||||
// ── Test 4 (N4): Inheritance resolution — FontDid propagated from base ───
|
||||
|
||||
/// <summary>
|
||||
/// Proves that <c>Resolve()</c>'s inheritance merge fired against real dat data:
|
||||
/// at least one element in the fixture tree must have <c>FontDid == 0x40000000</c>
|
||||
/// (the vitals font), inherited from the base-layout prototype <c>0x10000376</c>
|
||||
/// in <c>0x2100003F</c> via the <c>BaseElement</c> / <c>BaseLayoutId</c> chain.
|
||||
///
|
||||
/// <para>
|
||||
/// The three text labels (<c>0x100000EB</c> health, <c>0x100000ED</c> stamina,
|
||||
/// <c>0x100000EF</c> mana) are Type=0 derived elements with no own font property.
|
||||
/// The base element <c>0x10000376</c> carries <c>Properties[0x1A]</c> →
|
||||
/// <c>ArrayBaseProperty[ DataIdBaseProperty{Value=0x40000000} ]</c>.
|
||||
/// <see cref="ElementReader.Merge"/> propagates this via the "FontDid: derived wins
|
||||
/// if non-zero, otherwise inherit" rule.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This test verifies end-to-end inheritance resolution against the committed fixture
|
||||
/// (format doc §10, <c>docs/research/2026-06-15-layoutdesc-format.md</c>).
|
||||
/// It operates on the raw <see cref="ElementInfo"/> tree, NOT the widget tree,
|
||||
/// so the factory dispatch (Type 12 → skip) does not interfere.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void VitalsTree_TextLabel_InheritsFontDidFromBaseLayout()
|
||||
{
|
||||
var root = FixtureLoader.LoadVitalsInfos();
|
||||
|
||||
// Walk the full ElementInfo tree and collect all FontDid values.
|
||||
var fontDids = new System.Collections.Generic.List<uint>();
|
||||
CollectFontDids(root, fontDids);
|
||||
|
||||
// At least one element must carry FontDid == 0x40000000 (the vitals font).
|
||||
// In practice, the three text labels (health/stamina/mana) all inherit it.
|
||||
Assert.Contains(0x40000000u, fontDids);
|
||||
}
|
||||
|
||||
private static void CollectFontDids(ElementInfo node, System.Collections.Generic.List<uint> acc)
|
||||
{
|
||||
if (node.FontDid != 0) acc.Add(node.FontDid);
|
||||
foreach (var child in node.Children)
|
||||
CollectFontDids(child, acc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue