/** * Copyright (C) 2014-2015 Justin James. * * This license must be preserved. * Any applications, libraries, or code which make any use of any * component of this program must not be commercial, unless explicit * permission is granted from the original author. The use of this * program for non-profit purposes is permitted. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * In the event that this license restricts you from making desired use of this program, contact the original author. * Written by Justin James */ #if !defined _RENX_SERVER_H_HEADER #define _RENX_SERVER_H_HEADER /** * @file RenX_Server.h * @brief Defines the Server class. */ #include #include "Jupiter/TCPSocket.h" #include "Jupiter/DLList.h" #include "Jupiter/ArrayList.h" #include "Jupiter/String.h" #include "Jupiter/CString.h" #include "Jupiter/INIFile.h" #include "Jupiter/Thinker.h" #include "Jupiter/Rehash.h" #include "RenX.h" #include "RenX_ServerProfile.h" /** DLL Linkage Nagging */ #if defined _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace RenX { /** Forward declarations */ struct PlayerInfo; class GameCommand; class Core; /** * @brief Represents a connection to an individiaul Renegade-X server. * There are often more than one of these, such as when communities run multiple servers. */ class RENX_API Server : public Jupiter::Thinker, public Jupiter::Rehashable { public: // Jupiter::Thinker /** * @brief Checks and processes raw socket data. * * @return Zero if no error occurs, a non-zero value otherwise. */ int think(); public: // Jupiter::Rehashable /** * @brief Rehashes an object's status. * * @return 0. */ virtual int OnRehash(); /** * @brief Fires when a non-zero value is returned by an object during a call to rehash(). * * @param removed True if the object was removed from the rehashable objects list, false otherwise. * @return True if the object should be deleted, false otherwise. */ virtual bool OnBadRehash(bool removed); public: // RenX::Server Jupiter::DLList players; /** A list of players in the server */ Jupiter::INIFile varData; /** This may be replaced later with a more dedicated type. */ const RenX::ServerProfile *profile = RenX::defaultProfile; /** * @brief Checks if the server is connected to RCON. * * @return True if the server is connected, false otherwise. */ bool isConnected() const; /** * @brief Checks if the game in progress is the first game. * * @return True if this is the first game, false otherwise. */ bool isFirstGame() const; /** * @brief Checks if the first kill has already been processed. * Note: This does not set to "true" until AFTER the first kill has been fully processed. * This includes processing by plugins. * * @return True if the first kill has been fully processed, false otherwise. */ bool isFirstKill() const; /** * @brief Checks if the first death has already been processed. * Note: This does not set to "true" until AFTER the first death has been fully processed. * This includes processing by plugins. * * @return True if the first death has been fully processed, false otherwise. */ bool isFirstDeath() const; /** * @brief Checks if the first action has already been processed. * Note: This does not set to "true" until AFTER the first action has been fully processed. * This includes processing by plugins. * An action is a kill, death, message, destroy, or any other player-induced interaction other than a join or part. * * @return True if the first action has been fully processed, false otherwise. */ bool isFirstAction() const; /** * @brief Checks if the server travel mode is seamless. * * @return True if the server is using seamless travel, false otherwise. */ bool isSeamless() const; /** * @brief Checks if a channel type is a public channel type. * * @param type Type to check against. * @return True if this is a public channel type, false otherwise. */ bool isPublicLogChanType(int type) const; /** * @brief Checks if a channel type is an administrative channel type. * * @param type Type to check against. * @return True if this is an administrative channel type, false otherwise. */ bool isAdminLogChanType(int type) const; /** * @brief Checks if a channel type is either a public or administrative channel type. * * @param type Type to check against. * @return True if this is either a public or administrative channel type, false otherwise. */ bool isLogChanType(int type) const; /** * @brief Sends a command to the server. * * @param commmand Command to send. * @return The number of bytes sent on success, less than or equal to zero otherwise. */ int send(const Jupiter::ReadableString &command); /** * @brief Sends an in-game message to the server. * * @param message Message to send in-game. * @return The number of bytes sent on success, less than or equal to zero otherwise. */ int sendMessage(const Jupiter::ReadableString &message); /** * @brief Sends an in-game message to a player in the server. * * @param player Data of the player to send a message to. * @param message Message to send in-game. * @return The number of bytes sent on success, less than or equal to zero otherwise. */ int sendMessage(const RenX::PlayerInfo *player, const Jupiter::ReadableString &message); /** * @brief Sends data to the server. * * @param data String of data to send. * @return The number of bytes sent on success, less than or equal to zero otherwise. */ int sendData(const Jupiter::ReadableString &data); /** * @brief Fetches a player's data based on their ID number. * * @param id ID of the player * @return A pointer to a player's corresponding PlayerInfo on success, nullptr otherwise. */ RenX::PlayerInfo *getPlayer(int id) const; /** * @brief Fetches a player's data, based on their name. * * @param name Name of the player. * @return A player's data on success, nullptr otherwise. */ RenX::PlayerInfo *getPlayerByName(const Jupiter::ReadableString &name) const; /** * @brief Fetches a player's data, based on part of their name. * * @param name Name of the player. * @return A player's data on success, nullptr otherwise. */ RenX::PlayerInfo *getPlayerByPartName(const Jupiter::ReadableString &partName) const; /** * @brief Fetches a player's data, based on part of their name. * Note: This does not check that the exact name exists first. * * @param name Name of the player. * @return A player's data on success, nullptr otherwise. */ RenX::PlayerInfo *getPlayerByPartNameFast(const Jupiter::ReadableString &partName) const; /** * @brief Formats a player's Steam ID into a readable string. * * @param player Player to fetch Steam ID from * @return A player's formatted Steam ID on success, an empty string otherwise. */ Jupiter::StringS formatSteamID(const RenX::PlayerInfo *player) const; /** * @brief Formats a Steam ID into a readable string. * * @param id Steam ID to format * @return A player's formatted Steam ID on success, an empty string otherwise. */ Jupiter::StringS formatSteamID(uint64_t id) const; /** * @brief Kicks a player from the server. * * @param id Player ID of the player to kick. */ void kickPlayer(int id); /** * @brief Kicks a player from the server. * * @param player Data of the player to kick. */ void kickPlayer(const RenX::PlayerInfo *player); /** * @brief Bans a player from the server. * * @param id Player ID of the player to ban. */ void banPlayer(int id); /** * @brief Bans a player from the server. * * @param player Data of the player to ban. * @param length Duration of the ban (0 for permanent). */ void banPlayer(const RenX::PlayerInfo *player, time_t length = 0); /** * @brief Removes a player's data based on their ID number. * * @param id ID of the player * @return True if a player was removed, false otherwise. */ bool removePlayer(int id); /** * @brief Removes a player's data based on a player's data. * * @param player Pointer to a player's data * @return True if a player was removed, false otherwise. */ bool removePlayer(RenX::PlayerInfo *player); /** * @brief Sends a client list request. * * @return True on success, false otherwise. */ bool updateClientList(); /** * @brief Forces the current game to end, if the server supports it. * * @return True on success, false otherwise. */ bool gameover(); /** * @brief Forces the current game to end and changes the map, if the server supports it. * * @return True on success, false otherwise. */ bool setMap(const Jupiter::ReadableString &map); /** * @brief Forces the current game to end, if the server supports it. * * @return True on success, false otherwise. */ bool loadMutator(const Jupiter::ReadableString &mutator); /** * @brief Forces the current game to end, if the server supports it. * * @return True on success, false otherwise. */ bool unloadMutator(const Jupiter::ReadableString &mutator); /** * @brief Forcefully ends the current vote, if the server supports it. * * @return True on success, false otherwise. */ bool cancelVote(const RenX::TeamType team); /** * @brief Swaps the teams, if the server supports it. * * @return True on success, false otherwise. */ bool swapTeams(); /** * @brief Starts a demo recording, if the server supports it. * * @return True on success, false otherwise. */ bool recordDemo(); /** * @brief Mutes a player from the game chat, if the server supports it. * * @return True on success, false otherwise. */ bool mute(const RenX::PlayerInfo *player); /** * @brief Allows a player to use the game chat, if the server supports it. * * @return True on success, false otherwise. */ bool unmute(const RenX::PlayerInfo *player); /** * @brief Gives a player additional credits, if the server supports it. * * @param id ID of the player to give credits to * @param credits Credits to give to player * @return True on success, false otherwise. */ bool giveCredits(int id, double credits); /** * @brief Gives a player additional credits, if the server supports it. * * @param player Player to give credits to * @param credits Credits to give to player * @return True on success, false otherwise. */ bool giveCredits(RenX::PlayerInfo *player, double credits); /** * @brief Forces a player to change teams, if the server supports it. * * @param id ID of the player to give credits to * @param resetCredits True to reset the player's credits, false otherwise. * @return True on success, false otherwise. */ bool changeTeam(int id, bool resetCredits = true); /** * @brief Forces a player to change teams, if the server supports it. * * @param player Player to change teams * @param resetCredits True to reset the player's credits, false otherwise. * @return True on success, false otherwise. */ bool changeTeam(RenX::PlayerInfo *player, bool resetCredits = true); /** * @brief Forces a player to change teams, if the server supports it. * * @param id ID of the player to give credits to * @param team Team number to switch to * @param options Options to pass to the command * @return True on success, false otherwise. */ bool setTeam(int id, int team, unsigned char options = 0x03); /** * @brief Forces a player to change teams, if the server supports it. * * @param player Player to change teams * @param team Team number to switch to * @param options Options to pass to the command * @return True on success, false otherwise. */ bool setTeam(RenX::PlayerInfo *player, int team, unsigned char options = 0x03); /** * @brief Fetches a server's IRC logging prefix. * * @return The server's logging prefix. */ const Jupiter::ReadableString &getPrefix() const; /** * @brief Sets a server's IRC logging prefix. * * @param prefix Prefix to use. */ void setPrefix(const Jupiter::ReadableString &prefix); /** * @brief Fetches a server's game command prefix. * * @return The server's game command prefix. */ const Jupiter::ReadableString &getCommandPrefix() const; /** * @brief Sets a server's game command prefix. * * @param prefix Prefix to use. */ void setCommandPrefix(const Jupiter::ReadableString &prefix); /** * @brief Fetches the rules of a server. * * @return String containing the rules of the server. */ const Jupiter::ReadableString &getRules() const; /** * @brief Sets the rules of a server. * * @param rules Rules for the server to be used. */ void setRules(const Jupiter::ReadableString &rules); /** * @brief Fetches the hostname of a server. * * @return String containing the hostname of the server. */ const Jupiter::ReadableString &getHostname() const; /** * @brief Fetches the port of a server. * * @return Port of the server. */ unsigned short getPort() const; /** * @brief Fetches the time of the last connection attempt. * Note: This includes both successful and failed connection attempts. * * @return Time of the last connection attempt. */ time_t getLastAttempt() const; /** * @brief Fetches the time delay between connection attempts. * * @return Time delay between connection attempts. */ time_t getDelay() const; /** * @brief Fetches the password of a server. * * @return String containing the password of the server. */ const Jupiter::ReadableString &getPassword() const; /** * @brief Fetches this connection's RCON user name. * * @return String containing the RCON user name. */ const Jupiter::ReadableString &getUser() const; /** * @brief Fetches the name of this server. * * @return String containing the server name. */ const Jupiter::ReadableString &getName() const; /** * @brief Fetches the current map. * * @return String containing the current map. */ const Jupiter::ReadableString &getMap() const; /** * @brief Fetches a command from the list. * * @param index Index of the command to return. * @return Command located at the specified index. */ GameCommand *getCommand(unsigned int index) const; /** * @brief Fetches a command from the list. * * @param trigger Trigger of the command to get * @return Command with the specified trigger. */ GameCommand *getCommand(const Jupiter::ReadableString &trigger) const; /** * @brief Returns the number of commands in the command list. * * @return Number of commands in the command list. */ unsigned int getCommandCount() const; /** * @brief Triggers commands matching a specified trigger. * * @param trigger Trigger of the command to fire. * @return Number of commands triggered. */ unsigned int triggerCommand(const Jupiter::ReadableString &trigger, RenX::PlayerInfo *player, const Jupiter::ReadableString ¶meters); /** * @brief Adds a command to the server's game command list. * * @param command Command to add. */ void addCommand(RenX::GameCommand *command); /** * @brief Adds a command to the server's game command list. * * @param command Command to remove. * @return True if a command was removed, false otherwise. */ bool removeCommand(RenX::GameCommand *command); /** * @brief Adds a command to the server's game command list. * * @param trigger Trigger of the command to remove. * @return True if a command was removed, false otherwise. */ bool removeCommand(const Jupiter::ReadableString &trigger); /** * @brief Formats and sends a message to a server's corresponding public channels. * * @param fmt String containing the format specifiers indicating what message to send. */ void sendPubChan(const char *fmt, ...) const; void sendPubChan(const Jupiter::ReadableString &msg) const; /** * @brief Formats and sends a message to a server's corresponding adminstrative channels. * * @param fmt String containing the format specifiers indicating what message to send. */ void sendAdmChan(const char *fmt, ...) const; void sendAdmChan(const Jupiter::ReadableString &msg) const; /** * @brief Formats and sends a message to a server's corresponding channels. * * @param fmt String containing the format specifiers indicating what message to send. */ void sendLogChan(const char *fmt, ...) const; void sendLogChan(const Jupiter::ReadableString &msg) const; /** * @brief Processes a line of RCON input data. Input data SHOULD NOT include a new-line ('\n') terminator. * * @param line Line to process */ void processLine(const Jupiter::ReadableString &line); /** * @brief Disconnects from a server's RCON interface. */ void disconnect(); /** * @brief Connects to the server's RCON interface. * * @return True if the socket successfully connected, false otherwise. */ bool connect(); /** * @brief Reconnects to the server's RCON interface. * * @return True if the socket successfully connected, false otherwise. */ bool reconnect(); /** * @brief Deletes all of the data about a server (such as players). * This is mostly for use with the reconnect mechanism. */ void wipeData(); /** * @brief Fetches the RCON version number, or 0 or none has been set. * * @return RCON version number */ unsigned int getVersion() const; /** * @brief Fetches the eXtended-RCON version number, or 0 if none has been set. * * @return XRCON version number */ unsigned int getXVersion() const; /** * @brief Fetches the eXtended-RCON revision number, or 0 if none has been set. * * @return XRCON revision number */ unsigned int getXRevision() const; /** * @brief Fetches the game version string, or an empty string if none has been set. * * @return String containing the Game version */ const Jupiter::ReadableString &getGameVersion() const; /** * @brief Fetches the RCON user name. * * @return String containing the RCON user name */ const Jupiter::ReadableString &getRCONUsername() const; /** * @brief Creates the Server object, and loads settings from the specified configuration section. * * @param configurationSection Configuration section to load from. */ Server(const Jupiter::ReadableString &configurationSection); /** * @brief Destructor for Server class. */ ~Server(); /** Private members */ private: void init(); /** Tracking variables */ bool connected = false; bool seamless = false; bool needsCList = false; bool silenceParts = false; bool silenceJoins = false; bool firstGame = true; bool firstKill = false; bool firstDeath = false; bool firstAction = false; unsigned int rconVersion = 0; unsigned int xRconVersion = 0; unsigned int xRconRevision = 0; time_t lastAttempt = 0; Jupiter::String lastLine; Jupiter::StringS commandListFormat; Jupiter::StringS gameVersion; Jupiter::ArrayList commands; /** Configuration variables */ unsigned short port; int logChanType; int adminLogChanType; time_t delay; int steamFormat; /** 16 = hex, 10 = base 10, 8 = octal, -2 = SteamID 2, -3 = SteamID 3 */ unsigned int uuidMode; /** 0 = steam, 1 = nickname */ bool rconBan; bool localBan; bool localSteamBan; bool localIPBan; bool localNameBan; bool neverSay; Jupiter::TCPSocket sock; Jupiter::CStringS clientHostname; Jupiter::CStringS hostname; Jupiter::StringS pass; Jupiter::StringS configSection; Jupiter::StringS rules; Jupiter::StringS IRCPrefix; Jupiter::StringS CommandPrefix; Jupiter::StringS rconUser; Jupiter::StringS serverName; Jupiter::StringS lastCommand; Jupiter::StringS map; Jupiter::INIFile::Section *commandAccessLevels; Jupiter::INIFile::Section *commandAliases; }; } /** Re-enable warnings */ #if defined _MSC_VER #pragma warning(pop) #endif #endif // _RENX_SERVER_H_HEADER