Add Tier 1 utility commands: ignore, sit/stand, and logout

Ignore Commands:
- Add /ignore <name> to block messages from players
- Add /unignore <name> to unblock players
- Maintain ignoreCache for name-to-GUID lookups
- Show confirmation and error messages for ignore actions
- Use CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D)

Sit/Stand/Kneel Commands:
- Add /sit to sit down (stand state 1)
- Add /stand to stand up (stand state 0)
- Add /kneel to kneel (stand state 8)
- Instant visual feedback with CMSG_STAND_STATE_CHANGE (0x101)
- Support for additional stand states (chair, sleep, etc.)

Logout Commands:
- Add /logout and /camp to initiate logout with countdown
- Add /cancellogout to cancel pending logout
- Show "Logging out in 20 seconds..." or "Logout complete" messages
- Track logout state with loggingOut_ flag to prevent duplicate requests
- Handle instant logout (in inn/city) vs countdown logout
- Use opcodes:
  - CMSG_LOGOUT_REQUEST (0x4B)
  - CMSG_LOGOUT_CANCEL (0x4E)
  - SMSG_LOGOUT_RESPONSE (0x4C)
  - SMSG_LOGOUT_COMPLETE (0x4D)

Implementation:
- Add LogoutRequestPacket, LogoutCancelPacket builders
- Add LogoutResponseParser to parse server logout responses
- Add StandStateChangePacket builder for stance changes
- Add AddIgnorePacket and DelIgnorePacket for ignore list management
- Add handleLogoutResponse() and handleLogoutComplete() handlers
- Add ignoreCache map and loggingOut_ state tracking
- All commands display feedback in chat window
This commit is contained in:
kelsi davis 2026-02-07 12:58:11 -08:00
parent 6f45c6ab69
commit ec32286b0d
6 changed files with 325 additions and 0 deletions

View file

@ -214,10 +214,19 @@ public:
void addFriend(const std::string& playerName, const std::string& note = "");
void removeFriend(const std::string& playerName);
void setFriendNote(const std::string& playerName, const std::string& note);
void addIgnore(const std::string& playerName);
void removeIgnore(const std::string& playerName);
// Random roll
void randomRoll(uint32_t minRoll = 1, uint32_t maxRoll = 100);
// Logout commands
void requestLogout();
void cancelLogout();
// Stand state
void setStandState(uint8_t state); // 0=stand, 1=sit, 2=sit_chair, 3=sleep, 4=sit_low_chair, 5=sit_medium_chair, 6=sit_high_chair, 7=dead, 8=kneel, 9=submerged
// ---- Phase 1: Name queries ----
void queryPlayerName(uint64_t guid);
void queryCreatureInfo(uint32_t entry, uint64_t guid);
@ -525,6 +534,10 @@ private:
void handleFriendStatus(network::Packet& packet);
void handleRandomRoll(network::Packet& packet);
// ---- Logout handlers ----
void handleLogoutResponse(network::Packet& packet);
void handleLogoutComplete(network::Packet& packet);
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource);
void addSystemChatMessage(const std::string& message);
@ -607,6 +620,12 @@ private:
// ---- Friend list cache ----
std::unordered_map<std::string, uint64_t> friendsCache; // name -> guid
// ---- Ignore list cache ----
std::unordered_map<std::string, uint64_t> ignoreCache; // name -> guid
// ---- Logout state ----
bool loggingOut_ = false;
// ---- Online item tracking ----
struct OnlineItemInfo {
uint32_t entry = 0;

View file

@ -71,6 +71,16 @@ enum class Opcode : uint16_t {
CMSG_ADD_IGNORE = 0x06C,
CMSG_DEL_IGNORE = 0x06D,
// ---- Logout Commands ----
CMSG_PLAYER_LOGOUT = 0x04A,
CMSG_LOGOUT_REQUEST = 0x04B,
CMSG_LOGOUT_CANCEL = 0x04E,
SMSG_LOGOUT_RESPONSE = 0x04C,
SMSG_LOGOUT_COMPLETE = 0x04D,
// ---- Stand State ----
CMSG_STAND_STATE_CHANGE = 0x101,
// ---- Random Roll ----
MSG_RANDOM_ROLL = 0x1FB,

View file

@ -736,6 +736,56 @@ 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);
};
// ============================================================
// Random Roll
// ============================================================