feat(net+chat): #19 TurbineChat (0xF7DE) codec + ChatChannelInfo + SetTurbineChatChannels parser
Full port of holtburger's TurbineChat sidecar wire path: - TurbineChat.cs: 0xF7DE codec with three payload variants (EventSendToRoom S->C, RequestSendToRoomById C->S, Response). 10-field outer header (size_first/blob_type/dispatch_type/ target_type/target_id/transport_type/transport_id/cookie/ size_second + payload). - UTF-16LE turbine string codec with 1-or-2 byte variable-length prefix (high bit on first byte signals 2-byte form). Mirrors holtburger's read_turbine_string / write_turbine_string at references/holtburger/.../messages/chat/turbine.rs:502-544. - SetTurbineChatChannels.cs: 0x0295 GameEvent sub-opcode parser (10 x u32 channel ids). Wired through GameEventDispatcher in WorldSession ctor; routes to GameEventWiring + TurbineChatState. - ChatChannelInfo.cs (Core): unified record union with Legacy (channel id + name) and Turbine (room id + chat type + dispatch type + name) variants, plus IsSelfEchoChannel predicate (Tells = false, channels = true so optimistic echo is suppressed where the server will echo). - TurbineChatState.cs (Core): Enabled flag + 10 cached room ids + NextContextId() cookie counter starting at 1. - WorldSession adds TurbineChatReceived + TurbineChannelsReceived events; SendTurbineChatTo outbound builds RequestSendToRoomById + sends through SendGameAction. ProcessDatagram dispatches 0xF7DE at the top level. - GameWindow constructs TurbineChatState, subscribes inbound EventSendToRoom -> ChatLog.OnChannelBroadcast; extends I.3's SendChatCmd handler to route Turbine kinds (General/Trade/Lfg/ Roleplay/Society/Olthoi) through TurbineChat first, fall back to legacy ChatChannel send when state.Enabled == false. Round-trip golden fixtures from holtburger source verified for all three payload variants + UTF-16LE strings (short + long prefix + non-ASCII Cafe + empty) + SetTurbineChatChannels. 26 new tests: - TurbineChatTests, SetTurbineChatChannelsTests in Core.Net.Tests - ChatChannelInfoTests, TurbineChatStateTests in Core.Tests Solution total: 960 green (243 Core.Net + 625 Core + 92 UI). ACE doesn't run a TurbineChat server, so codec is "ready when needed" for retail-server-emulating setups. Legacy ChatChannel fallback continues to work for current ACE-against-acdream play. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f14296c75f
commit
ca968fc766
11 changed files with 1604 additions and 8 deletions
|
|
@ -36,7 +36,8 @@ public static class GameEventWiring
|
|||
CombatState combat,
|
||||
Spellbook spellbook,
|
||||
ChatLog chat,
|
||||
LocalPlayerState? localPlayer = null)
|
||||
LocalPlayerState? localPlayer = null,
|
||||
TurbineChatState? turbineChat = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dispatcher);
|
||||
ArgumentNullException.ThrowIfNull(items);
|
||||
|
|
@ -66,6 +67,34 @@ public static class GameEventWiring
|
|||
if (s is not null) chat.OnPopup(s);
|
||||
});
|
||||
|
||||
// ── TurbineChat channel list (0x0295 SetTurbineChatChannels) ─────
|
||||
// Phase I.6: arrives once at login (and after chat-server reconnect)
|
||||
// listing the per-session room ids assigned to General / Trade /
|
||||
// LFG / Roleplay / Society / Olthoi (and the optional Allegiance
|
||||
// Turbine room). Without this the TurbineChat outbound path stays
|
||||
// disabled and the chat panel falls back to the legacy ChatChannel
|
||||
// GameAction. See holtburger client/messages.rs:220-223 for the
|
||||
// server-message handling pattern.
|
||||
if (turbineChat is not null)
|
||||
{
|
||||
dispatcher.Register(GameEventType.SetTurbineChatChannels, e =>
|
||||
{
|
||||
var p = SetTurbineChatChannels.TryParse(e.Payload.Span);
|
||||
if (p is null) return;
|
||||
turbineChat.OnChannelsReceived(
|
||||
allegianceRoom: p.Value.AllegianceRoom,
|
||||
generalRoom: p.Value.GeneralRoom,
|
||||
tradeRoom: p.Value.TradeRoom,
|
||||
lfgRoom: p.Value.LfgRoom,
|
||||
roleplayRoom: p.Value.RoleplayRoom,
|
||||
olthoiRoom: p.Value.OlthoiRoom,
|
||||
societyRoom: p.Value.SocietyRoom,
|
||||
societyCelestialHandRoom: p.Value.SocietyCelestialHandRoom,
|
||||
societyEldrytchWebRoom: p.Value.SocietyEldrytchWebRoom,
|
||||
societyRadiantBloodRoom: p.Value.SocietyRadiantBloodRoom);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Errors ───────────────────────────────────────────────
|
||||
// Phase I.5: WeenieError + WeenieErrorWithString parsers existed
|
||||
// (GameEvents.ParseWeenieError(WithString)) but were never registered.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue