/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. */ #pragma once // Standard library includes #include #include #include #include #include #include #include // Project includes #include "../common/linked_list.h" #include "../common/timer.h" #include "../common/TCPConnection.h" #include "../common/PacketStruct.h" #include "login_structs.h" #include "LoginAccount.h" // Forward declarations class DelayQue; class EQStream; class EQ2Packet; class EQApplicationPacket; /** * @brief Login modes for client state management */ enum class LoginMode : std::uint8_t { None, // No login state Normal, // Normal login process Registration // Account registration mode }; /** * @brief Represents a connected client in the login server * * This class manages individual client connections, handling: * - Authentication and login process * - Character selection and creation * - World server communication * - Packet processing and queuing */ class Client { public: /** * @brief Constructs a new client instance * @param ieqnc The EQStream connection for this client */ explicit Client(EQStream* ieqnc); /** * @brief Destructor - ensures proper cleanup of client resources */ ~Client(); // Disable copy operations Client(const Client&) = delete; Client& operator=(const Client&) = delete; // Login response methods /** * @brief Sends a login denied message to the client */ void SendLoginDenied(); /** * @brief Sends a login denied message due to version mismatch */ void SendLoginDeniedBadVersion(); /** * @brief Sends a login accepted message to the client * @param account_id The account ID (default: 1) * @param login_response The login response code (default: 0) */ void SendLoginAccepted(std::int32_t account_id = 1, std::int8_t login_response = 0); // World and character list methods /** * @brief Sends the world server list to the client */ void SendWorldList(); /** * @brief Sends the character list to the client */ void SendCharList(); /** * @brief Adds a world server to the list buffer * @param buffer Output buffer for world data * @param name World server name * @param id World server ID * @param flags World server flags * @return Size of data written to buffer */ std::int16_t AddWorldToList2(unsigned char* buffer, const char* name, std::int32_t id, std::int16_t* flags); /** * @brief Generates checksum for outgoing packet * @param outapp Packet to generate checksum for */ void GenerateChecksum(EQApplicationPacket* outapp); /** * @brief Main processing loop for the client * @return true if client is still active, false if should be removed */ bool Process(); /** * @brief Saves client error logs to database * @param app Packet containing error data * @param type Type of error log * @param version Client version */ void SaveErrorsToDB(EQApplicationPacket* app, const char* type, std::int32_t version); // Character management methods /** * @brief Handles character creation approval from world server * @param server_id World server ID * @param char_id New character ID */ void CharacterApproved(std::int32_t server_id, std::int32_t char_id); /** * @brief Handles character creation rejection * @param reason_number Rejection reason code */ void CharacterRejected(std::int8_t reason_number); /** * @brief Processes login attempt * @param name Account name * @param pass Account password * @param seq Sequence number (default: 0) */ void ProcessLogin(const char* name, const char* pass, int seq = 0); /** * @brief Queues a packet for sending to the client * @param app Packet to queue */ void QueuePacket(EQ2Packet* app); /** * @brief Sends a fatal error to the client * @param response Error response code */ void FatalError(std::int8_t response); /** * @brief Handles world server response for play request * @param worldid World server ID * @param response Response code * @param ip_address World server IP * @param port World server port * @param access_key Access key for world server */ void WorldResponse(std::int32_t worldid, std::int8_t response, char* ip_address, std::int32_t port, std::int32_t access_key); /** * @brief Sends play failed message to client * @param response Failure reason code */ void SendPlayFailed(std::int8_t response); /** * @brief Starts the disconnect timer */ void StartDisconnectTimer(); // Getter methods [[nodiscard]] EQStream* getConnection() { return eqnc_; } [[nodiscard]] LoginAccount* GetLoginAccount() { return login_account_.get(); } [[nodiscard]] std::int16_t GetVersion() const { return version_; } [[nodiscard]] char* GetKey() { return key_; } [[nodiscard]] std::int32_t GetIP() const { return ip_; } [[nodiscard]] std::int16_t GetPort() const { return port_; } [[nodiscard]] std::int32_t GetAccountID() const { return account_id_; } [[nodiscard]] const char* GetAccountName() const { return account_name_.c_str(); } [[nodiscard]] bool AwaitingCharCreationRequest() const { return createRequest_ != nullptr; } // Setter methods void SetLoginAccount(LoginAccount* in_account) { login_account_.reset(in_account); if (in_account) { account_id_ = in_account->getLoginAccountID(); } } void SetKey(const char* in_key) { std::strncpy(key_, in_key, sizeof(key_) - 1); key_[sizeof(key_) - 1] = '\0'; } void SetAccountName(const char* name) { account_name_ = name; } // Public data members (legacy compatibility) std::int8_t LoginKey[10]{}; // Login key for authentication std::int8_t ClientSession[25]{}; // Client session data // Timers std::unique_ptr updatetimer; // Timer for periodic updates std::unique_ptr updatelisttimer; // Timer for world list updates std::unique_ptr disconnectTimer; // Timer for disconnect timeout // Request tracking std::int16_t packettotal{0}; // Total packets processed std::int32_t requested_server_id{0}; // Requested world server ID std::int32_t request_num{0}; // Current request number // Delay queue for packet scheduling LinkedList delay_que; private: // Character play state std::string pending_play_char_name_; // Name of character pending play std::int32_t pending_play_char_id_{0}; // ID of character pending play // Update state std::int8_t update_position_{0}; // Current position in update sequence std::int16_t num_updates_{0}; // Number of updates sent std::vector* update_packets_{nullptr}; // Update packet queue // Account information std::unique_ptr login_account_; // Login account data EQStream* eqnc_; // Network connection stream // Connection details std::int32_t ip_{0}; // Client IP address std::int16_t port_{0}; // Client port // Account data std::int32_t account_id_{0}; // Account ID in database std::string account_name_; // Account name char key_[10]{}; // Authentication key std::int8_t lsadmin_{0}; // Login server admin level std::int16_t worldadmin_{0}; // World server admin level int lsstatus_{0}; // Login server status // Client state flags bool kicked_{false}; // Client has been kicked bool verified_{false}; // Client has been verified bool start_{false}; // Client has started bool needs_world_list_{true}; // Client needs world list bool sent_character_list_{false}; // Character list has been sent // Version and mode std::int16_t version_{0}; // Client version LoginMode login_mode_{LoginMode::None}; // Current login mode // Character creation char bannedreason_[30]{}; // Ban reason if applicable PacketStruct* createRequest_{nullptr}; // Pending character creation request std::unique_ptr playWaitTimer_; // Timer for play request timeout }; /** * @brief Manages all connected clients * * Thread-safe container for managing multiple client connections */ class ClientList { public: /** * @brief Default constructor */ ClientList() = default; /** * @brief Destructor */ ~ClientList() = default; // Disable copy operations ClientList(const ClientList&) = delete; ClientList& operator=(const ClientList&) = delete; /** * @brief Adds a client to the list * @param client Client to add */ void Add(Client* client); /** * @brief Finds a client by IP and port * @param ip Client IP address * @param port Client port * @return Pointer to client if found, nullptr otherwise */ [[nodiscard]] Client* Get(std::int32_t ip, std::int16_t port); /** * @brief Finds a client by login server account ID * @param lsaccountid Login server account ID * @return Pointer to client if found, nullptr otherwise */ [[nodiscard]] Client* FindByLSID(std::int32_t lsaccountid); /** * @brief Finds clients waiting for character creation response */ void FindByCreateRequest(); /** * @brief Sends a packet to all connected clients * @param app Packet to send */ void SendPacketToAllClients(EQ2Packet* app); /** * @brief Processes all clients in the list */ void Process(); private: mutable std::mutex mutex_; // Mutex for thread safety std::map client_list_; // Map of clients to active status }; /** * @brief Delayed packet queue entry * * Holds a packet with an associated timer for delayed sending */ class DelayQue { public: /** * @brief Constructs a delayed queue entry * @param in_timer Timer for delay * @param in_packet Packet to delay */ DelayQue(Timer* in_timer, EQApplicationPacket* in_packet) : timer(in_timer) , packet(in_packet) { } Timer* timer; // Timer controlling the delay EQApplicationPacket* packet; // Packet to be sent after delay };