fix(chat): Campaign CH round 3 — SpewBox flush-top/font, /help exact print sequence
User-gate round 3 findings (a)-(c):
(a) SpewBox: TopOffset moves from the round-1 60px placeholder to 0 (flush
to the viewport top). SpewBoxController never wired DatFont/Font at all
before this round, so it silently rendered through the 15px debug
BitmapFont fallback; it now resolves retail dat Font 0x40000025
(MaxCharHeight=11px) through a new RetailUiRuntime.Assets accessor —
the smallest font id confirmed in use by any currently-imported retail
LayoutDesc fixture, cross-referenced against every
tests/AcDream.App.Tests/UI/Layout/fixtures/*.json dump and confirmed
against the installed DAT via AcDream.Cli dump-font-atlas. It is also the
chat window's own smallest font (the 0x2100006F floating-window 1/2/3/4
indicator badges), so both selection criteria the brief offered agree.
Both remain best-available approximations, not resolved retail values —
register row AP-178 updated accordingly.
(b)/(c) /help and /help death: round 2 extracted the individual retail
strings byte-exact but never traced ClientCommunicationSystem::DoHelp's
complete print sequence. Byte-swept DoHelp's own range plus the five
Summary-branch functions it calls into (HelpEmote/HelpSquelch/
HelpStatusGroup/HelpTextGroup/HelpAllGroup) against the PDB-paired
acclient.exe. Retail's real shape: bare /help prints exactly TWO scroll
entries (HelpPrefixNote, then the 13-item AvailableHelpListing built from
DoHelp's own literals and each group's Summary_HelpType branch, in exact
source order) — not the acdream-invented cheat sheet BuildHelpText()
built before. Any resolved /help <verb> gets the SAME two-entry shape:
HelpPrefixNote, then ForMoreInformationPrefix concatenated directly onto
the verb's own Detail text (retail's own unsubstituted "<command>"
literal, ported verbatim). ChatCommandRouter.EmitVerbHelp applies this
uniformly to every resolved verb, not just death. An unresolved verb now
shows retail's real "Unknown command" fallback text; that fallback types
0x1A (ClientLocal), which retail routes to the SpewBox exclusively — a
gap ChatVM's UI.Abstractions layer can't yet reach, filed as ISSUES #367
/ register AP-186 rather than left silently unregistered.
Jump-in-air (round 2's open item 1) was root-caused and fixed separately
at a5a7eb4f between rounds — recorded in the campaign ledger.
Debug suite (all projects): 12,329 passed / 4 skipped / 1 failed — the
one failure is issue #351, a pre-existing Debug-only streaming flake
confirmed reproducing identically on the pristine pre-round-3 commit via
git stash, not a regression. Release verification covers every project
reachable without rebuilding AcDream.App: a live client process (PID
15064) held its own Release binaries locked for the session and was not
killed per project policy — AcDream.UI.Abstractions.Tests (867/867, the
layer both /help fixes live in) plus every other non-App-dependent
project, all 0 failed. AcDream.App/AcDream.App.Tests/AcDream.Core.Tests
(the SpewBox fix's layer) are green in Debug only this session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
a5a7eb4fb6
commit
98de4f5ab3
14 changed files with 665 additions and 105 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.UI.Abstractions.Panels.SpewBox;
|
||||
|
||||
|
|
@ -67,19 +68,73 @@ namespace AcDream.App.UI;
|
|||
/// the divergence register rows this class cites for each remaining
|
||||
/// placeholder.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// <b>Campaign CH user-gate round 3 (2026-08-10), finding (a) — position
|
||||
/// and font.</b> The user reported live: "still not aligned all the way to
|
||||
/// the top" and "not the correct font and size (retail's is SMALLER than
|
||||
/// ours)". Two changes, both still user-DIRECTED approximations (not
|
||||
/// resolved retail values — the true absolute position/parent and the true
|
||||
/// retail font remain unmeasurable statically; <c>SpewBoxLayoutDumpDiagnostic</c>
|
||||
/// re-run this round still finds no <c>FontDid</c>/colour property on
|
||||
/// element <c>0x10000048</c> or its ListBox child):
|
||||
/// <list type="bullet">
|
||||
/// <item><b>Position:</b> <see cref="TopOffset"/> is now <c>0</c> — flush
|
||||
/// to the viewport top, per the user's explicit direction ("mount at
|
||||
/// viewport top-center, exactly"). The centered-X, recompute-every-frame
|
||||
/// behavior from CH2 nit 1 is unchanged.</item>
|
||||
/// <item><b>Font:</b> <see cref="SpewBoxController"/> now accepts a
|
||||
/// resolved <see cref="UiDatFont"/> (retail font id
|
||||
/// <see cref="RetailFontId"/>, <c>0x40000025</c>) instead of silently
|
||||
/// falling back to the debug <see cref="BitmapFont"/> at its ad hoc 15px
|
||||
/// pixel height (the pre-round-3 behavior — no <c>DatFont</c>/<c>Font</c>
|
||||
/// was ever wired here at all). <c>0x40000025</c> is <c>MaxCharHeight=11</c>
|
||||
/// px (confirmed via <c>AcDream.Cli dump-font-atlas</c> against the
|
||||
/// installed DAT, sweeping every populated font id
|
||||
/// <c>0x40000000</c>-<c>0x40000032</c>) — the SMALLEST font id actually
|
||||
/// confirmed IN USE by any of acdream's currently-imported retail
|
||||
/// LayoutDesc fixtures (cross-referenced across every
|
||||
/// <c>tests/AcDream.App.Tests/UI/Layout/fixtures/*.json</c> dump), and
|
||||
/// it is ALSO the chat window's own smallest font — the same
|
||||
/// <c>0x2100006F</c> floating-window 1/2/3/4 indicator badges
|
||||
/// (<c>ChatWindowController.Indicator1-4Id</c>) use it. Both selection
|
||||
/// criteria from the round-3 brief ("smallest DAT font used by retail UI
|
||||
/// imports" vs "the chat window's own font, whichever is smaller") land
|
||||
/// on the SAME id, so there was no tension to resolve. This is visibly
|
||||
/// smaller than the previous 15px debug font, matching the user's
|
||||
/// report. Falls back to the debug font only if the dat resolve fails
|
||||
/// (matching every other retained-UI controller's pattern, e.g.
|
||||
/// <c>ChatWindowController.Bind</c>).</item>
|
||||
/// </list>
|
||||
/// Register row AP-178 updated to record both dispositions.
|
||||
/// </remarks>
|
||||
internal sealed class SpewBoxController : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Retail dat Font id this controller resolves for its text
|
||||
/// (Campaign CH user-gate round 3 — see the class remarks). Not
|
||||
/// retail's own measured SpewBox font (unmeasurable — no FontDid
|
||||
/// property was found on the authored element); the smallest DAT font
|
||||
/// confirmed in use by any currently-imported retail LayoutDesc,
|
||||
/// chosen so the rendered text is visibly smaller than the prior debug
|
||||
/// fallback, per the user's report.
|
||||
/// </summary>
|
||||
internal const uint RetailFontId = 0x40000025u;
|
||||
|
||||
/// <summary>
|
||||
/// Register row AP-178 (screen position): retail's authored ABSOLUTE
|
||||
/// screen position is still unknown — the LayoutDesc dump (see class
|
||||
/// remarks) recovered the element's position as <c>(0,0)</c> relative
|
||||
/// to a PARENT this sweep could not identify, so this centered-top
|
||||
/// placement remains acdream's own choice, not a resolved retail value.
|
||||
/// (The SIBLING row AP-177 — the invented line-lifetime timeout — lives
|
||||
/// in <see cref="SpewBoxState.DefaultLifetime"/>'s own doc comment, not
|
||||
/// to a PARENT this sweep could not identify. Campaign CH user-gate
|
||||
/// round 3 (2026-08-10): the user reported the box was not flush to
|
||||
/// the very top of the screen; mounted at <c>0</c> now, per explicit
|
||||
/// user direction — still acdream's own placement choice pending the
|
||||
/// true retail parent/offset, but now matching the user's live report
|
||||
/// instead of an arbitrary 60px placeholder. (The SIBLING row AP-177 —
|
||||
/// the invented line-lifetime timeout — lives in
|
||||
/// <see cref="SpewBoxState.DefaultLifetime"/>'s own doc comment, not
|
||||
/// here; this controller does not own that concern.)
|
||||
/// </summary>
|
||||
private const float TopOffset = 60f;
|
||||
private const float TopOffset = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Register row AP-178 (extent): AUTHORED, not a placeholder — the
|
||||
|
|
@ -121,9 +176,10 @@ internal sealed class SpewBoxController : IDisposable
|
|||
/// (research doc §3.2.3); the LayoutDesc dump (see class remarks) also
|
||||
/// never surfaced a colour property for this element. The exact retail
|
||||
/// value simply happens to coincide with the Tell colour, per the user's
|
||||
/// live observation. SIZE/POSITION/FONT remain OPEN — the user reports
|
||||
/// all three still differ from retail; user gate round 1: differs,
|
||||
/// iterating.
|
||||
/// live observation. POSITION and FONT were re-addressed at Campaign CH
|
||||
/// user-gate round 3 (2026-08-10) — see the class remarks and the
|
||||
/// <see cref="TopOffset"/>/<see cref="RetailFontId"/> comments; both
|
||||
/// remain acdream-directed approximations, not resolved retail values.
|
||||
/// </summary>
|
||||
private static readonly Vector4 SpewBoxColor = new(1f, 1f, 0.247f, 1f);
|
||||
|
||||
|
|
@ -134,7 +190,18 @@ internal sealed class SpewBoxController : IDisposable
|
|||
private UiText.Line[] _lines = Array.Empty<UiText.Line>();
|
||||
private bool _disposed;
|
||||
|
||||
public SpewBoxController(UiRoot root, SpewBoxVM vm)
|
||||
/// <param name="root">Retained-UI root this element mounts under.</param>
|
||||
/// <param name="vm">SpewBox view-model (bounded, newest-on-top queue).</param>
|
||||
/// <param name="font">
|
||||
/// Resolved retail dat font (<see cref="RetailFontId"/>) — Campaign CH
|
||||
/// user-gate round 3. Null falls back to <paramref name="debugFont"/>,
|
||||
/// matching every other retained-UI controller's dat-font pattern (e.g.
|
||||
/// <c>ChatWindowController.Bind</c>).
|
||||
/// </param>
|
||||
/// <param name="debugFont">Fallback bitmap font, used only when
|
||||
/// <paramref name="font"/> is null.</param>
|
||||
public SpewBoxController(
|
||||
UiRoot root, SpewBoxVM vm, UiDatFont? font = null, BitmapFont? debugFont = null)
|
||||
{
|
||||
_root = root ?? throw new ArgumentNullException(nameof(root));
|
||||
_vm = vm ?? throw new ArgumentNullException(nameof(vm));
|
||||
|
|
@ -152,6 +219,12 @@ internal sealed class SpewBoxController : IDisposable
|
|||
Height = SpewBoxHeight,
|
||||
Anchors = AnchorEdges.None,
|
||||
Centered = true,
|
||||
// Campaign CH user-gate round 3: retail dat font (RetailFontId)
|
||||
// when resolved, falling back to the debug bitmap font exactly
|
||||
// like every other retained-UI controller (ChatWindowController
|
||||
// et al.) — see the class remarks.
|
||||
DatFont = font,
|
||||
Font = debugFont,
|
||||
// AUTHORED MaxConcurrentItems is 4, not retail's code-default 1
|
||||
// (see SpewBoxState.MaxConcurrentItems) — OneLine=true would
|
||||
// silently collapse the box back down to showing only the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue