feat(ui): House tab ownership text — DisplayPurchaseTimeText + RuntimeHouseState
Derived the mechanism from the decomp before writing code: neither gmHouseUI::PostInit @0x004a2710 nor gmMapUI::PostInit @0x004a1c70 sends a HouseQuery, and six of gmHouseUI's seven Display* builders early-return on m_pHouseData == 0. The only text a houseless character's House tab shows is gmHouseUI::DisplayPurchaseTimeText @0x004a3110's expired branch (it doesn't gate on m_pHouseData) — the local player's PropertyInt.HousePurchaseTimestamp plus HouseSystem::HasPurchaseWaitPeriodExpired renders exactly "You may buy another house immediately." for a fresh character. Exhaustive search of the 2013 EoR decomp, ACE, and the live DAT found zero support for a second "You do not currently own a house." line the task brief described — this commit ports what the decomp actually shows. Ships: - RuntimeHouseState: a minimal (no disposal, no construction-transaction Fault() point) Runtime owner per ISSUES #413's own sizing note, wired through GameEventWiring's existing HouseData/HouseStatus delegate holes, LiveSessionEventRouter, and GameRuntime.HouseOwner. Participates in RuntimeGenerationReset (new House stage) since a fresh login must not show a stale character's house state. - HousePageController.Bindings.Lines/OnShown wired to real data; OnShown fires WorldSession.SendHouseQuery() on tab-open (AD-107: an acdream trigger, not a ported retail call site — filed in the divergence register). - Fixed a real bug found along the way: HousePageController.Bind never wired UiTemplateListBox.TemplateResolver, so no row could ever render regardless of Lines content. Now reuses the Map tab's generic hotspot resolver. Live-verified against a real local ACE server and the +Acdream character (--session-config auto-select + a UI automation script): screenshot and structural UI-tree dump both confirm the House tab renders exactly "You may buy another house immediately." Graceful logout confirmed both launches. ISSUES #413 narrowed to its one remaining piece: the six owned-house-only Display* builders (DisplayBuyPayment/RentPayment/BuyTime/RentTimes/ Location/WarningText), unexercisable without a test character that owns a house. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
eb6f3bd8c8
commit
06512f0957
13 changed files with 601 additions and 99 deletions
|
|
@ -25,19 +25,22 @@ namespace AcDream.App.UI.Layout;
|
|||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>Scope (Batch C, 2026-08-17) — see ISSUES #413 for the full ledger.</b>
|
||||
/// This session shipped the mount (this class) and the wire PARSING
|
||||
/// <b>Scope — see ISSUES #413 for the full ledger.</b> Batch C
|
||||
/// (2026-08-17) shipped the mount (this class) and the wire PARSING
|
||||
/// groundwork (<c>GameEvents.ParseHouseData</c>/<c>ParseHouseStatus</c>/
|
||||
/// <c>ParseUpdateRentTime</c>/<c>ParseUpdateRentPayment</c>,
|
||||
/// <c>GameEventWiring</c>'s four delegate holes, the outbound HouseQuery
|
||||
/// action). <see cref="Bindings.Lines"/>/<see cref="Bindings.OnShown"/> are
|
||||
/// NOT yet wired to real data — no <c>RuntimeHouseState</c> owner exists,
|
||||
/// and none of the seven <c>Display*</c> line builders
|
||||
/// <c>DisplayHouseData</c> calls (including
|
||||
/// <c>DisplayPurchaseTimeText @0x004a3110</c>'s two fully-recovered
|
||||
/// literal strings) are ported. Until #413 closes, this page mounts with
|
||||
/// genuinely empty content — matching retail's own <c>PostInit</c>, which
|
||||
/// never calls <c>Update</c>/<c>DisplayHouseData</c> either.
|
||||
/// action). The House-tab ownership-text closer session (also 2026-08-17)
|
||||
/// wired <see cref="Bindings.Lines"/>/<see cref="Bindings.OnShown"/> to the
|
||||
/// minimal <c>RuntimeHouseState</c> owner and ported
|
||||
/// <c>DisplayPurchaseTimeText @0x004a3110</c>'s expired branch — a fresh
|
||||
/// houseless character's House tab now shows the single decomp-verified
|
||||
/// line "You may buy another house immediately." after the tab is opened,
|
||||
/// live-connected-gate-verified (screenshot + structural UI-tree dump
|
||||
/// against the real <c>+Acdream</c> character on a local ACE server). The
|
||||
/// other six <c>Display*</c> line builders <c>DisplayHouseData</c> calls
|
||||
/// (owned-house-only content: buy/rent payments and times, location,
|
||||
/// warning text) remain unported — ISSUES #413's surviving scope.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class HousePageController
|
||||
|
|
@ -52,7 +55,19 @@ public sealed class HousePageController
|
|||
// see ISSUES #413. NOT a ported retail call site (PostInit never
|
||||
// triggers a query) — an acdream convention, documented as such
|
||||
// (recon doc open item).
|
||||
Action? OnShown = null);
|
||||
Action? OnShown = null,
|
||||
// Batch C House-ownership-text closer (2026-08-17): the ListBox's
|
||||
// OWN row template (LayoutDesc 0x21000025 element 0x100001E7,
|
||||
// live-DAT-confirmed by MapHousePanelSlotProbeTests) is resolved
|
||||
// through the SAME generic (templateLayoutId, templateElementId) ->
|
||||
// UiElement seam MapPageController.Bindings.TemplateResolver already
|
||||
// wires for the Map tab's town hotspots — it performs the identical
|
||||
// LayoutImporter.ImportInfos+Build operation, nothing map-specific
|
||||
// about it. Without this, UiTemplateListBox.AddItemFromTemplateList
|
||||
// always returns null (no resolver = no row), so Refresh silently
|
||||
// produced zero rows regardless of Lines — the gap this session
|
||||
// closes alongside the text composition itself.
|
||||
Func<uint, uint, UiElement?>? TemplateResolver = null);
|
||||
|
||||
private readonly UiTemplateListBox _listBox;
|
||||
private readonly Bindings _bindings;
|
||||
|
|
@ -76,6 +91,7 @@ public sealed class HousePageController
|
|||
return null;
|
||||
}
|
||||
|
||||
listBox.TemplateResolver = bindings.TemplateResolver;
|
||||
var controller = new HousePageController(listBox, bindings);
|
||||
controller.Refresh(bindings.Lines());
|
||||
return controller;
|
||||
|
|
|
|||
|
|
@ -3339,7 +3339,11 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
TemplateResolver: ResolveHotspotTemplate),
|
||||
House: new Layout.HousePageController.Bindings(
|
||||
Lines: mh.HouseLines ?? (static () => Array.Empty<string>()),
|
||||
OnShown: mh.HouseShown));
|
||||
OnShown: mh.HouseShown,
|
||||
// Same generic template resolver the Map tab's town
|
||||
// hotspots use — see HousePageController.Bindings.
|
||||
// TemplateResolver's own doc for why reusing it is correct.
|
||||
TemplateResolver: ResolveHotspotTemplate));
|
||||
|
||||
Layout.MapHousePanelController? controller;
|
||||
lock (_bindings.Assets.DatLock)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue