using System; using System.Buffers.Binary; namespace AcDream.Core.Net.Messages; /// /// SetTurbineChatChannels (0x0295) — GameEvent (0xF7B0 sub-opcode) /// the server fires once at login (and after a chat-server reconnect) /// listing the runtime room ids assigned to the global community /// channels (General, Trade, LFG, Roleplay, Society + sub-societies, /// Olthoi, plus the optional Allegiance Turbine room). /// /// /// Wire layout (10 sequential u32s, payload only — the 0xF7B0 envelope /// is parsed by ; this parser consumes /// the payload slice): /// /// u32 allegianceRoom // 0 = None (server-side flag) /// u32 generalRoom /// u32 tradeRoom /// u32 lfgRoom /// u32 roleplayRoom /// u32 olthoiRoom /// u32 societyRoom // 0 = None (player not in a society) /// u32 societyCelestialHandRoom /// u32 societyEldrytchWebRoom /// u32 societyRadiantBloodRoom /// /// /// /// /// Source: holtburger /// references/holtburger/crates/holtburger-protocol/src/messages/chat/turbine.rs /// lines 132-209 (struct + ProtocolUnpack/ProtocolPack). /// /// public static class SetTurbineChatChannels { /// GameEvent sub-opcode (NOT a top-level GameMessage opcode). public const uint EventType = 0x0295u; /// Payload size in bytes (10 u32 fields). public const int PayloadSize = 40; /// /// Parsed channel ids. Optional fields (, /// ) carry 0u when the server signals /// "not applicable" — callers should treat 0 as None. /// public readonly record struct Parsed( uint AllegianceRoom, uint GeneralRoom, uint TradeRoom, uint LfgRoom, uint RoleplayRoom, uint OlthoiRoom, uint SocietyRoom, uint SocietyCelestialHandRoom, uint SocietyEldrytchWebRoom, uint SocietyRadiantBloodRoom); /// /// Parse the payload of a 0xF7B0 envelope whose event type is /// . The slice must contain exactly the 10 /// channel u32s (40 bytes); shorter buffers return null. /// public static Parsed? TryParse(ReadOnlySpan payload) { if (payload.Length < PayloadSize) return null; uint allegiance = BinaryPrimitives.ReadUInt32LittleEndian(payload[..4]); uint general = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(4, 4)); uint trade = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(8, 4)); uint lfg = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(12, 4)); uint roleplay = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(16, 4)); uint olthoi = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(20, 4)); uint society = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(24, 4)); uint societyCelHan = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(28, 4)); uint societyEldWeb = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(32, 4)); uint societyRadBlo = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(36, 4)); return new Parsed( AllegianceRoom: allegiance, GeneralRoom: general, TradeRoom: trade, LfgRoom: lfg, RoleplayRoom: roleplay, OlthoiRoom: olthoi, SocietyRoom: society, SocietyCelestialHandRoom: societyCelHan, SocietyEldrytchWebRoom: societyEldWeb, SocietyRadiantBloodRoom: societyRadBlo); } /// /// Serialize into a 40-byte payload buffer /// (the 0xF7B0 envelope is the caller's responsibility). Used by /// fixture round-trip tests. /// public static byte[] Serialize(Parsed parsed) { var buf = new byte[PayloadSize]; var span = buf.AsSpan(); BinaryPrimitives.WriteUInt32LittleEndian(span, parsed.AllegianceRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(4, 4), parsed.GeneralRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(8, 4), parsed.TradeRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(12, 4), parsed.LfgRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(16, 4), parsed.RoleplayRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(20, 4), parsed.OlthoiRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(24, 4), parsed.SocietyRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(28, 4), parsed.SocietyCelestialHandRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(32, 4), parsed.SocietyEldrytchWebRoom); BinaryPrimitives.WriteUInt32LittleEndian(span.Slice(36, 4), parsed.SocietyRadiantBloodRoom); return buf; } }