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