Add server info commands: /time, /played, and /who

- Add CMSG_QUERY_TIME (0x1CE) and SMSG_QUERY_TIME_RESPONSE (0x1CF) opcodes
- Add CMSG_REQUEST_PLAYED_TIME (0x1CC) and SMSG_PLAYED_TIME (0x1CD) opcodes
- Add CMSG_WHO (0x062) and SMSG_WHO (0x063) opcodes
- Implement /time command to query and display server time
- Implement /played command to show total and level playtime statistics
- Implement /who [name] command to list online players with level and guild
- Add packet builders: QueryTimePacket, RequestPlayedTimePacket, WhoPacket
- Add response parsers for all three server info packet types
- Add handlers that format and display responses in chat as system messages
- Format played time as "X days, Y hours, Z minutes" for readability
- Format server time as "YYYY-MM-DD HH:MM:SS" for readability
This commit is contained in:
kelsi davis 2026-02-07 12:43:32 -08:00
parent 8b8e32e716
commit f9c4cbddee
6 changed files with 287 additions and 0 deletions

View file

@ -648,6 +648,58 @@ public:
*/
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);
};
// ============================================================
// Phase 1: Foundation — Targeting, Name Queries
// ============================================================