#pragma once #include "network/packet.hpp" #include "game/opcodes.hpp" #include "game/character.hpp" #include "game/entity.hpp" #include "game/spell_defines.hpp" #include "game/group_defines.hpp" #include #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, uint32_t realmId = 1); 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 { // TrinityCore/AzerothCore auth response codes (3.3.5a) OK = 0x0C, // Success, proceed to character screen FAILED = 0x0D, // Generic failure REJECT = 0x0E, // Reject BAD_SERVER_PROOF = 0x0F, // Bad server proof UNAVAILABLE = 0x10, // Unavailable SYSTEM_ERROR = 0x11, // System error BILLING_ERROR = 0x12, // Billing error BILLING_EXPIRED = 0x13, // Billing expired VERSION_MISMATCH = 0x14, // Version mismatch UNKNOWN_ACCOUNT = 0x15, // Unknown account INCORRECT_PASSWORD = 0x16, // Incorrect password SESSION_EXPIRED = 0x17, // Session expired SERVER_SHUTTING_DOWN = 0x18, // Server shutting down ALREADY_LOGGING_IN = 0x19, // Already logging in LOGIN_SERVER_NOT_FOUND = 0x1A, // Login server not found WAIT_QUEUE = 0x1B, // Wait queue BANNED = 0x1C, // Banned ALREADY_ONLINE = 0x1D, // Already online NO_TIME = 0x1E, // No game time DB_BUSY = 0x1F, // DB busy SUSPENDED = 0x20, // Suspended PARENTAL_CONTROL = 0x21, // Parental control LOCKED_ENFORCED = 0x22 // 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); }; // ============================================================ // Character Creation // ============================================================ // WoW 3.3.5a ResponseCodes for character creation (from ResponseCodes enum) enum class CharCreateResult : uint8_t { // Success codes SUCCESS = 0x2F, // CHAR_CREATE_SUCCESS // CHAR_CREATE error codes IN_PROGRESS = 0x2E, // CHAR_CREATE_IN_PROGRESS ERROR = 0x30, // CHAR_CREATE_ERROR FAILED = 0x31, // CHAR_CREATE_FAILED NAME_IN_USE = 0x32, // CHAR_CREATE_NAME_IN_USE DISABLED = 0x33, // CHAR_CREATE_DISABLED PVP_TEAMS_VIOLATION = 0x34, // CHAR_CREATE_PVP_TEAMS_VIOLATION SERVER_LIMIT = 0x35, // CHAR_CREATE_SERVER_LIMIT ACCOUNT_LIMIT = 0x36, // CHAR_CREATE_ACCOUNT_LIMIT SERVER_QUEUE = 0x37, // CHAR_CREATE_SERVER_QUEUE ONLY_EXISTING = 0x38, // CHAR_CREATE_ONLY_EXISTING EXPANSION = 0x39, // CHAR_CREATE_EXPANSION EXPANSION_CLASS = 0x3A, // CHAR_CREATE_EXPANSION_CLASS LEVEL_REQUIREMENT = 0x3B, // CHAR_CREATE_LEVEL_REQUIREMENT UNIQUE_CLASS_LIMIT = 0x3C, // CHAR_CREATE_UNIQUE_CLASS_LIMIT CHARACTER_IN_GUILD = 0x3D, // CHAR_CREATE_CHARACTER_IN_GUILD RESTRICTED_RACECLASS = 0x3E, // CHAR_CREATE_RESTRICTED_RACECLASS CHARACTER_CHOOSE_RACE= 0x3F, // CHAR_CREATE_CHARACTER_CHOOSE_RACE CHARACTER_ARENA_LEADER=0x40, // CHAR_CREATE_CHARACTER_ARENA_LEADER CHARACTER_DELETE_MAIL= 0x41, // CHAR_CREATE_CHARACTER_DELETE_MAIL CHARACTER_SWAP_FACTION=0x42, // CHAR_CREATE_CHARACTER_SWAP_FACTION CHARACTER_RACE_ONLY = 0x43, // CHAR_CREATE_CHARACTER_RACE_ONLY CHARACTER_GOLD_LIMIT = 0x44, // CHAR_CREATE_CHARACTER_GOLD_LIMIT FORCE_LOGIN = 0x45, // CHAR_CREATE_FORCE_LOGIN // CHAR_NAME error codes (name validation failures) NAME_SUCCESS = 0x57, // CHAR_NAME_SUCCESS NAME_FAILURE = 0x58, // CHAR_NAME_FAILURE NAME_NO_NAME = 0x59, // CHAR_NAME_NO_NAME NAME_TOO_SHORT = 0x5A, // CHAR_NAME_TOO_SHORT NAME_TOO_LONG = 0x5B, // CHAR_NAME_TOO_LONG NAME_INVALID_CHARACTER = 0x5C, // CHAR_NAME_INVALID_CHARACTER NAME_MIXED_LANGUAGES = 0x5D, // CHAR_NAME_MIXED_LANGUAGES NAME_PROFANE = 0x5E, // CHAR_NAME_PROFANE NAME_RESERVED = 0x5F, // CHAR_NAME_RESERVED NAME_INVALID_APOSTROPHE = 0x60, // CHAR_NAME_INVALID_APOSTROPHE NAME_MULTIPLE_APOSTROPHES = 0x61, // CHAR_NAME_MULTIPLE_APOSTROPHES NAME_THREE_CONSECUTIVE = 0x62, // CHAR_NAME_THREE_CONSECUTIVE (98 decimal) NAME_INVALID_SPACE = 0x63, // CHAR_NAME_INVALID_SPACE NAME_CONSECUTIVE_SPACES = 0x64, // CHAR_NAME_CONSECUTIVE_SPACES NAME_RUSSIAN_CONSECUTIVE_SILENT = 0x65, // CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS NAME_RUSSIAN_SILENT_AT_BEGIN_OR_END = 0x66, // CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END NAME_DECLENSION_DOESNT_MATCH = 0x67, // CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME }; struct CharCreateData { std::string name; Race race; Class characterClass; Gender gender; uint8_t skin = 0; uint8_t face = 0; uint8_t hairStyle = 0; uint8_t hairColor = 0; uint8_t facialHair = 0; }; class CharCreatePacket { public: static network::Packet build(const CharCreateData& data); }; struct CharCreateResponseData { CharCreateResult result; }; class CharCreateResponseParser { public: static bool parse(network::Packet& packet, CharCreateResponseData& data); }; /** * 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, uint64_t playerGuid = 0); }; // 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); /** * Read packed GUID from packet * * @param packet Packet to read from * @return GUID value */ static uint64_t readPackedGuid(network::Packet& packet); 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); }; /** * 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); // ============================================================ // Server Info Commands // ============================================================ /** CMSG_QUERY_TIME packet builder */ class QueryTimePacket { public: static network::Packet build(); }; /** SMSG_QUERY_TIME_RESPONSE data */ struct QueryTimeResponseData { uint32_t serverTime = 0; // Unix timestamp uint32_t timeOffset = 0; // Time until next daily reset }; /** SMSG_QUERY_TIME_RESPONSE parser */ class QueryTimeResponseParser { public: static bool parse(network::Packet& packet, QueryTimeResponseData& data); }; /** CMSG_REQUEST_PLAYED_TIME packet builder */ class RequestPlayedTimePacket { public: static network::Packet build(bool sendToChat = true); }; /** SMSG_PLAYED_TIME data */ struct PlayedTimeData { uint32_t totalTimePlayed = 0; // Total seconds played uint32_t levelTimePlayed = 0; // Seconds played at current level bool triggerMessage = false; // Whether to show in chat }; /** SMSG_PLAYED_TIME parser */ class PlayedTimeParser { public: static bool parse(network::Packet& packet, PlayedTimeData& data); }; /** CMSG_WHO packet builder */ class WhoPacket { public: static network::Packet build(uint32_t minLevel = 0, uint32_t maxLevel = 0, const std::string& playerName = "", const std::string& guildName = "", uint32_t raceMask = 0xFFFFFFFF, uint32_t classMask = 0xFFFFFFFF, uint32_t zones = 0); }; // ============================================================ // Social Commands // ============================================================ /** CMSG_ADD_FRIEND packet builder */ class AddFriendPacket { public: static network::Packet build(const std::string& playerName, const std::string& note = ""); }; /** CMSG_DEL_FRIEND packet builder */ class DelFriendPacket { public: static network::Packet build(uint64_t friendGuid); }; /** CMSG_SET_CONTACT_NOTES packet builder */ class SetContactNotesPacket { public: static network::Packet build(uint64_t friendGuid, const std::string& note); }; /** SMSG_FRIEND_STATUS data */ struct FriendStatusData { uint8_t status = 0; // 0 = offline, 1 = online, etc. uint64_t guid = 0; std::string note; uint8_t chatFlag = 0; }; /** SMSG_FRIEND_STATUS parser */ class FriendStatusParser { public: static bool parse(network::Packet& packet, FriendStatusData& data); }; /** CMSG_ADD_IGNORE packet builder */ class AddIgnorePacket { public: static network::Packet build(const std::string& playerName); }; /** CMSG_DEL_IGNORE packet builder */ class DelIgnorePacket { public: static network::Packet build(uint64_t ignoreGuid); }; // ============================================================ // Logout Commands // ============================================================ /** CMSG_LOGOUT_REQUEST packet builder */ class LogoutRequestPacket { public: static network::Packet build(); }; /** CMSG_LOGOUT_CANCEL packet builder */ class LogoutCancelPacket { public: static network::Packet build(); }; /** SMSG_LOGOUT_RESPONSE data */ struct LogoutResponseData { uint32_t result = 0; // 0 = success, 1 = failure uint8_t instant = 0; // 1 = instant logout }; /** SMSG_LOGOUT_RESPONSE parser */ class LogoutResponseParser { public: static bool parse(network::Packet& packet, LogoutResponseData& data); }; // ============================================================ // Stand State // ============================================================ /** CMSG_STAND_STATE_CHANGE packet builder */ class StandStateChangePacket { public: static network::Packet build(uint8_t state); }; // ============================================================ // Display Toggles // ============================================================ /** CMSG_SHOWING_HELM packet builder */ class ShowingHelmPacket { public: static network::Packet build(bool show); }; /** CMSG_SHOWING_CLOAK packet builder */ class ShowingCloakPacket { public: static network::Packet build(bool show); }; // ============================================================ // PvP // ============================================================ /** CMSG_TOGGLE_PVP packet builder */ class TogglePvpPacket { public: static network::Packet build(); }; // ============================================================ // Guild Commands // ============================================================ /** CMSG_GUILD_INFO packet builder */ class GuildInfoPacket { public: static network::Packet build(); }; /** CMSG_GUILD_GET_ROSTER packet builder */ class GuildRosterPacket { public: static network::Packet build(); }; /** CMSG_GUILD_MOTD packet builder */ class GuildMotdPacket { public: static network::Packet build(const std::string& motd); }; /** CMSG_GUILD_PROMOTE_MEMBER packet builder */ class GuildPromotePacket { public: static network::Packet build(const std::string& playerName); }; /** CMSG_GUILD_DEMOTE_MEMBER packet builder */ class GuildDemotePacket { public: static network::Packet build(const std::string& playerName); }; /** CMSG_GUILD_LEAVE packet builder */ class GuildLeavePacket { public: static network::Packet build(); }; /** CMSG_GUILD_INVITE packet builder */ class GuildInvitePacket { public: static network::Packet build(const std::string& playerName); }; // ============================================================ // Ready Check // ============================================================ /** MSG_RAID_READY_CHECK packet builder */ class ReadyCheckPacket { public: static network::Packet build(); }; /** MSG_RAID_READY_CHECK_CONFIRM packet builder */ class ReadyCheckConfirmPacket { public: static network::Packet build(bool ready); }; // ============================================================ // Duel // ============================================================ /** CMSG_DUEL_CANCELLED packet builder */ class DuelCancelPacket { public: static network::Packet build(); }; // ============================================================ // Random Roll // ============================================================ /** CMSG_RANDOM_ROLL packet builder */ class RandomRollPacket { public: static network::Packet build(uint32_t minRoll, uint32_t maxRoll); }; /** SMSG_RANDOM_ROLL data */ struct RandomRollData { uint64_t rollerGuid = 0; uint64_t targetGuid = 0; // 0 for party roll uint32_t minRoll = 0; uint32_t maxRoll = 0; uint32_t result = 0; }; /** SMSG_RANDOM_ROLL parser */ class RandomRollParser { public: static bool parse(network::Packet& packet, RandomRollData& data); }; // ============================================================ // Phase 1: Foundation — Targeting, Name Queries // ============================================================ /** CMSG_SET_SELECTION packet builder */ class SetSelectionPacket { public: static network::Packet build(uint64_t targetGuid); }; /** CMSG_SET_ACTIVE_MOVER packet builder */ class SetActiveMoverPacket { public: static network::Packet build(uint64_t guid); }; /** CMSG_INSPECT packet builder */ class InspectPacket { public: static network::Packet build(uint64_t targetGuid); }; /** CMSG_NAME_QUERY packet builder */ class NameQueryPacket { public: static network::Packet build(uint64_t playerGuid); }; /** SMSG_NAME_QUERY_RESPONSE data */ struct NameQueryResponseData { uint64_t guid = 0; uint8_t found = 1; // 0 = found, 1 = not found std::string name; std::string realmName; uint8_t race = 0; uint8_t gender = 0; uint8_t classId = 0; bool isValid() const { return found == 0 && !name.empty(); } }; /** SMSG_NAME_QUERY_RESPONSE parser */ class NameQueryResponseParser { public: static bool parse(network::Packet& packet, NameQueryResponseData& data); }; /** CMSG_CREATURE_QUERY packet builder */ class CreatureQueryPacket { public: static network::Packet build(uint32_t entry, uint64_t guid); }; /** SMSG_CREATURE_QUERY_RESPONSE data */ struct CreatureQueryResponseData { uint32_t entry = 0; std::string name; std::string subName; std::string iconName; uint32_t typeFlags = 0; uint32_t creatureType = 0; uint32_t family = 0; uint32_t rank = 0; // 0=Normal, 1=Elite, 2=Rare Elite, 3=Boss, 4=Rare bool isValid() const { return entry != 0 && !name.empty(); } }; /** SMSG_CREATURE_QUERY_RESPONSE parser */ class CreatureQueryResponseParser { public: static bool parse(network::Packet& packet, CreatureQueryResponseData& data); }; // ============================================================ // Item Query // ============================================================ /** CMSG_ITEM_QUERY_SINGLE packet builder */ class ItemQueryPacket { public: static network::Packet build(uint32_t entry, uint64_t guid); }; /** SMSG_ITEM_QUERY_SINGLE_RESPONSE data */ struct ItemQueryResponseData { uint32_t entry = 0; std::string name; uint32_t displayInfoId = 0; uint32_t quality = 0; uint32_t inventoryType = 0; int32_t maxStack = 1; uint32_t containerSlots = 0; int32_t armor = 0; int32_t stamina = 0; int32_t strength = 0; int32_t agility = 0; int32_t intellect = 0; int32_t spirit = 0; uint32_t sellPrice = 0; std::string subclassName; bool valid = false; }; /** SMSG_ITEM_QUERY_SINGLE_RESPONSE parser */ class ItemQueryResponseParser { public: static bool parse(network::Packet& packet, ItemQueryResponseData& data); }; // ============================================================ // Phase 2: Combat Core // ============================================================ /** SMSG_MONSTER_MOVE data */ struct MonsterMoveData { uint64_t guid = 0; float x = 0, y = 0, z = 0; // Current position (server coords) uint8_t moveType = 0; // 0=Normal, 1=Stop, 2=FacingSpot, 3=FacingTarget, 4=FacingAngle float facingAngle = 0; uint64_t facingTarget = 0; uint32_t splineFlags = 0; uint32_t duration = 0; // Destination (final point of the spline, server coords) float destX = 0, destY = 0, destZ = 0; bool hasDest = false; }; class MonsterMoveParser { public: static bool parse(network::Packet& packet, MonsterMoveData& data); }; /** CMSG_ATTACKSWING packet builder */ class AttackSwingPacket { public: static network::Packet build(uint64_t targetGuid); }; /** CMSG_ATTACKSTOP packet builder */ class AttackStopPacket { public: static network::Packet build(); }; /** SMSG_ATTACKSTART data */ struct AttackStartData { uint64_t attackerGuid = 0; uint64_t victimGuid = 0; bool isValid() const { return attackerGuid != 0 && victimGuid != 0; } }; class AttackStartParser { public: static bool parse(network::Packet& packet, AttackStartData& data); }; /** SMSG_ATTACKSTOP data */ struct AttackStopData { uint64_t attackerGuid = 0; uint64_t victimGuid = 0; uint32_t unknown = 0; bool isValid() const { return true; } }; class AttackStopParser { public: static bool parse(network::Packet& packet, AttackStopData& data); }; /** Sub-damage entry for melee hits */ struct SubDamage { uint32_t schoolMask = 0; float damage = 0.0f; uint32_t intDamage = 0; uint32_t absorbed = 0; uint32_t resisted = 0; }; /** SMSG_ATTACKERSTATEUPDATE data */ struct AttackerStateUpdateData { uint32_t hitInfo = 0; uint64_t attackerGuid = 0; uint64_t targetGuid = 0; int32_t totalDamage = 0; uint8_t subDamageCount = 0; std::vector subDamages; uint32_t victimState = 0; // 0=hit, 1=dodge, 2=parry, 3=interrupt, 4=block, etc. int32_t overkill = -1; uint32_t blocked = 0; bool isValid() const { return attackerGuid != 0; } bool isCrit() const { return (hitInfo & 0x200) != 0; } bool isMiss() const { return (hitInfo & 0x10) != 0; } }; class AttackerStateUpdateParser { public: static bool parse(network::Packet& packet, AttackerStateUpdateData& data); }; /** SMSG_SPELLNONMELEEDAMAGELOG data (simplified) */ struct SpellDamageLogData { uint64_t targetGuid = 0; uint64_t attackerGuid = 0; uint32_t spellId = 0; uint32_t damage = 0; uint32_t overkill = 0; uint8_t schoolMask = 0; uint32_t absorbed = 0; uint32_t resisted = 0; bool isCrit = false; bool isValid() const { return spellId != 0; } }; class SpellDamageLogParser { public: static bool parse(network::Packet& packet, SpellDamageLogData& data); }; /** SMSG_SPELLHEALLOG data (simplified) */ struct SpellHealLogData { uint64_t targetGuid = 0; uint64_t casterGuid = 0; uint32_t spellId = 0; uint32_t heal = 0; uint32_t overheal = 0; uint32_t absorbed = 0; bool isCrit = false; bool isValid() const { return spellId != 0; } }; class SpellHealLogParser { public: static bool parse(network::Packet& packet, SpellHealLogData& data); }; // ============================================================ // XP Gain // ============================================================ /** SMSG_LOG_XPGAIN data */ struct XpGainData { uint64_t victimGuid = 0; // 0 for non-kill XP (quest, exploration) uint32_t totalXp = 0; uint8_t type = 0; // 0 = kill, 1 = non-kill uint32_t groupBonus = 0; bool isValid() const { return totalXp > 0; } }; class XpGainParser { public: static bool parse(network::Packet& packet, XpGainData& data); }; // ============================================================ // Phase 3: Spells, Action Bar, Auras // ============================================================ /** SMSG_INITIAL_SPELLS data */ struct InitialSpellsData { uint8_t talentSpec = 0; std::vector spellIds; std::vector cooldowns; bool isValid() const { return true; } }; class InitialSpellsParser { public: static bool parse(network::Packet& packet, InitialSpellsData& data); }; /** CMSG_CAST_SPELL packet builder */ class CastSpellPacket { public: static network::Packet build(uint32_t spellId, uint64_t targetGuid, uint8_t castCount); }; /** CMSG_CANCEL_CAST packet builder */ class CancelCastPacket { public: static network::Packet build(uint32_t spellId); }; /** CMSG_CANCEL_AURA packet builder */ class CancelAuraPacket { public: static network::Packet build(uint32_t spellId); }; /** SMSG_CAST_FAILED data */ struct CastFailedData { uint8_t castCount = 0; uint32_t spellId = 0; uint8_t result = 0; bool isValid() const { return spellId != 0; } }; class CastFailedParser { public: static bool parse(network::Packet& packet, CastFailedData& data); }; /** SMSG_SPELL_START data (simplified) */ struct SpellStartData { uint64_t casterGuid = 0; uint64_t casterUnit = 0; uint8_t castCount = 0; uint32_t spellId = 0; uint32_t castFlags = 0; uint32_t castTime = 0; uint64_t targetGuid = 0; bool isValid() const { return spellId != 0; } }; class SpellStartParser { public: static bool parse(network::Packet& packet, SpellStartData& data); }; /** SMSG_SPELL_GO data (simplified) */ struct SpellGoData { uint64_t casterGuid = 0; uint64_t casterUnit = 0; uint8_t castCount = 0; uint32_t spellId = 0; uint32_t castFlags = 0; uint8_t hitCount = 0; std::vector hitTargets; uint8_t missCount = 0; bool isValid() const { return spellId != 0; } }; class SpellGoParser { public: static bool parse(network::Packet& packet, SpellGoData& data); }; /** SMSG_AURA_UPDATE / SMSG_AURA_UPDATE_ALL data */ struct AuraUpdateData { uint64_t guid = 0; std::vector> updates; // slot index + aura data bool isValid() const { return true; } }; class AuraUpdateParser { public: static bool parse(network::Packet& packet, AuraUpdateData& data, bool isAll); }; /** SMSG_SPELL_COOLDOWN data */ struct SpellCooldownData { uint64_t guid = 0; uint8_t flags = 0; std::vector> cooldowns; // spellId, cooldownMs bool isValid() const { return true; } }; class SpellCooldownParser { public: static bool parse(network::Packet& packet, SpellCooldownData& data); }; // ============================================================ // Phase 4: Group/Party System // ============================================================ /** CMSG_GROUP_INVITE packet builder */ class GroupInvitePacket { public: static network::Packet build(const std::string& playerName); }; /** SMSG_GROUP_INVITE data */ struct GroupInviteResponseData { uint8_t canAccept = 0; std::string inviterName; bool isValid() const { return !inviterName.empty(); } }; class GroupInviteResponseParser { public: static bool parse(network::Packet& packet, GroupInviteResponseData& data); }; /** CMSG_GROUP_ACCEPT packet builder */ class GroupAcceptPacket { public: static network::Packet build(); }; /** CMSG_GROUP_DECLINE packet builder */ class GroupDeclinePacket { public: static network::Packet build(); }; /** CMSG_GROUP_DISBAND (leave party) packet builder */ class GroupDisbandPacket { public: static network::Packet build(); }; /** SMSG_GROUP_LIST parser */ class GroupListParser { public: static bool parse(network::Packet& packet, GroupListData& data); }; /** SMSG_PARTY_COMMAND_RESULT data */ struct PartyCommandResultData { PartyCommand command; std::string name; PartyResult result; bool isValid() const { return true; } }; class PartyCommandResultParser { public: static bool parse(network::Packet& packet, PartyCommandResultData& data); }; /** SMSG_GROUP_DECLINE data */ struct GroupDeclineData { std::string playerName; bool isValid() const { return !playerName.empty(); } }; class GroupDeclineResponseParser { public: static bool parse(network::Packet& packet, GroupDeclineData& data); }; // ============================================================ // Phase 5: Loot System // ============================================================ /** Loot item entry */ struct LootItem { uint8_t slotIndex = 0; uint32_t itemId = 0; uint32_t count = 0; uint32_t displayInfoId = 0; uint32_t randomSuffix = 0; uint32_t randomPropertyId = 0; uint8_t lootSlotType = 0; }; /** SMSG_LOOT_RESPONSE data */ struct LootResponseData { uint64_t lootGuid = 0; uint8_t lootType = 0; uint32_t gold = 0; // In copper std::vector items; bool isValid() const { return true; } uint32_t getGold() const { return gold / 10000; } uint32_t getSilver() const { return (gold / 100) % 100; } uint32_t getCopper() const { return gold % 100; } }; /** CMSG_LOOT packet builder */ class LootPacket { public: static network::Packet build(uint64_t targetGuid); }; /** CMSG_AUTOSTORE_LOOT_ITEM packet builder */ class AutostoreLootItemPacket { public: static network::Packet build(uint8_t slotIndex); }; /** CMSG_USE_ITEM packet builder */ class UseItemPacket { public: static network::Packet build(uint8_t bagIndex, uint8_t slotIndex, uint64_t itemGuid); }; /** CMSG_AUTOEQUIP_ITEM packet builder */ class AutoEquipItemPacket { public: static network::Packet build(uint8_t srcBag, uint8_t srcSlot); }; /** CMSG_LOOT_MONEY packet builder (empty body) */ class LootMoneyPacket { public: static network::Packet build(); }; /** CMSG_LOOT_RELEASE packet builder */ class LootReleasePacket { public: static network::Packet build(uint64_t lootGuid); }; /** SMSG_LOOT_RESPONSE parser */ class LootResponseParser { public: static bool parse(network::Packet& packet, LootResponseData& data); }; // ============================================================ // Phase 5: NPC Gossip // ============================================================ /** Gossip menu option */ struct GossipOption { uint32_t id = 0; uint8_t icon = 0; // 0=chat, 1=vendor, 2=taxi, 3=trainer, etc. bool isCoded = false; uint32_t boxMoney = 0; std::string text; std::string boxText; }; /** Gossip quest item */ struct GossipQuestItem { uint32_t questId = 0; uint32_t questIcon = 0; int32_t questLevel = 0; uint32_t questFlags = 0; uint8_t isRepeatable = 0; std::string title; }; /** SMSG_GOSSIP_MESSAGE data */ struct GossipMessageData { uint64_t npcGuid = 0; uint32_t menuId = 0; uint32_t titleTextId = 0; std::vector options; std::vector quests; bool isValid() const { return true; } }; /** CMSG_GOSSIP_HELLO packet builder */ class GossipHelloPacket { public: static network::Packet build(uint64_t npcGuid); }; /** CMSG_GOSSIP_SELECT_OPTION packet builder */ class GossipSelectOptionPacket { public: static network::Packet build(uint64_t npcGuid, uint32_t menuId, uint32_t optionId, const std::string& code = ""); }; /** SMSG_GOSSIP_MESSAGE parser */ class GossipMessageParser { public: static bool parse(network::Packet& packet, GossipMessageData& data); }; /** CMSG_QUESTGIVER_QUERY_QUEST packet builder */ class QuestgiverQueryQuestPacket { public: static network::Packet build(uint64_t npcGuid, uint32_t questId); }; /** CMSG_QUESTGIVER_ACCEPT_QUEST packet builder */ class QuestgiverAcceptQuestPacket { public: static network::Packet build(uint64_t npcGuid, uint32_t questId); }; /** SMSG_QUESTGIVER_QUEST_DETAILS data (simplified) */ struct QuestDetailsData { uint64_t npcGuid = 0; uint32_t questId = 0; std::string title; std::string details; // Quest description text std::string objectives; // Objectives text uint32_t suggestedPlayers = 0; uint32_t rewardMoney = 0; uint32_t rewardXp = 0; }; /** SMSG_QUESTGIVER_QUEST_DETAILS parser */ class QuestDetailsParser { public: static bool parse(network::Packet& packet, QuestDetailsData& data); }; /** Reward item entry (shared by quest detail/offer windows) */ struct QuestRewardItem { uint32_t itemId = 0; uint32_t count = 0; uint32_t displayInfoId = 0; }; /** SMSG_QUESTGIVER_REQUEST_ITEMS data (turn-in progress check) */ struct QuestRequestItemsData { uint64_t npcGuid = 0; uint32_t questId = 0; std::string title; std::string completionText; uint32_t requiredMoney = 0; uint32_t completableFlags = 0; // 0x03 = completable std::vector requiredItems; bool isCompletable() const { return (completableFlags & 0x03) != 0; } }; /** SMSG_QUESTGIVER_REQUEST_ITEMS parser */ class QuestRequestItemsParser { public: static bool parse(network::Packet& packet, QuestRequestItemsData& data); }; /** SMSG_QUESTGIVER_OFFER_REWARD data (choose reward) */ struct QuestOfferRewardData { uint64_t npcGuid = 0; uint32_t questId = 0; std::string title; std::string rewardText; uint32_t rewardMoney = 0; uint32_t rewardXp = 0; std::vector choiceRewards; // Pick one std::vector fixedRewards; // Always given }; /** SMSG_QUESTGIVER_OFFER_REWARD parser */ class QuestOfferRewardParser { public: static bool parse(network::Packet& packet, QuestOfferRewardData& data); }; /** CMSG_QUESTGIVER_COMPLETE_QUEST packet builder */ class QuestgiverCompleteQuestPacket { public: static network::Packet build(uint64_t npcGuid, uint32_t questId); }; /** CMSG_QUESTGIVER_CHOOSE_REWARD packet builder */ class QuestgiverChooseRewardPacket { public: static network::Packet build(uint64_t npcGuid, uint32_t questId, uint32_t rewardIndex); }; // ============================================================ // Phase 5: Vendor // ============================================================ /** Vendor item entry */ struct VendorItem { uint32_t slot = 0; uint32_t itemId = 0; uint32_t displayInfoId = 0; int32_t maxCount = -1; // -1 = unlimited uint32_t buyPrice = 0; // In copper uint32_t durability = 0; uint32_t stackCount = 0; uint32_t extendedCost = 0; }; /** SMSG_LIST_INVENTORY data */ struct ListInventoryData { uint64_t vendorGuid = 0; std::vector items; bool isValid() const { return true; } }; /** CMSG_LIST_INVENTORY packet builder */ class ListInventoryPacket { public: static network::Packet build(uint64_t npcGuid); }; /** CMSG_BUY_ITEM packet builder */ class BuyItemPacket { public: static network::Packet build(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint8_t count); }; /** CMSG_SELL_ITEM packet builder */ class SellItemPacket { public: static network::Packet build(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count); }; /** SMSG_LIST_INVENTORY parser */ class ListInventoryParser { public: static bool parse(network::Packet& packet, ListInventoryData& data); }; /** CMSG_REPOP_REQUEST packet builder */ class RepopRequestPacket { public: static network::Packet build(); }; /** CMSG_SPIRIT_HEALER_ACTIVATE packet builder */ class SpiritHealerActivatePacket { public: static network::Packet build(uint64_t npcGuid); }; } // namespace game } // namespace wowee