fix(chat): /help client-side handler + System dedup + ThatIsNotAValidCommand template
Phase J follow-up after a 2026-04-25 trace where typing /help
produced two identical "Unknown command: help" lines (ACE fires the
text via both GameMessageSystemChat 0xF7E0 and a paired
CommunicationTransientString 0x02EB), and the server's WeenieError
0x0026 trailer rendered cryptically as "WeenieError 0x0026".
Three small changes:
1. WeenieErrorMessages: add 0x0026 ThatIsNotAValidCommand ->
"That is not a valid command." Plus 0x0414 / 0x050F that Phase J
already added are now covered by tests too.
2. ChatLog.OnSystemMessage dedup. Track last system text + arrival
time; if a second identical text shows up within 1 second,
suppress. ACE's two-path send (gag warnings, command errors,
etc.) collapses to a single chat line. Long bursts of repeated
text still skip the duplicates without resetting the timer.
3. Client-side /help and /clear in ChatPanel. Intercepted BEFORE
the parser passes to the server bus:
- /help, /?, /h (case-insensitive) -> render local cheat-sheet
listing acdream's slash prefixes via ChatLog.OnSystemMessage.
Avoids the round-trip to ACE that produced the duplicate
"Unknown command: help" lines AND gives users discoverability.
- /clear, /cls -> drains the chat log so the panel starts empty.
New ChatVM.ShowSystemMessage() + ChatVM.Clear() expose the
minimum surface the panel needs to dispatch client-only feedback
without coupling the panel to ChatLog directly.
12 new tests:
- 3 WeenieErrorMessages template adds (0x0026 / 0x0414 / 0x050F).
- 4 ChatLog dedup cases (immediate dup, different text, triplet,
bookended-by-different-text).
- 5 ChatPanel client-command cases (/help, 3 alias variants,
/clear).
Solution total: 1033 green (243 Core.Net + 130 UI + 660 Core),
0 warnings.
Acceptance: type /help in chat -> local help banner appears, no
server round-trip, no "Unknown command: help" duplicates. Type
/clear -> chat tail empty. Welcome banner + WeenieError-templated
"You are not in an allegiance!" / "You do not belong to a
Fellowship." continue rendering once each.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7726f62528
commit
3501194083
7 changed files with 269 additions and 2 deletions
|
|
@ -26,6 +26,17 @@ public sealed class ChatLog
|
|||
private readonly int _maxEntries;
|
||||
private uint _localPlayerGuid;
|
||||
|
||||
// Phase J follow-up: ACE often sends the same system text via two
|
||||
// wire paths (GameMessageSystemChat 0xF7E0 + GameEventCommunication-
|
||||
// TransientString 0x02EB) for back-compat — we wired both to
|
||||
// OnSystemMessage in I.5/J, so the user saw lines like "Unknown
|
||||
// command: help" twice. Dedupe within a short window: track the
|
||||
// last system text + arrival time; if a second identical text
|
||||
// shows up within one second, skip.
|
||||
private string _lastSystemText = "";
|
||||
private DateTime _lastSystemAt = DateTime.MinValue;
|
||||
private static readonly TimeSpan SystemDedupWindow = TimeSpan.FromSeconds(1);
|
||||
|
||||
public ChatLog(int maxEntries = 500)
|
||||
{
|
||||
if (maxEntries < 1) throw new ArgumentOutOfRangeException(nameof(maxEntries));
|
||||
|
|
@ -178,9 +189,28 @@ public sealed class ChatLog
|
|||
ChannelId: 0));
|
||||
}
|
||||
|
||||
/// <summary>GameEvent CommunicationTransientString (0x02EB) — e.g. "Your spell fizzled!"</summary>
|
||||
/// <summary>
|
||||
/// System chat — covers GameMessageSystemChat (0xF7E0
|
||||
/// ServerMessage) and GameEventCommunicationTransientString
|
||||
/// (0x02EB). Phase J follow-up: dedupe identical text arriving
|
||||
/// within <see cref="SystemDedupWindow"/> so flows that fire on
|
||||
/// both opcodes (e.g. "Unknown command: help" via help-command
|
||||
/// failure path) only show once.
|
||||
/// </summary>
|
||||
public void OnSystemMessage(string text, uint chatType)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (text == _lastSystemText && (now - _lastSystemAt) < SystemDedupWindow)
|
||||
{
|
||||
// Suppress the dup — the wire-level duplicate isn't a
|
||||
// user-meaningful signal. Reset the timer so a long burst
|
||||
// of the same text still skips.
|
||||
_lastSystemAt = now;
|
||||
return;
|
||||
}
|
||||
_lastSystemText = text;
|
||||
_lastSystemAt = now;
|
||||
|
||||
Append(new ChatEntry(
|
||||
Kind: ChatKind.System,
|
||||
Sender: "",
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ public static class WeenieErrorMessages
|
|||
/// </summary>
|
||||
private static readonly Dictionary<uint, string> NoParamTemplates = new()
|
||||
{
|
||||
// Command parser
|
||||
[0x0026] = "That is not a valid command.", // ThatIsNotAValidCommand
|
||||
|
||||
// Tell-related
|
||||
[0x052B] = "That person is not available now.", // CharacterNotAvailable
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue