fix(chat): translate WeenieError templates + strip Tell target punctuation + Turbine routing diagnostics

Three post-launch fixes from the 2026-04-25 live verify session.

1. WeenieError display bug. Many ACE WeenieError / WeenieErrorWithString
   codes are *informational*, not error-level — the user saw cryptic
   "WeenieError 0x051B: General" / "WeenieError 0x051D" at login, but
   those decode as "You have entered the General channel." and
   "Turbine Chat is enabled." per ACE WeenieError(WithString).cs
   templates. New static helper Core/Chat/WeenieErrorMessages.cs maps
   ~30 high-frequency codes to retail-faithful templates with `_`
   placeholder substitution. ChatLog.OnWeenieError now routes through
   Format(); unknown codes still fall back to "WeenieError 0xNNNN[: param]"
   so nothing is silently lost. New codes can be added in 30 seconds
   when the user reports one.

2. Tell target eats trailing punctuation. Retail muscle memory is
   "/t Name, message" — comma is the separator. Our split-on-whitespace
   pulled "Name," (with comma) as the target, server returned 0x052B
   "That person is not available now." because no such character.
   ChatInputParser.TryParseTargeted now strips a trailing ,;:.!? from
   the target token so "/t Caith, hi" and "/t Caith hi" both work.
   Added 7 Theory cases covering each separator + the long-form alias.

3. TurbineChat routing diagnostics. The user's ACE login showed the
   "TurbineChatIsEnabled" + "YouHaveEnteredThe_Channel" notifications
   for General/Trade/LFG, confirming TurbineChat IS active server-side.
   But outbound /g /trade /lfg might still fall back to legacy
   ChatChannel (which the server then rejects). Added diagnostic
   Console.WriteLines so the next launch shows:
     - "chat: SetTurbineChatChannels parsed enabled=true general=0x... ..."
       (when ACE sends the 0x0295 channel-id table)
     - "chat: outbound TurbineChat General room=0x... cookie=0x... len=N"
       (when SendChatCmd routes a Turbine kind through 0xF7DE)
     - "chat: outbound legacy ChatChannel Fellowship id=0x... len=N"
       (when SendChatCmd uses the legacy 0x0147 path)
     - "chat: SendChatCmd kind=General dropped (turbine.Enabled=false no legacy id)"
       (when neither path can dispatch — usually means ACE didn't send
       0x0295 yet and the kind is Turbine-only)

   Sets up Bug 3 (proper outbound TurbineChat for /g /trade /lfg) for
   a follow-up commit once the next live trace shows the actual flow.

18 new tests:
- WeenieErrorMessagesTests: 11 covering known templates + fallback.
- ChatInputParserTests: +7 Theory cases for trailing-punctuation strip.

Solution total: 1007 green (114 UI + 650 Core + 243 Core.Net), 0 warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-25 20:31:23 +02:00
parent 762df152d1
commit e17caa2942
7 changed files with 338 additions and 4 deletions

View file

@ -1312,6 +1312,10 @@ public sealed class GameWindow : IDisposable
uint senderGuid = _playerServerGuid != 0u
? _playerServerGuid
: playerGuid;
Console.WriteLine(
$"chat: outbound TurbineChat {turbine.Value.DisplayName} " +
$"room=0x{turbine.Value.RoomId:X8} chatType={turbine.Value.ChatType} " +
$"cookie=0x{cookie:X} sender=0x{senderGuid:X8} len={cmd.Text.Length}");
liveSession.SendTurbineChatTo(
roomId: turbine.Value.RoomId,
chatType: turbine.Value.ChatType,
@ -1326,7 +1330,22 @@ public sealed class GameWindow : IDisposable
}
var resolved = AcDream.UI.Abstractions.ChannelResolver.Resolve(cmd.Channel);
if (resolved is null) return;
if (resolved is null)
{
// Diagnostic: the user picked a channel kind that
// (a) isn't a Turbine channel TurbineChatState
// knows about and (b) has no legacy ChatChannel
// mapping. Most common cause: TurbineChat hasn't
// been enabled yet (server didn't send 0x0295)
// and the kind is General/Trade/LFG/etc.
Console.WriteLine(
$"chat: SendChatCmd kind={cmd.Channel} dropped " +
$"(turbine.Enabled={turbineChat.Enabled} no legacy id)");
return;
}
Console.WriteLine(
$"chat: outbound legacy ChatChannel {resolved.Value.DisplayName} " +
$"id=0x{resolved.Value.ChannelId:X8} len={cmd.Text.Length}");
liveSession.SendChannel(resolved.Value.ChannelId, cmd.Text);
chat.OnSelfSent(
AcDream.Core.Chat.ChatKind.Channel, cmd.Text,