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>
112 lines
3.9 KiB
C#
112 lines
3.9 KiB
C#
using AcDream.Core.Chat;
|
|
|
|
namespace AcDream.Core.Tests.Chat;
|
|
|
|
/// <summary>
|
|
/// Tests for <see cref="WeenieErrorMessages"/>. The retail client showed
|
|
/// these as plain-language strings; we mirror that via templated lookup.
|
|
/// Filed after the 2026-04-25 live launch where the user saw cryptic
|
|
/// "WeenieError 0x051B" in chat for what was actually a friendly login
|
|
/// notification.
|
|
/// </summary>
|
|
public sealed class WeenieErrorMessagesTests
|
|
{
|
|
// ── known codes — informational, parameterised ───────────────────
|
|
|
|
[Fact]
|
|
public void Format_YouHaveEnteredChannel_SubstitutesParam()
|
|
{
|
|
// 0x051B = WeenieErrorWithString.YouHaveEnteredThe_Channel.
|
|
// Template "You have entered the _ channel." with `_` placeholder.
|
|
Assert.Equal(
|
|
"You have entered the General channel.",
|
|
WeenieErrorMessages.Format(0x051B, "General"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_YouHaveEnteredChannel_WorksForEachChannelName()
|
|
{
|
|
Assert.Equal("You have entered the Trade channel.", WeenieErrorMessages.Format(0x051B, "Trade"));
|
|
Assert.Equal("You have entered the LFG channel.", WeenieErrorMessages.Format(0x051B, "LFG"));
|
|
Assert.Equal("You have entered the Roleplay channel.",WeenieErrorMessages.Format(0x051B, "Roleplay"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_YouHaveLeftChannel_SubstitutesParam()
|
|
{
|
|
Assert.Equal(
|
|
"You have left the General channel.",
|
|
WeenieErrorMessages.Format(0x051C, "General"));
|
|
}
|
|
|
|
// ── known codes — informational, no parameter ────────────────────
|
|
|
|
[Fact]
|
|
public void Format_TurbineChatIsEnabled_NoParamForm()
|
|
{
|
|
// 0x051D came in WeenieError (no param) form at login.
|
|
Assert.Equal(
|
|
"Turbine Chat is enabled.",
|
|
WeenieErrorMessages.Format(0x051D, param: null));
|
|
}
|
|
|
|
// ── known codes — error-level ────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void Format_CharacterNotAvailable_NoParam()
|
|
{
|
|
// 0x052B fired by the server when a Tell target lookup fails
|
|
// (e.g. the user typed "/t je, hello" → server got "je," → no
|
|
// character). Should read like the retail message.
|
|
Assert.Equal(
|
|
"That person is not available now.",
|
|
WeenieErrorMessages.Format(0x052B, param: null));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_TradeComplete()
|
|
{
|
|
Assert.Equal("Trade Complete!", WeenieErrorMessages.Format(0x0529, null));
|
|
}
|
|
|
|
// ── unknown codes — graceful fallback preserves debug info ───────
|
|
|
|
[Fact]
|
|
public void Format_UnknownCode_NoParam_FallsBackToHexForm()
|
|
{
|
|
Assert.Equal("WeenieError 0xABCD", WeenieErrorMessages.Format(0xABCD, null));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_UnknownCode_WithParam_FallsBackToColonForm()
|
|
{
|
|
Assert.Equal(
|
|
"WeenieError 0xDEAD: Mana Stone",
|
|
WeenieErrorMessages.Format(0xDEAD, "Mana Stone"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_UnknownCode_EmptyParam_StaysAsHexOnly()
|
|
{
|
|
// Empty string param shouldn't add a stray colon.
|
|
Assert.Equal("WeenieError 0xCAFE", WeenieErrorMessages.Format(0xCAFE, ""));
|
|
}
|
|
|
|
// ── parameterised templates with non-trivial params ──────────────
|
|
|
|
[Fact]
|
|
public void Format_HearListAdded_SubstitutesParam()
|
|
{
|
|
Assert.Equal(
|
|
"Caith has been added to the list of people you can hear.",
|
|
WeenieErrorMessages.Format(0x0521, "Caith"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Format_FailToAffectCannotBeHarmed_SubstitutesParam()
|
|
{
|
|
Assert.Equal(
|
|
"You fail to affect Drudge because they cannot be harmed!",
|
|
WeenieErrorMessages.Format(0x004F, "Drudge"));
|
|
}
|
|
}
|