mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
566 lines
14 KiB
C++
566 lines
14 KiB
C++
#pragma once
|
|
|
|
#include "network/packet.hpp"
|
|
#include "game/opcodes.hpp"
|
|
#include "game/entity.hpp"
|
|
#include <vector>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <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);
|
|
|
|
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 {
|
|
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<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);
|
|
};
|
|
|
|
/**
|
|
* 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);
|
|
};
|
|
|
|
// 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<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);
|
|
|
|
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
|