fix(ui): Map tab player/house icon resolution — build the button-swallowed icons from the panel-slot resolve tree, detached from the per-frame layout pass
Two mechanisms, both live-verified (register row AD-108 updated to match): 1. RESOLUTION. The player/house icons (0x100001ED/0x100001EE) are authored as nested dat children of m_pMap (0x100001EC), itself a Type-1 button whose UiButton.ConsumesDatChildren swallows them at build. The old ResolveSwallowedIcon re-imported them standalone via ImportInfos(hostLayout, iconId) — which returns null on the live DAT: FindDesc walks the raw top-level Elements table (one entry for 0x2100006E) and never reaches them. Their ElementInfos only materialize inside the full panel-slot resolve (ImportInfos(0x2100006E, 0x1000018C)) that MountMapHousePanel already imports — the pageInfo Bind already receives. The fix finds each icon's info under m_pMap's own resolved info subtree and BUILDS it through the new Bindings.IconBuilder seam (production: LayoutImporter.Build under the DAT lock — the build half of RowTemplateResolver's shape). An icon the normal walk DID build is preferred (FindDescendant first), so a future ConsumesDatChildren policy change cannot double-build. 2. POSITION. Found by this fix's own F1 live verification: the resolved ring rendered pinned to m_pMap's top-left. PlaceMarker owns marker position outright (retail's gmMapUI::Update re-places every tick; retail's UpdateForParentSizeChange runs only on real parent resize), but acdream re-runs ApplyAnchor per frame and the icon's compatibility anchor had captured the authored (0,0) rect while the panel was still hidden, re-asserting it over PlaceMarker's writes every frame. PrepareIcon now sets Anchors=None (clearing any imported LayoutPolicy), the established runtime-positioned-element convention. Live numeric gate (session character +Acdream, cell 0xF07E003F): independent computation (gid_to_lcoord -> display (90.8E, 0.5S) -> byte-decoded PlaceMarkerOnMap formula, 17x16 icon, marker area (6,8)-(247,258)) predicts local pixel (226,125); the connected client's UI-tree dump shows the icon at screen (1166,195) under m_pMap (940,70) = local (226,125) — exact match in both panel-open dumps. Coordinate text "0.5S,90.8E", Holtburg town-marker tooltip (real-mouse hover), and the House tab's "You may buy another house immediately." sentence all confirmed on screen; ACE-confirmed graceful logout. New pin: MapHousePanelLiveDatMountTests ([InstalledDatFact]) reproduces the production mount recipe against the installed DATs — the test that would have caught this at Batch C: pins the cold-import null, the panel-slot resolution of both icons with non-degenerate extents, AND that PlaceMarker's writes survive the per-frame ApplyAnchor pass. Gates: Release build green; App suite (live-DAT mode) 5479/3 skips (baseline 5478 + the new pin); Runtime 1744/0; full solution green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
38c580ff6d
commit
e316e190cb
6 changed files with 289 additions and 42 deletions
|
|
@ -17,17 +17,14 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
/// </summary>
|
||||
public sealed class MapHousePanelControllerTests
|
||||
{
|
||||
/// <summary>Serves BOTH the town-hotspot template (any (layoutId,
|
||||
/// elementId) pair not the player/house icon ids) and the two icons
|
||||
/// <see cref="MapPageController.Bind"/> re-resolves standalone
|
||||
/// (<c>m_pMap</c>'s own button-swallowed children). Returns a
|
||||
/// <summary>Serves the town-hotspot template. Returns a
|
||||
/// <see cref="UiButton"/> — matching the live template's own authored
|
||||
/// Type 1 (<c>MapHousePanelSlotProbeTests</c>: "hotspot template
|
||||
/// type=1") — so <see cref="MapPageController.BuildTownMarkers"/>'s
|
||||
/// <c>marker is UiButton</c> tooltip-text branch is actually exercised
|
||||
/// by these tests. A real <see cref="RowTemplateResolver"/> would set
|
||||
/// <c>DatElementId</c> the same way <see cref="LayoutImporter.Build"/>
|
||||
/// does, so tests that need to find these icons back by id after the
|
||||
/// does, so tests that need to find these markers back by id after the
|
||||
/// fact need it too.</summary>
|
||||
private static UiElement? FakeHotspotTemplate(uint layoutId, uint elementId)
|
||||
=> new UiButton(new ElementInfo(), static _ => (0u, 0, 0))
|
||||
|
|
@ -37,6 +34,22 @@ public sealed class MapHousePanelControllerTests
|
|||
DatElementId = elementId,
|
||||
};
|
||||
|
||||
/// <summary>The <see cref="MapPageController.Bindings.IconBuilder"/>
|
||||
/// seam: builds m_pMap's two button-swallowed icon children from their
|
||||
/// OWN <see cref="ElementInfo"/>s inside the panel-slot resolve tree
|
||||
/// (register row AD-108 — a standalone re-import cannot find them on
|
||||
/// the live DAT, so the icons are found under the already-resolved
|
||||
/// <c>pageInfo</c> and built through this seam instead). Mirrors
|
||||
/// production's <c>LayoutImporter.Build(info, ...).Root</c>, which sets
|
||||
/// <c>DatElementId</c> from the info's own id.</summary>
|
||||
private static UiElement? FakeIconBuilder(ElementInfo info)
|
||||
=> new UiButton(new ElementInfo(), static _ => (0u, 0, 0))
|
||||
{
|
||||
Width = 10f,
|
||||
Height = 10f,
|
||||
DatElementId = info.Id,
|
||||
};
|
||||
|
||||
/// <summary>The House ListBox's own row template resolves to a
|
||||
/// <see cref="UiText"/> in the live DAT (<c>MapHousePanelSlotProbeTests</c>:
|
||||
/// "row template type=12" — <c>UIElement_Text</c>), unlike the Map tab's
|
||||
|
|
@ -59,7 +72,8 @@ public sealed class MapHousePanelControllerTests
|
|||
CurrentCalendar: currentCalendar ?? (static () => default),
|
||||
PlayerCellId: playerCellId ?? (static () => 0u),
|
||||
HousePosition: housePosition ?? (static () => null),
|
||||
TemplateResolver: FakeHotspotTemplate),
|
||||
TemplateResolver: FakeHotspotTemplate,
|
||||
IconBuilder: FakeIconBuilder),
|
||||
House: new HousePageController.Bindings(
|
||||
Lines: houseLines ?? (static () => Array.Empty<string>()),
|
||||
OnShown: () => calls.Add("house-shown"),
|
||||
|
|
@ -158,10 +172,10 @@ public sealed class MapHousePanelControllerTests
|
|||
|
||||
UiElement? map = UiElement.FindDescendant(controller!.Root, MapPageController.MapWidgetId);
|
||||
Assert.NotNull(map);
|
||||
// m_pMap's own children are the player/house icons (re-resolved
|
||||
// standalone — see MapPageController.Bind's doc on why m_pMap being
|
||||
// a Button swallows its authored nested children) PLUS the 53 town
|
||||
// hotspots.
|
||||
// m_pMap's own children are the player/house icons (found under the
|
||||
// panel-slot resolve tree and rebuilt via Bindings.IconBuilder — see
|
||||
// MapPageController.Bind's doc on why m_pMap being a Button swallows
|
||||
// its authored nested children) PLUS the 53 town hotspots.
|
||||
var townMarkers = map!.Children
|
||||
.Where(c => c.DatElementId != MapPageController.PlayerIconId
|
||||
&& c.DatElementId != MapPageController.HouseIconId)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue