Added different textures for each ptolemaic camel rank
[0ad.git] / source / network / NetServer.h
blob350779c211cd9576371966c6a29606775efbd16e
1 /* Copyright (C) 2011 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. 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 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. 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.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef NETSERVER_H
19 #define NETSERVER_H
21 #include "NetFileTransfer.h"
22 #include "NetHost.h"
24 #include "ps/ThreadUtil.h"
25 #include "scriptinterface/ScriptVal.h"
27 #include <vector>
29 class CNetServerSession;
30 class CNetServerTurnManager;
31 class CFsmEvent;
32 class ScriptInterface;
33 class CPlayerAssignmentMessage;
34 class CNetStatsTable;
35 class CSimulationMessage;
37 class CNetServerWorker;
39 enum NetServerState
41 // We haven't opened the port yet, we're just setting some stuff up.
42 // The worker thread has not been started.
43 SERVER_STATE_UNCONNECTED,
45 // The server is open and accepting connections. This is the screen where
46 // rules are set up by the operator and where players join and select civs
47 // and stuff.
48 SERVER_STATE_PREGAME,
50 // All the hosts are connected and are loading the game
51 SERVER_STATE_LOADING,
53 // The one with all the killing ;-)
54 SERVER_STATE_INGAME,
56 // The game is over and someone has won. Players might linger to chat or
57 // download the replay log.
58 SERVER_STATE_POSTGAME
61 /**
62 * Server session representation of client state
64 enum NetServerSessionState
66 // The client has disconnected or been disconnected
67 NSS_UNCONNECTED,
69 // The client has just connected and we're waiting for its handshake message,
70 // to agree on the protocol version
71 NSS_HANDSHAKE,
73 // The client has handshook and we're waiting for its authentication message,
74 // to find its name and check its password etc
75 NSS_AUTHENTICATE,
77 // The client has fully joined, and is in the pregame setup stage
78 // or is loading the game.
79 // Server must be in SERVER_STATE_PREGAME or SERVER_STATE_LOADING.
80 NSS_PREGAME,
82 // The client has authenticated but the game was already started,
83 // so it's synchronising with the game state from other clients
84 NSS_JOIN_SYNCING,
86 // The client is running the game.
87 // Server must be in SERVER_STATE_LOADING or SERVER_STATE_INGAME.
88 NSS_INGAME
91 /**
92 * Network server interface. Handles all the coordination between players.
93 * One person runs this object, and every player (including the host) connects their CNetClient to it.
95 * The actual work is performed by CNetServerWorker in a separate thread.
97 class CNetServer
99 NONCOPYABLE(CNetServer);
100 public:
102 * Construct a new network server.
103 * @param autostartPlayers if positive then StartGame will be called automatically
104 * once this many players are connected (intended for the command-line testing mode).
106 CNetServer(int autostartPlayers = -1);
108 ~CNetServer();
111 * Begin listening for network connections.
112 * This function is synchronous (it won't return until the connection is established).
113 * @return true on success, false on error (e.g. port already in use)
115 bool SetupConnection();
118 * Call from the GUI to update the player assignments.
119 * The given GUID will be (re)assigned to the given player ID.
120 * Any player currently using that ID will be unassigned.
121 * The changes will be asynchronously propagated to all clients.
123 void AssignPlayer(int playerID, const CStr& guid);
126 * Call from the GUI to asynchronously notify all clients that they should start loading the game.
128 void StartGame();
131 * Call from the GUI to update the game setup attributes.
132 * This must be called at least once before starting the game.
133 * The changes will be asynchronously propagated to all clients.
134 * @param attrs game attributes, in the script context of scriptInterface
136 void UpdateGameAttributes(const CScriptVal& attrs, ScriptInterface& scriptInterface);
139 * Set the turn length to a fixed value.
140 * TODO: we should replace this with some adapative lag-dependent computation.
142 void SetTurnLength(u32 msecs);
144 private:
145 CNetServerWorker* m_Worker;
149 * Network server worker thread.
150 * (This is run in a thread so that client/server communication is not delayed
151 * by the host player's framerate - the only delay should be the network latency.)
153 * Thread-safety:
154 * - SetupConnection and constructor/destructor must be called from the main thread.
155 * - The main thread may push commands onto the Queue members,
156 * while holding the m_WorkerMutex lock.
157 * - Public functions (SendMessage, Broadcast) must be called from the network
158 * server thread.
160 class CNetServerWorker
162 NONCOPYABLE(CNetServerWorker);
164 public:
165 // Public functions for CNetSession/CNetServerTurnManager to use:
168 * Send a message to the given network peer.
170 bool SendMessage(ENetPeer* peer, const CNetMessage* message);
173 * Send a message to all clients who have completed the full connection process
174 * (i.e. are in the pre-game or in-game states).
176 bool Broadcast(const CNetMessage* message);
178 private:
179 friend class CNetServer;
180 friend class CNetFileReceiveTask_ServerRejoin;
182 CNetServerWorker(int autostartPlayers);
183 ~CNetServerWorker();
186 * Begin listening for network connections.
187 * @return true on success, false on error (e.g. port already in use)
189 bool SetupConnection();
192 * Call from the GUI to update the player assignments.
193 * The given GUID will be (re)assigned to the given player ID.
194 * Any player currently using that ID will be unassigned.
195 * The changes will be propagated to all clients.
197 void AssignPlayer(int playerID, const CStr& guid);
200 * Call from the GUI to notify all clients that they should start loading the game.
202 void StartGame();
205 * Call from the GUI to update the game setup attributes.
206 * This must be called at least once before starting the game.
207 * The changes will be propagated to all clients.
208 * @param attrs game attributes, in the script context of GetScriptInterface()
210 void UpdateGameAttributes(const CScriptValRooted& attrs);
213 * Make a player name 'nicer' by limiting the length and removing forbidden characters etc.
215 static CStrW SanitisePlayerName(const CStrW& original);
218 * Make a player name unique, if it matches any existing session's name.
220 CStrW DeduplicatePlayerName(const CStrW& original);
223 * Get the script context used for game attributes.
225 ScriptInterface& GetScriptInterface();
228 * Set the turn length to a fixed value.
229 * TODO: we should replace this with some adaptive lag-dependent computation.
231 void SetTurnLength(u32 msecs);
233 void AddPlayer(const CStr& guid, const CStrW& name);
234 void RemovePlayer(const CStr& guid);
235 void SendPlayerAssignments();
237 void SetupSession(CNetServerSession* session);
238 bool HandleConnect(CNetServerSession* session);
240 void OnUserJoin(CNetServerSession* session);
241 void OnUserLeave(CNetServerSession* session);
243 static bool OnClientHandshake(void* context, CFsmEvent* event);
244 static bool OnAuthenticate(void* context, CFsmEvent* event);
245 static bool OnInGame(void* context, CFsmEvent* event);
246 static bool OnChat(void* context, CFsmEvent* event);
247 static bool OnLoadedGame(void* context, CFsmEvent* event);
248 static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
249 static bool OnDisconnect(void* context, CFsmEvent* event);
251 void CheckGameLoadStatus(CNetServerSession* changedSession);
253 void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message);
255 void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session);
259 * Internal script context for (de)serializing script messages,
260 * and for storing game attributes.
261 * (TODO: we shouldn't bother deserializing (except for debug printing of messages),
262 * we should just forward messages blindly and efficiently.)
264 ScriptInterface* m_ScriptInterface;
266 PlayerAssignmentMap m_PlayerAssignments;
268 CScriptValRooted m_GameAttributes;
270 int m_AutostartPlayers;
272 ENetHost* m_Host;
273 std::vector<CNetServerSession*> m_Sessions;
275 CNetStatsTable* m_Stats;
277 NetServerState m_State;
279 CStrW m_ServerName;
280 CStrW m_WelcomeMessage;
282 u32 m_NextHostID;
284 CNetServerTurnManager* m_ServerTurnManager;
287 * A copy of all simulation commands received so far, indexed by
288 * turn number, to simplify support for rejoining etc.
289 * TODO: verify this doesn't use too much RAM.
291 std::vector<std::vector<CSimulationMessage> > m_SavedCommands;
294 * The latest copy of the simulation state, received from an existing
295 * client when a new client has asked to rejoin the game.
297 std::string m_JoinSyncFile;
299 private:
300 // Thread-related stuff:
302 static void* RunThread(void* data);
303 void Run();
304 bool RunStep();
306 pthread_t m_WorkerThread;
307 CMutex m_WorkerMutex;
309 bool m_Shutdown; // protected by m_WorkerMutex
311 // Queues for messages sent by the game thread:
312 std::vector<std::pair<int, CStr> > m_AssignPlayerQueue; // protected by m_WorkerMutex
313 std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
314 std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
315 std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
318 /// Global network server for the standard game
319 extern CNetServer *g_NetServer;
321 #endif // NETSERVER_H