namespace AcDream.Core.Chat; /// /// Source/transport classification for a chat channel — distinguishes /// retail's two parallel chat channel pipelines. /// public enum ChatChannelSource { /// Legacy ChatChannel bitflag id rides 0x0147 ChatChannel. Legacy, /// Turbine room id rides 0xF7DE TurbineChat. Turbine, } /// /// Unified info about a chat channel — either a legacy ChatChannel id /// (Fellowship, Allegiance, Vassals, Patron, Monarch, CoVassals) or a /// Turbine room id (General, Trade, LFG, Roleplay, Society*, Olthoi). /// /// /// Mirrors holtburger's ChatChannelInfo /// (references/holtburger/crates/holtburger-core/src/client/types.rs /// lines 63-102). The two retail channel pipelines run side by side — /// legacy ChatChannel for the player-organisation channels and /// TurbineChat for the global community rooms — and a single /// abstraction over both keeps the chat panel and command bus from /// having to special-case the transport at every call site. /// /// /// /// tells callers whether the server /// echoes the client's own outgoing messages back on this channel /// (so the client should suppress its optimistic local echo). Per /// holtburger's predicate at chat.rs::is_self_echo_channel /// (lines 492-507) this is true ONLY for the legacy fellowship/vassals/ /// patron/monarch/co-vassals channels — server resends those with /// empty sender. Turbine and tells do not echo. /// /// public abstract record ChatChannelInfo(string DisplayName, ChatChannelSource Source) { /// Legacy ChatChannel bitflag id (0x00000800 etc.). public sealed record Legacy(uint ChannelId, string DisplayName) : ChatChannelInfo(DisplayName, ChatChannelSource.Legacy) { public override bool IsSelfEchoChannel() { // Per holtburger: the legacy fellowship + allegiance-tree // channels are the ones the server echoes back to the sender // with an empty sender field. Bitflag values from // references/holtburger/.../messages/chat/types.rs::ChatChannel. return ChannelId switch { 0x00000800u => true, // Fellow 0x00001000u => true, // Vassals 0x00002000u => true, // Patron 0x00004000u => true, // Monarch 0x01000000u => true, // CoVassals _ => false, }; } } /// /// TurbineChat room. is the runtime channel id /// the server hands out via SetTurbineChatChannels (0x0295). /// classifies the room semantically (General, /// Trade, etc.); chooses the wire dispatch /// (SendToRoomById for outbound, SendToRoomByName for inbound events). /// public sealed record Turbine( uint RoomId, uint ChatType, uint DispatchType, string DisplayName) : ChatChannelInfo(DisplayName, ChatChannelSource.Turbine) { public override bool IsSelfEchoChannel() { // Turbine rooms do NOT echo the sender's own messages back. // The client must emit its own optimistic local echo to give // the player feedback that the message was sent. return false; } } /// /// True iff the server echoes our own outgoing messages on this /// channel — caller should suppress optimistic local echo to avoid /// double-printing. /// public abstract bool IsSelfEchoChannel(); }