fix(chat): #363 — retail 0x1A typing for command refusals via the interface-text seam
ChatVM gains an OnInterfaceText hook + ShowInterfaceText(text), the
App-layer composition wires it to RuntimeCommunicationState.AddText,
and ChatCommandRouter routes every retail-0x1A command refusal through
it instead of the chat log's 0x00 sink. UI.Abstractions still never
references Runtime directly; unwired hosts (headless, tests) fall back
to the chat log tagged ClientLocal so no text is ever silently lost.
Reclassified per register row AP-183 (DoChannelList/On/Off, DoAllegiance,
DoHouseAvailableList — the last also corrected to retail's own bad-house-
type string instead of a synthesized "Usage:" line) and newly wired two
sites that previously showed nothing at all (DoStupidChannelHack's bare
legacy-channel-verb refusal, DoReply's message-but-no-last-teller
refusal). The generic bad-args fallback now resolves WeenieErrorMessages
0x026 ("That is not a valid command.", retail's HandleFailureEvent(0x26))
instead of synthesizing "Usage: {Usage}". DoSpeaker/DoEndurance/DoTitle
are untouched — already correct at 0x00.
Also closes #367 (DoHelp's "Unknown command" fallback and the degenerate-
prefix refusal now reach the SpewBox too) and retires register row
AP-186, whose own filing proposed exactly this seam shape.
Full Release suite: 12,542 passed / 4 skipped / 0 failed (baseline
12,466/4/0 at ff2784ea).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff2784eaa4
commit
09453ecae8
14 changed files with 702 additions and 106 deletions
|
|
@ -73,6 +73,21 @@ public sealed class ChatVM : IDisposable
|
|||
/// </summary>
|
||||
public Func<Vector3>? PositionProvider { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional hook routing retail-<c>0x1A</c> (<see
|
||||
/// cref="RetailLogTextType.ClientLocal"/>) interface text — command
|
||||
/// refusals and bad-argument usage lines — to the SpewBox instead of
|
||||
/// the chat transcript. <c>AcDream.UI.Abstractions</c> must stay
|
||||
/// Runtime-independent (Code Structure Rules), so it cannot call
|
||||
/// <c>RuntimeCommunicationState.AddText</c> directly; the App-layer
|
||||
/// composition host wires this the same way it wires
|
||||
/// <see cref="FpsProvider"/>/<see cref="PositionProvider"/>. Closes
|
||||
/// ISSUES.md #367 / register row AP-186 — <see cref="ChatCommandRouter"/>
|
||||
/// no longer has to render every <c>0x1A</c> refusal through the chat
|
||||
/// scroll.
|
||||
/// </summary>
|
||||
public Action<string>? OnInterfaceText { get; init; }
|
||||
|
||||
/// <summary>Monotonic revision of the underlying transcript content.</summary>
|
||||
public long Revision => _log.Revision;
|
||||
|
||||
|
|
@ -139,6 +154,33 @@ public sealed class ChatVM : IDisposable
|
|||
/// </remarks>
|
||||
public void ShowSystemMessage(string text) => _log.OnSystemMessage(text, chatType: 0x00u);
|
||||
|
||||
/// <summary>
|
||||
/// Route a retail-<c>0x1A</c> (<see cref="RetailLogTextType.ClientLocal"/>)
|
||||
/// command refusal / usage line to the SpewBox — retail's
|
||||
/// <c>ClientSystem::AddTextToScroll(text, 0x1A, 1, windowId) @0x00563C50</c>
|
||||
/// destination for this text type is the SpewBox exclusively, never a
|
||||
/// chat window (<c>docs/research/2026-08-09-chat-retail-interface-text.md</c>
|
||||
/// §2.1/§2.2).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Prefers <see cref="OnInterfaceText"/> when the App-layer host wired
|
||||
/// it (the production graphical client). When unwired — headless, the
|
||||
/// automation probe runner, or a test fixture that only exercises the
|
||||
/// pure UI.Abstractions layer — the text still needs to reach the
|
||||
/// player somewhere, so it falls back to the ordinary chat transcript
|
||||
/// tagged with the real <see cref="RetailLogTextType.ClientLocal"/>
|
||||
/// color rather than being silently dropped. That fallback lands in
|
||||
/// the wrong PANEL (chat instead of SpewBox) but keeps the right TYPE
|
||||
/// and never loses the line — the safe default issue #363 requires.
|
||||
/// </remarks>
|
||||
public void ShowInterfaceText(string text)
|
||||
{
|
||||
if (OnInterfaceText is { } hook)
|
||||
hook(text);
|
||||
else
|
||||
_log.OnSystemMessage(text, chatType: (uint)RetailLogTextType.ClientLocal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drain the chat log. Used by the /clear client-side command.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue