1 #ifndef __LOBBY_2_SERVER_H 2 #define __LOBBY_2_SERVER_H 3 4 #include "Export.h" 5 #include "RakNetTypes.h" 6 #include "Lobby2Plugin.h" 7 #include "DS_OrderedList.h" 8 #include "ThreadPool.h" 9 #include "Lobby2Presence.h" 10 11 //class PostgreSQLInterface; 12 13 namespace RakNet 14 { 15 16 struct Lobby2Message; 17 class RoomsPlugin; 18 19 /// Commands are either messages from remote systems, or can be run by the local system 20 /// \internal 21 struct Lobby2ServerCommand 22 { 23 Lobby2Message *lobby2Message; 24 bool deallocMsgWhenDone; 25 bool returnToSender; 26 unsigned int callerUserId; 27 RakNet::RakString callingUserName; 28 DataStructures::List<SystemAddress> callerSystemAddresses; 29 DataStructures::List<RakNetGUID> callerGuids; 30 //SystemAddress requiredConnectionAddress; 31 Lobby2Server *server; 32 }; 33 34 /// \brief The base class for the lobby server, without database specific functionality 35 /// \details This is a plugin which will take incoming messages via Lobby2Client_PC::SendMessage(), process them, and send back the same messages with output and a result code 36 /// Unlike the first implementation of the lobby server, this is a thin plugin that mostly just sends messages to threads and sends back the results. 37 /// \ingroup LOBBY_2_SERVER 38 class RAK_DLL_EXPORT Lobby2Server : public RakNet::Lobby2Plugin, public ThreadDataInterface 39 { 40 public: 41 Lobby2Server(); 42 virtual ~Lobby2Server(); 43 44 /// \brief Connect to the database \a numWorkerThreads times using the connection string 45 /// \param[in] conninfo See the postgre docs 46 /// \return True on success, false on failure. 47 virtual bool ConnectToDB(const char *conninfo, int numWorkerThreads)=0; 48 /// \internal 49 virtual void AddInputFromThread(Lobby2Message *msg, unsigned int targetUserId, RakNet::RakString targetUserHandle)=0; 50 /// \internal 51 virtual void AddOutputFromThread(Lobby2Message *msg, unsigned int targetUserId, RakNet::RakString targetUserHandle)=0; 52 53 /// \brief Lobby2Message encapsulates a user command, containing both input and output data 54 /// \details This will serialize and transmit that command 55 void SendMessage(Lobby2Message *msg, const DataStructures::List<SystemAddress> &recipients); 56 57 /// \brief Add a command, which contains a message and other data such as who send the message. 58 /// \details The command will be processed according to its implemented virtual functions. Most likely it will be processed in a thread to run database commands 59 void ExecuteCommand(Lobby2ServerCommand *command); 60 61 /// \brief If Lobby2Message::RequiresAdmin() returns true, the message can only be processed from a remote system if the sender's system address is first added() 62 /// \details This is useful if you want to administrate the server remotely 63 void AddAdminAddress(SystemAddress addr); 64 /// \brief If AddAdminAddress() was previously called with \a addr then this returns true. 65 bool HasAdminAddress(const DataStructures::List<SystemAddress> &addresses); 66 /// \brief Removes a system address previously added with AddAdminAddress() 67 void RemoveAdminAddress(SystemAddress addr); 68 /// \brief Removes all system addresses previously added with AddAdminAddress() 69 void ClearAdminAddresses(void); 70 71 /// \brief If Lobby2Message::RequiresRankingPermission() returns true, then the system that sent the command must be registered with AddRankingAddress() 72 /// \param[in] addr Address to allow 73 void AddRankingAddress(SystemAddress addr); 74 75 /// Returns if an address was previously added with AddRankingAddress() 76 /// \param[in] addr Address to check 77 bool HasRankingAddress(const DataStructures::List<SystemAddress> &addresses); 78 79 /// Removes an addressed added with AddRankingAddress() 80 /// \param[in] addr Address to check 81 void RemoveRankingAddress(SystemAddress addr); 82 83 /// \brief Clears all addresses added with AddRankingAddress() 84 void ClearRankingAddresses(void); 85 86 /// \brief To use RoomsPlugin and Lobby2Server together, register RoomsPlugin with this funcrtion 87 /// \details The rooms plugin does not automatically handle users logging in and logging off, or renaming users. 88 /// You can have Lobby2Server manage this for you by calling SetRoomsPlugin() with a pointer to the rooms plugin, if it is on the local system. 89 /// This will call RoomsPlugin::LoginRoomsParticipant() and RoomsPlugin::LogoffRoomsParticipant() as the messages L2MID_Client_Login and L2MID_Client_Logoff arrive 90 /// This will use the pointer to RoomsPlugin directly. Setting this will disable SetRoomsPluginAddress() 91 /// \note This is an empty function. You must #define __INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN and link with RoomsPlugin.h to use it() 92 void SetRoomsPlugin(RoomsPlugin *rp); 93 94 /// \brief This is similar to SetRoomsPlugin(), except the plugin is on another system. 95 /// \details This will set the system address of that system to send the login and logoff commands to. 96 /// For this function to work, you must first call RoomsPlugin::AddLoginServerAddress() so that RoomsPlugin will accept the incoming login and logoff messages. 97 /// \note This is an empty function. You must #define __INTEGRATE_LOBBY2_WITH_ROOMS_PLUGIN and link with RoomsPlugin.h to use it() 98 void SetRoomsPluginAddress(SystemAddress address); 99 100 /// \brief Server configuration properties, to customize how the server runs specific commands 101 struct ConfigurationProperties 102 { ConfigurationPropertiesConfigurationProperties103 ConfigurationProperties() {requiresEmailAddressValidationToLogin=false; requiresTitleToLogin=false; accountRegistrationRequiredAgeYears=0;} 104 105 /// \brief If true, Client_Login will fail with Client_Login_EMAIL_ADDRESS_NOT_VALIDATED unless the email address registered with Client_RegisterAccount is verified with the command System_SetEmailAddressValidated 106 bool requiresEmailAddressValidationToLogin; 107 108 /// \brief If true Client_Login::titleName and Client_Login::titleSecretKey must be previously registered with System_CreateTitle or Client_Login will fail with L2RC_Client_Login_BAD_TITLE_OR_TITLE_SECRET_KEY 109 bool requiresTitleToLogin; 110 111 /// \brief If true, Client_RegisterAccount::cdKey must be previously registered with CDKey_Add or Client_RegisterAccount will fail with L2RC_Client_RegisterAccount_REQUIRES_CD_KEY or a related error message 112 bool accountRegistrationRequiresCDKey; 113 114 /// \brief The minimum age needed to register accounts. If Client_RegisterAccount::createAccountParameters::ageInDays is less than this, then the account registration will fail with L2RC_Client_RegisterAccount_REQUIRED_AGE_NOT_MET 115 /// \details Per-title age requirements can be handled client-side with System_CreateTitle::requiredAge and System_GetTitleRequiredAge 116 unsigned int accountRegistrationRequiredAgeYears; 117 }; 118 119 /// \brief Set the desired configuration properties. This is read during runtime from threads. 120 void SetConfigurationProperties(ConfigurationProperties c); 121 /// \brief Get the previously set configuration properties. 122 const ConfigurationProperties *GetConfigurationProperties(void) const; 123 124 /// Set the presence of a logged in user 125 /// \param[in] presence Presence info of this user 126 void SetPresence(const RakNet::Lobby2Presence &presence, RakNet::RakString userHandle); 127 128 /// Get the presence of a logged in user, by handle 129 /// \param[out] presence Presence info of requested user 130 /// \param[in] userHandle Handle of the user 131 void GetPresence(RakNet::Lobby2Presence &presence, RakNet::RakString userHandle); 132 133 /// \internal Lets the plugin know that a user has logged on, so this user can be tracked and the message forwarded to RoomsPlugin 134 void OnLogin(Lobby2ServerCommand *command, bool calledFromThread); 135 /// \internal Lets the plugin know that a user has logged off, so this user can be tracked and the message forwarded to RoomsPlugin 136 void OnLogoff(Lobby2ServerCommand *command, bool calledFromThread); 137 /// \internal Lets the plugin know that a user has been renamed, so this user can be tracked and the message forwarded to RoomsPlugin 138 void OnChangeHandle(Lobby2ServerCommand *command, bool calledFromThread); 139 140 /// \internal 141 struct User 142 { 143 DataStructures::List<SystemAddress> systemAddresses; 144 DataStructures::List<RakNetGUID> guids; 145 unsigned int callerUserId; 146 RakNet::RakString userName; 147 Lobby2Presence presence; 148 bool allowMultipleLogins; 149 }; 150 151 /// \internal 152 static int UserCompByUsername( const RakString &key, Lobby2Server::User * const &data ); 153 154 /// \internal 155 struct ThreadAction 156 { 157 Lobby2MessageID action; 158 Lobby2ServerCommand command; 159 }; 160 GetUsers(void)161 const DataStructures::OrderedList<RakString, User*, Lobby2Server::UserCompByUsername>& GetUsers(void) const {return users;} 162 void GetUserOnlineStatus(UsernameAndOnlineStatus &userInfo) const; 163 164 165 protected: 166 167 void Update(void); 168 PluginReceiveResult OnReceive(Packet *packet); 169 void OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); 170 void OnShutdown(void); 171 void OnMessage(Packet *packet); 172 void Clear(void); 173 void ClearUsers(void); 174 unsigned int GetUserIndexBySystemAddress(SystemAddress systemAddress) const; 175 unsigned int GetUserIndexByGUID(RakNetGUID guid) const; 176 unsigned int GetUserIndexByUsername(RakNet::RakString userName) const; 177 void StopThreads(void); 178 void SendRemoteLoginNotification(RakNet::RakString handle, const DataStructures::List<SystemAddress>& recipients); 179 180 /// \internal 181 void RemoveUser(RakString userName); 182 /// \internal 183 void RemoveUser(unsigned int index); 184 void LogoffFromRooms(User *user); 185 186 virtual void* PerThreadFactory(void *context)=0; 187 virtual void PerThreadDestructor(void* factoryResult, void *context)=0; 188 virtual void AddInputCommand(Lobby2ServerCommand command)=0; ClearConnections(void)189 virtual void ClearConnections(void) {}; 190 191 DataStructures::OrderedList<SystemAddress, SystemAddress> adminAddresses; 192 DataStructures::OrderedList<SystemAddress, SystemAddress> rankingAddresses; 193 DataStructures::OrderedList<RakString, User*, Lobby2Server::UserCompByUsername> users; 194 RoomsPlugin *roomsPlugin; 195 SystemAddress roomsPluginAddress; 196 ThreadPool<Lobby2ServerCommand,Lobby2ServerCommand> threadPool; 197 SimpleMutex connectionPoolMutex; 198 ConfigurationProperties configurationProperties; 199 DataStructures::Queue<ThreadAction> threadActionQueue; 200 SimpleMutex threadActionQueueMutex; 201 202 //DataStructures::List<PostgreSQLInterface *> connectionPool; 203 void SendUnifiedToMultiple( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const DataStructures::List<SystemAddress> systemAddresses ); 204 }; 205 206 } 207 208 #endif