Kelsidavis-WoWee/include/game/world_packets.hpp
Kelsi 1603456120 Add body type selection for nonbinary characters and reduce preview rotation sensitivity
Nonbinary characters can now choose between masculine and feminine body types in character creation, with real-time preview updates and full appearance customization. Body type preference is saved to character config and persists across sessions. Also reduces character preview drag-to-rotate sensitivity from 0.5 to 0.2 for better control.
2026-02-09 17:56:04 -08:00

1831 lines
48 KiB
C++

#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 <vector>
#include <cstdint>
#include <string>
#include <map>
#include <unordered_map>
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<uint8_t>& 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<uint8_t> computeAuthHash(
const std::string& accountName,
uint32_t clientSeed,
uint32_t serverSeed,
const std::vector<uint8_t>& 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<Character> 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;
bool useFemaleModel = false; // For nonbinary: choose body type
};
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<std::string> 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<uint32_t>(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;
float runSpeed = 0.0f;
// Update flags from movement block (for detecting transports, etc.)
uint16_t updateFlags = 0;
// Transport data from LIVING movement block (MOVEMENTFLAG_ONTRANSPORT)
bool onTransport = false;
uint64_t transportGuid = 0;
float transportX = 0.0f, transportY = 0.0f, transportZ = 0.0f, transportO = 0.0f;
// Field data (for VALUES and CREATE updates)
std::map<uint16_t, uint32_t> fields;
};
/**
* SMSG_UPDATE_OBJECT data
*
* Contains all update blocks in the packet
*/
struct UpdateObjectData {
uint32_t blockCount = 0;
std::vector<UpdateBlock> blocks;
// Out-of-range GUIDs (for OUT_OF_RANGE_OBJECTS)
std::vector<uint64_t> 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();
};
// ============================================================
// Party/Raid Management
// ============================================================
/** CMSG_GROUP_UNINVITE_GUID packet builder */
class GroupUninvitePacket {
public:
static network::Packet build(const std::string& playerName);
};
/** CMSG_GROUP_DISBAND packet builder */
class GroupDisbandPacket {
public:
static network::Packet build();
};
/** MSG_RAID_TARGET_UPDATE packet builder */
class RaidTargetUpdatePacket {
public:
/**
* Build raid target marker update packet
* @param targetIndex 0-7 for raid icons, 0 = MainTank, 1 = MainAssist
* @param targetGuid GUID to mark, or 0 to clear
*/
static network::Packet build(uint8_t targetIndex, uint64_t targetGuid);
};
/** CMSG_REQUEST_RAID_INFO packet builder */
class RequestRaidInfoPacket {
public:
static network::Packet build();
};
// ============================================================
// Combat and Trade
// ============================================================
/** CMSG_DUEL_PROPOSED packet builder */
class DuelProposedPacket {
public:
static network::Packet build(uint64_t targetGuid);
};
/** CMSG_INITIATE_TRADE packet builder */
class InitiateTradePacket {
public:
static network::Packet build(uint64_t targetGuid);
};
/** 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();
};
/** CMSG_CANCEL_CAST packet builder */
class CancelCastPacket {
public:
static network::Packet build(uint32_t spellId);
};
// ============================================================
// 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);
};
// ============================================================
// GameObject Query
// ============================================================
/** CMSG_GAMEOBJECT_QUERY packet builder */
class GameObjectQueryPacket {
public:
static network::Packet build(uint32_t entry, uint64_t guid);
};
/** SMSG_GAMEOBJECT_QUERY_RESPONSE data */
struct GameObjectQueryResponseData {
uint32_t entry = 0;
std::string name;
uint32_t type = 0; // GameObjectType (e.g. 3=chest, 2=questgiver)
bool isValid() const { return entry != 0 && !name.empty(); }
};
/** SMSG_GAMEOBJECT_QUERY_RESPONSE parser */
class GameObjectQueryResponseParser {
public:
static bool parse(network::Packet& packet, GameObjectQueryResponseData& 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);
};
/** 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<SubDamage> 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<uint32_t> spellIds;
std::vector<SpellCooldownEntry> 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_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<uint64_t> 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<std::pair<uint8_t, AuraSlot>> 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<std::pair<uint32_t, uint32_t>> 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();
};
/** 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<LootItem> 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<GossipOption> options;
std::vector<GossipQuestItem> quests;
bool isValid() const { return true; }
};
/** CMSG_GOSSIP_HELLO packet builder */
class GossipHelloPacket {
public:
static network::Packet build(uint64_t npcGuid);
};
/** CMSG_QUESTGIVER_HELLO packet builder */
class QuestgiverHelloPacket {
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);
};
// ============================================================
// Bind Point (Hearthstone)
// ============================================================
struct BindPointUpdateData {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
uint32_t mapId = 0;
uint32_t zoneId = 0;
};
/** CMSG_BINDER_ACTIVATE packet builder */
class BinderActivatePacket {
public:
static network::Packet build(uint64_t npcGuid);
};
/** SMSG_BINDPOINTUPDATE parser */
class BindPointUpdateParser {
public:
static bool parse(network::Packet& packet, BindPointUpdateData& 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<QuestRewardItem> 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<QuestRewardItem> choiceRewards; // Pick one
std::vector<QuestRewardItem> 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<VendorItem> 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, uint32_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);
};
// ============================================================
// Trainer
// ============================================================
struct TrainerSpell {
uint32_t spellId = 0;
uint8_t state = 0; // 0=known(green), 1=available, 2=unavailable(red)
uint32_t spellCost = 0; // copper
uint32_t profDialog = 0;
uint32_t profButton = 0;
uint8_t reqLevel = 0;
uint32_t reqSkill = 0;
uint32_t reqSkillValue = 0;
uint32_t chainNode1 = 0;
uint32_t chainNode2 = 0;
uint32_t chainNode3 = 0;
};
struct TrainerListData {
uint64_t trainerGuid = 0;
uint32_t trainerType = 0; // 0=class, 1=mounts, 2=tradeskills, 3=pets
std::vector<TrainerSpell> spells;
std::string greeting;
bool isValid() const { return true; }
};
class TrainerListParser {
public:
static bool parse(network::Packet& packet, TrainerListData& data);
};
class TrainerBuySpellPacket {
public:
static network::Packet build(uint64_t trainerGuid, uint32_t trainerId, uint32_t spellId);
};
// ============================================================
// Taxi / Flight Paths
// ============================================================
static constexpr uint32_t TLK_TAXI_MASK_SIZE = 12;
/** SMSG_SHOWTAXINODES data */
struct ShowTaxiNodesData {
uint32_t windowInfo = 0; // 1 = show window
uint64_t npcGuid = 0;
uint32_t nearestNode = 0; // Taxi node player is at
uint32_t nodeMask[TLK_TAXI_MASK_SIZE] = {};
bool isNodeKnown(uint32_t nodeId) const {
if (nodeId == 0) return false;
uint32_t bitIndex = nodeId - 1;
uint32_t idx = bitIndex / 32;
uint32_t bit = bitIndex % 32;
return idx < TLK_TAXI_MASK_SIZE && (nodeMask[idx] & (1u << bit));
}
};
/** SMSG_SHOWTAXINODES parser */
class ShowTaxiNodesParser {
public:
static bool parse(network::Packet& packet, ShowTaxiNodesData& data);
};
/** SMSG_ACTIVATETAXIREPLY data */
struct ActivateTaxiReplyData {
uint32_t result = 0; // 0 = OK
};
/** SMSG_ACTIVATETAXIREPLY parser */
class ActivateTaxiReplyParser {
public:
static bool parse(network::Packet& packet, ActivateTaxiReplyData& data);
};
/** CMSG_ACTIVATETAXIEXPRESS packet builder */
class ActivateTaxiExpressPacket {
public:
static network::Packet build(uint64_t npcGuid, uint32_t totalCost, const std::vector<uint32_t>& pathNodes);
};
/** CMSG_ACTIVATETAXI packet builder */
class ActivateTaxiPacket {
public:
static network::Packet build(uint64_t npcGuid, uint32_t srcNode, uint32_t destNode);
};
/** CMSG_GAMEOBJECT_USE packet builder */
class GameObjectUsePacket {
public:
static network::Packet build(uint64_t guid);
};
/** 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);
};
/** CMSG_RESURRECT_RESPONSE packet builder */
class ResurrectResponsePacket {
public:
static network::Packet build(uint64_t casterGuid, bool accept);
};
} // namespace game
} // namespace wowee