1 /* 2 * Copyright (C) 2011-2016 OpenDungeons Team 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef ODSERVER_H 19 #define ODSERVER_H 20 21 #include "ODSocketServer.h" 22 #include "modes/ConsoleInterface.h" 23 24 #include <OgreSingleton.h> 25 26 class ServerNotification; 27 class GameMap; 28 29 enum class ServerMode; 30 31 //! \brief An enum used to know what kind of game event it is. 32 enum class EventShortNoticeType : int32_t 33 { 34 genericGameInfo, 35 majorGameEvent, 36 aboutCreatures, 37 aboutSkills, 38 aboutObjectives 39 }; 40 41 ODPacket& operator<<(ODPacket& os, const EventShortNoticeType& type); 42 ODPacket& operator>>(ODPacket& is, EventShortNoticeType& type); 43 44 /** 45 * When playing single player or multiplayer, there is always one reference gamemap. It is 46 * the one on ODServer. There is also a client gamemap in ODFrameListener which is supposed to be 47 * a "copy" from the server gamemap containing only the useful information for the player. 48 * The server has its own thread to update the server gamemap. When a relevant change occurs, 49 * the server sends messages to the clients so that they know they should update the client gamemaps. 50 * The server gamemap should only be accessed from the server thread because it is not thread safe. 51 * and the server thread should never be used for calling functions from the client gamemap. 52 * As a consequence, ODFrameListener.h should not be included is ODServer.cpp 53 * Interactions between client and server gamemaps should only occur through client/server messages 54 * by queuing messages (calling queueServerNotification). 55 * Moreover, in processServerNotifications, no message should be sent directly to the clients (by 56 * creating an ODPacket and sending it to the clients) because it would break the queue order. Instead, 57 * queueServerNotification should be called with the message. 58 * Note that this rule is not followed when dealing with client connexions or chat because there 59 * is no need to synchronize such messages with the gamemap. 60 */ 61 class ODServer: public Ogre::Singleton<ODServer>, 62 public ODSocketServer 63 { 64 public: 65 enum ServerState 66 { 67 StateNone, 68 StateConfiguration, 69 StateGame 70 }; 71 ODServer(); 72 virtual ~ODServer(); 73 getServerMode()74 inline ServerMode getServerMode() const 75 { return mServerMode; } 76 77 bool startServer(const std::string& creator, const std::string& levelFilename, ServerMode mode, bool useMasterServer); 78 void stopServer(); 79 80 //! \brief Adds a server notification to the server notification queue. The message will be sent to the concerned player 81 void queueServerNotification(ServerNotification* n); 82 83 //! \brief Sends an asynchronous message to the concerned player. This function should be used really carefully as it can easily 84 //! make the game crash by sending messages in an unexpected order (changing the state of an entity that was not created, for example). 85 //! In most of the can, we will use it for messages that do not need synchronization with the game (example : chat) or 86 //! for messages that need to show reactivity (after a player does something like building a room or tried to pickup a creature). 87 void sendAsyncMsg(ServerNotification& notif); 88 89 void notifyExit(); 90 91 //! This function will block the calling thread until the game is launched and 92 //! all the clients disconnect. Then, it will return true if everything went well 93 //! and false if there is an error (server not launched or system error) 94 bool waitEndGame(); 95 96 int32_t getNetworkPort() const; 97 98 protected: 99 ODSocketClient* notifyNewConnection(sf::TcpListener& sockListener) override; 100 bool notifyClientMessage(ODSocketClient *sock) override; 101 void serverThread() override; 102 103 private: 104 uint32_t mUniqueNumberPlayer; 105 ServerMode mServerMode; 106 ServerState mServerState; 107 GameMap *mGameMap; 108 bool mSeatsConfigured; 109 //! Player allowed to configure the lobby, save the game, ... 110 Player* mPlayerConfig; 111 std::vector<Player*> mDisconnectedPlayers; 112 113 std::deque<ServerNotification*> mServerNotificationQueue; 114 115 std::map<ODSocketClient*, std::vector<std::string>> mCreaturesInfoWanted; 116 117 ConsoleInterface mConsoleInterface; 118 119 std::string mMasterServerGameId; 120 double mMasterServerGameStatusUpdateTime; 121 122 void printConsoleMsg(const std::string& text); 123 124 ODSocketClient* getClientFromPlayer(Player* player); 125 ODSocketClient* getClientFromPlayerId(int32_t playerId); 126 127 //! \brief Called when a new turn started. 128 void startNewTurn(double timeSinceLastTurn); 129 130 /*! \brief Monitors mServerNotificationQueue for new events and informs the clients about them. 131 * 132 * This function is used in server mode and acts as a "consumer" on 133 * mServerNotificationQueue. It takes an event out of the queue, determines 134 * which clients need to be informed about that particular event, and 135 * dispacthes TCP packets to inform the clients about the new information. 136 */ 137 void processServerNotifications(); 138 139 /*! \brief The function running in server-mode which listens for messages from an individual, already connected, client. 140 * 141 * This function receives TCP packets one at a time from a connected client, 142 * decodes them, and carries out requests for the client, returning any 143 * results. 144 * \returns false When the client has disconnected. 145 */ 146 bool processClientNotifications(ODSocketClient* clientSocket); 147 148 //! \brief Sends the packet to the given player. If player is nullptr, the packet is sent to every connected player 149 void sendMsg(Player* player, ODPacket& packet); 150 151 void fireSeatConfigurationRefresh(); 152 153 //! \brief Handles console command. player is the player that launched the command 154 void handleConsoleCommand(Player* player, GameMap* gameMap, const std::vector<std::string>& args); 155 }; 156 157 #endif // ODSERVER_H 158