using AcDream.Core.Net.Packets; namespace AcDream.Core.Net.Messages; /// /// Outbound GameMessages for the character-select → in-world transition. /// The client sends two messages in order after receiving /// : /// /// /// CharacterEnterWorldRequest (opcode 0xF7C8) — /// empty body beyond the 4-byte opcode. "Hi server, I'm about /// to try to enter the world, anything I should know?" /// Server replies with /// CharacterEnterWorldServerReady (0xF7DF). /// CharacterEnterWorld (opcode 0xF657) — u32 GUID /// of the chosen character + String16L account name. Server /// validates ownership and begins spawning the player + world /// entities into our session, which is where the CreateObject /// flood starts. /// /// /// Both messages are tiny enough to fit in one fragment each. They go on /// the queue per ACE's /// CharacterHandler annotations. /// public static class CharacterEnterWorld { public const uint EnterWorldRequestOpcode = 0xF7C8u; public const uint EnterWorldOpcode = 0xF657u; /// /// Build the body bytes for an outbound CharacterEnterWorldRequest. /// Just the 4-byte opcode, nothing else. /// public static byte[] BuildEnterWorldRequestBody() { var w = new PacketWriter(8); w.WriteUInt32(EnterWorldRequestOpcode); return w.ToArray(); } /// /// Build the body bytes for an outbound CharacterEnterWorld. /// Layout: opcode(4) + characterGuid(4) + String16L(accountName). /// public static byte[] BuildEnterWorldBody(uint characterGuid, string accountName) { ArgumentNullException.ThrowIfNull(accountName); var w = new PacketWriter(32); w.WriteUInt32(EnterWorldOpcode); w.WriteUInt32(characterGuid); w.WriteString16L(accountName); return w.ToArray(); } }