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/>.
21 #include "NetFileTransfer.h"
24 #include "ps/ThreadUtil.h"
25 #include "scriptinterface/ScriptVal.h"
29 class CNetServerSession
;
30 class CNetServerTurnManager
;
32 class ScriptInterface
;
33 class CPlayerAssignmentMessage
;
35 class CSimulationMessage
;
37 class CNetServerWorker
;
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
50 // All the hosts are connected and are loading the game
53 // The one with all the killing ;-)
56 // The game is over and someone has won. Players might linger to chat or
57 // download the replay log.
62 * Server session representation of client state
64 enum NetServerSessionState
66 // The client has disconnected or been disconnected
69 // The client has just connected and we're waiting for its handshake message,
70 // to agree on the protocol version
73 // The client has handshook and we're waiting for its authentication message,
74 // to find its name and check its password etc
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.
82 // The client has authenticated but the game was already started,
83 // so it's synchronising with the game state from other clients
86 // The client is running the game.
87 // Server must be in SERVER_STATE_LOADING or SERVER_STATE_INGAME.
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.
99 NONCOPYABLE(CNetServer
);
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);
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.
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
);
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.)
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
160 class CNetServerWorker
162 NONCOPYABLE(CNetServerWorker
);
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
);
179 friend class CNetServer
;
180 friend class CNetFileReceiveTask_ServerRejoin
;
182 CNetServerWorker(int autostartPlayers
);
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.
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
;
273 std::vector
<CNetServerSession
*> m_Sessions
;
275 CNetStatsTable
* m_Stats
;
277 NetServerState m_State
;
280 CStrW m_WelcomeMessage
;
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
;
300 // Thread-related stuff:
302 static void* RunThread(void* data
);
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