#pragma once #include "network/packet.hpp" #include "game/opcodes.hpp" #include "game/entity.hpp" #include #include #include #include namespace wowee { namespace game { /** * SMSG_AUTH_CHALLENGE data (from server) * * Sent by world server immediately after TCP connect * Contains server seed/salt for authentication hash */ struct AuthChallengeData { uint32_t unknown1; // Always seems to be 0x00000001 uint32_t serverSeed; // Random seed from server // Note: 3.3.5a has additional data after this bool isValid() const { return unknown1 != 0; } }; /** * CMSG_AUTH_SESSION packet builder * * Client authentication to world server using session key from auth server */ class AuthSessionPacket { public: /** * Build CMSG_AUTH_SESSION packet * * @param build Client build number (12340 for 3.3.5a) * @param accountName Account name (uppercase) * @param clientSeed Random 4-byte seed generated by client * @param sessionKey 40-byte session key from auth server * @param serverSeed 4-byte seed from SMSG_AUTH_CHALLENGE * @return Packet ready to send */ static network::Packet build(uint32_t build, const std::string& accountName, uint32_t clientSeed, const std::vector& sessionKey, uint32_t serverSeed); private: /** * Compute authentication hash * * SHA1(account + [0,0,0,0] + clientSeed + serverSeed + sessionKey) * * @param accountName Account name * @param clientSeed Client seed * @param serverSeed Server seed * @param sessionKey 40-byte session key * @return 20-byte SHA1 hash */ static std::vector computeAuthHash( const std::string& accountName, uint32_t clientSeed, uint32_t serverSeed, const std::vector& sessionKey); }; /** * SMSG_AUTH_CHALLENGE response parser */ class AuthChallengeParser { public: static bool parse(network::Packet& packet, AuthChallengeData& data); }; /** * SMSG_AUTH_RESPONSE result codes */ enum class AuthResult : uint8_t { OK = 0x00, // Success, proceed to character screen FAILED = 0x01, // Generic failure REJECT = 0x02, // Reject BAD_SERVER_PROOF = 0x03, // Bad server proof UNAVAILABLE = 0x04, // Unavailable SYSTEM_ERROR = 0x05, // System error BILLING_ERROR = 0x06, // Billing error BILLING_EXPIRED = 0x07, // Billing expired VERSION_MISMATCH = 0x08, // Version mismatch UNKNOWN_ACCOUNT = 0x09, // Unknown account INCORRECT_PASSWORD = 0x0A, // Incorrect password SESSION_EXPIRED = 0x0B, // Session expired SERVER_SHUTTING_DOWN = 0x0C, // Server shutting down ALREADY_LOGGING_IN = 0x0D, // Already logging in LOGIN_SERVER_NOT_FOUND = 0x0E, // Login server not found WAIT_QUEUE = 0x0F, // Wait queue BANNED = 0x10, // Banned ALREADY_ONLINE = 0x11, // Already online NO_TIME = 0x12, // No game time DB_BUSY = 0x13, // DB busy SUSPENDED = 0x14, // Suspended PARENTAL_CONTROL = 0x15, // Parental control LOCKED_ENFORCED = 0x16 // Account locked }; /** * SMSG_AUTH_RESPONSE data (from server) */ struct AuthResponseData { AuthResult result; bool isSuccess() const { return result == AuthResult::OK; } }; /** * SMSG_AUTH_RESPONSE parser */ class AuthResponseParser { public: static bool parse(network::Packet& packet, AuthResponseData& data); }; /** * Get human-readable string for auth result */ const char* getAuthResultString(AuthResult result); // Forward declare Character struct Character; /** * CMSG_CHAR_ENUM packet builder * * Request list of characters on account */ class CharEnumPacket { public: /** * Build CMSG_CHAR_ENUM packet * * This packet has no body - just the opcode */ static network::Packet build(); }; /** * SMSG_CHAR_ENUM response data (from server) * * Contains list of all characters on the account */ struct CharEnumResponse { std::vector characters; bool isEmpty() const { return characters.empty(); } size_t count() const { return characters.size(); } }; /** * SMSG_CHAR_ENUM response parser */ class CharEnumParser { public: static bool parse(network::Packet& packet, CharEnumResponse& response); }; /** * CMSG_PLAYER_LOGIN packet builder * * Select character and enter world */ class PlayerLoginPacket { public: /** * Build CMSG_PLAYER_LOGIN packet * * @param characterGuid GUID of character to log in with */ static network::Packet build(uint64_t characterGuid); }; /** * SMSG_LOGIN_VERIFY_WORLD data (from server) * * Confirms successful world entry with initial position and map info */ struct LoginVerifyWorldData { uint32_t mapId; // Map ID where character spawned float x, y, z; // Initial position coordinates float orientation; // Initial orientation (facing direction) bool isValid() const { return mapId != 0xFFFFFFFF; } }; /** * SMSG_LOGIN_VERIFY_WORLD parser */ class LoginVerifyWorldParser { public: static bool parse(network::Packet& packet, LoginVerifyWorldData& data); }; /** * SMSG_ACCOUNT_DATA_TIMES data (from server) * * Contains timestamps for account data (macros, keybindings, etc.) */ struct AccountDataTimesData { uint32_t serverTime; // Current server time (Unix timestamp) uint8_t unknown; // Unknown (always 1?) uint32_t accountDataTimes[8]; // Timestamps for 8 account data slots bool isValid() const { return true; } }; /** * SMSG_ACCOUNT_DATA_TIMES parser */ class AccountDataTimesParser { public: static bool parse(network::Packet& packet, AccountDataTimesData& data); }; /** * SMSG_MOTD data (from server) * * Message of the Day from server */ struct MotdData { std::vector lines; // MOTD text lines bool isEmpty() const { return lines.empty(); } size_t lineCount() const { return lines.size(); } }; /** * SMSG_MOTD parser */ class MotdParser { public: static bool parse(network::Packet& packet, MotdData& data); }; /** * CMSG_PING packet builder * * Heartbeat packet sent periodically to keep connection alive */ class PingPacket { public: /** * Build CMSG_PING packet * * @param sequence Sequence number (increments with each ping) * @param latency Client-side latency estimate in milliseconds * @return Packet ready to send */ static network::Packet build(uint32_t sequence, uint32_t latency); }; /** * SMSG_PONG data (from server) * * Response to CMSG_PING, echoes back the sequence number */ struct PongData { uint32_t sequence; // Sequence number from CMSG_PING bool isValid() const { return true; } }; /** * SMSG_PONG parser */ class PongParser { public: static bool parse(network::Packet& packet, PongData& data); }; /** * Movement flags for player movement */ enum class MovementFlags : uint32_t { NONE = 0x00000000, FORWARD = 0x00000001, BACKWARD = 0x00000002, STRAFE_LEFT = 0x00000004, STRAFE_RIGHT = 0x00000008, TURN_LEFT = 0x00000010, TURN_RIGHT = 0x00000020, PITCH_UP = 0x00000040, PITCH_DOWN = 0x00000080, WALKING = 0x00000100, ONTRANSPORT = 0x00000200, LEVITATING = 0x00000400, ROOT = 0x00000800, FALLING = 0x00001000, FALLINGFAR = 0x00002000, SWIMMING = 0x00200000, ASCENDING = 0x00400000, CAN_FLY = 0x00800000, FLYING = 0x01000000, }; /** * Movement info structure * * Contains all movement-related data sent in movement packets */ struct MovementInfo { uint32_t flags = 0; // Movement flags uint16_t flags2 = 0; // Extra movement flags uint32_t time = 0; // Movement timestamp (milliseconds) float x = 0.0f; // Position X float y = 0.0f; // Position Y float z = 0.0f; // Position Z float orientation = 0.0f; // Facing direction (radians) // Optional fields (based on flags) float pitch = 0.0f; // Pitch angle (swimming/flying) uint32_t fallTime = 0; // Time falling (milliseconds) float jumpVelocity = 0.0f; // Jump vertical velocity float jumpSinAngle = 0.0f; // Jump horizontal sin float jumpCosAngle = 0.0f; // Jump horizontal cos float jumpXYSpeed = 0.0f; // Jump horizontal speed bool hasFlag(MovementFlags flag) const { return (flags & static_cast(flag)) != 0; } }; /** * Movement packet builder * * Builds CMSG_MOVE_* packets with movement info */ class MovementPacket { public: /** * Build a movement packet * * @param opcode Movement opcode (CMSG_MOVE_START_FORWARD, etc.) * @param info Movement info * @return Packet ready to send */ static network::Packet build(Opcode opcode, const MovementInfo& info); }; // Forward declare Entity types class Entity; class EntityManager; enum class ObjectType : uint8_t; enum class UpdateType : uint8_t; /** * Update block for a single object in SMSG_UPDATE_OBJECT */ struct UpdateBlock { UpdateType updateType; uint64_t guid = 0; ObjectType objectType; // Movement data (for MOVEMENT updates) bool hasMovement = false; float x = 0.0f, y = 0.0f, z = 0.0f, orientation = 0.0f; // Field data (for VALUES and CREATE updates) std::map fields; }; /** * SMSG_UPDATE_OBJECT data * * Contains all update blocks in the packet */ struct UpdateObjectData { uint32_t blockCount = 0; std::vector blocks; // Out-of-range GUIDs (for OUT_OF_RANGE_OBJECTS) std::vector outOfRangeGuids; }; /** * SMSG_UPDATE_OBJECT parser * * Parses object updates from server */ class UpdateObjectParser { public: /** * Parse SMSG_UPDATE_OBJECT packet * * @param packet Packet to parse * @param data Output data * @return true if successful */ static bool parse(network::Packet& packet, UpdateObjectData& data); private: /** * Parse a single update block * * @param packet Packet to read from * @param block Output block * @return true if successful */ static bool parseUpdateBlock(network::Packet& packet, UpdateBlock& block); /** * Parse movement block * * @param packet Packet to read from * @param block Output block * @return true if successful */ static bool parseMovementBlock(network::Packet& packet, UpdateBlock& block); /** * Parse update fields (mask + values) * * @param packet Packet to read from * @param block Output block * @return true if successful */ static bool parseUpdateFields(network::Packet& packet, UpdateBlock& block); /** * Read packed GUID from packet * * @param packet Packet to read from * @return GUID value */ static uint64_t readPackedGuid(network::Packet& packet); }; /** * SMSG_DESTROY_OBJECT data */ struct DestroyObjectData { uint64_t guid = 0; bool isDeath = false; // true if unit died, false if despawned }; /** * SMSG_DESTROY_OBJECT parser */ class DestroyObjectParser { public: static bool parse(network::Packet& packet, DestroyObjectData& data); }; /** * Chat message types */ enum class ChatType : uint8_t { SAY = 0, PARTY = 1, RAID = 2, GUILD = 3, OFFICER = 4, YELL = 5, WHISPER = 6, WHISPER_INFORM = 7, EMOTE = 8, TEXT_EMOTE = 9, SYSTEM = 10, MONSTER_SAY = 11, MONSTER_YELL = 12, MONSTER_EMOTE = 13, CHANNEL = 14, CHANNEL_JOIN = 15, CHANNEL_LEAVE = 16, CHANNEL_LIST = 17, CHANNEL_NOTICE = 18, CHANNEL_NOTICE_USER = 19, AFK = 20, DND = 21, IGNORED = 22, SKILL = 23, LOOT = 24, BATTLEGROUND = 25, BATTLEGROUND_LEADER = 26, RAID_LEADER = 27, RAID_WARNING = 28, ACHIEVEMENT = 29, GUILD_ACHIEVEMENT = 30 }; /** * Chat language IDs */ enum class ChatLanguage : uint32_t { UNIVERSAL = 0, ORCISH = 1, DARNASSIAN = 2, TAURAHE = 3, DWARVISH = 6, COMMON = 7, DEMONIC = 8, TITAN = 9, THALASSIAN = 10, DRACONIC = 11, KALIMAG = 12, GNOMISH = 13, TROLL = 14, GUTTERSPEAK = 33, DRAENEI = 35, ZOMBIE = 36, GNOMISH_BINARY = 37, GOBLIN_BINARY = 38, ADDON = 0xFFFFFFFF // Used for addon communication }; /** * CMSG_MESSAGECHAT packet builder */ class MessageChatPacket { public: /** * Build CMSG_MESSAGECHAT packet * * @param type Chat type (SAY, YELL, etc.) * @param language Language ID * @param message Message text * @param target Target name (for whispers, empty otherwise) * @return Packet ready to send */ static network::Packet build(ChatType type, ChatLanguage language, const std::string& message, const std::string& target = ""); }; /** * SMSG_MESSAGECHAT data */ struct MessageChatData { ChatType type; ChatLanguage language; uint64_t senderGuid = 0; std::string senderName; uint64_t receiverGuid = 0; std::string receiverName; std::string message; std::string channelName; // For channel messages uint8_t chatTag = 0; // Player flags (AFK, DND, GM, etc.) bool isValid() const { return !message.empty(); } }; /** * SMSG_MESSAGECHAT parser */ class MessageChatParser { public: static bool parse(network::Packet& packet, MessageChatData& data); }; /** * Get human-readable string for chat type */ const char* getChatTypeString(ChatType type); } // namespace game } // namespace wowee