Merge 'remotes/trunk'
[0ad.git] / source / network / NetClient.h
blob1184434f0ba9192fabd52b382abe9a23b6aed233
1 /* Copyright (C) 2017 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 NETCLIENT_H
19 #define NETCLIENT_H
21 #include "network/fsm.h"
22 #include "network/NetFileTransfer.h"
23 #include "network/NetHost.h"
24 #include "scriptinterface/ScriptVal.h"
26 #include "ps/CStr.h"
28 #include <deque>
30 class CGame;
31 class CNetClientSession;
32 class CNetClientTurnManager;
33 class CNetServer;
34 class ScriptInterface;
36 typedef struct _ENetHost ENetHost;
38 // NetClient session FSM states
39 enum
41 NCS_UNCONNECTED,
42 NCS_CONNECT,
43 NCS_HANDSHAKE,
44 NCS_AUTHENTICATE,
45 NCS_INITIAL_GAMESETUP,
46 NCS_PREGAME,
47 NCS_LOADING,
48 NCS_JOIN_SYNCING,
49 NCS_INGAME
52 /**
53 * Network client.
54 * This code is run by every player (including the host, if they are not
55 * a dedicated server).
56 * It provides an interface between the GUI, the network (via CNetClientSession),
57 * and the game (via CGame and CNetClientTurnManager).
59 class CNetClient : public CFsm
61 NONCOPYABLE(CNetClient);
63 friend class CNetFileReceiveTask_ClientRejoin;
65 public:
66 /**
67 * Construct a client associated with the given game object.
68 * The game must exist for the lifetime of this object.
70 CNetClient(CGame* game, bool isLocalClient);
72 virtual ~CNetClient();
74 /**
75 * We assume that adding a tracing function that's only called
76 * during GC is better for performance than using a
77 * PersistentRooted<T> where each value needs to be added to
78 * the root set.
80 static void Trace(JSTracer *trc, void *data)
82 reinterpret_cast<CNetClient*>(data)->TraceMember(trc);
85 void TraceMember(JSTracer *trc);
87 /**
88 * Set the user's name that will be displayed to all players.
89 * This must not be called after the connection setup.
91 void SetUserName(const CStrW& username);
93 /**
94 * Returns the GUID of the local client.
95 * Used for distinguishing observers.
97 CStr GetGUID() const { return m_GUID; }
99 /**
100 * Set up a connection to the remote networked server.
101 * @param server IP address or host name to connect to
102 * @return true on success, false on connection failure
104 bool SetupConnection(const CStr& server, const u16 port, ENetHost* enetClient = NULL);
107 * Destroy the connection to the server.
108 * This client probably cannot be used again.
110 void DestroyConnection();
113 * Poll the connection for messages from the server and process them, and send
114 * any queued messages.
115 * This must be called frequently (i.e. once per frame).
117 void Poll();
120 * Locally triggers a GUI message if the connection to the server is being lost or has bad latency.
122 void CheckServerConnection();
125 * Flush any queued outgoing network messages.
126 * This should be called soon after sending a group of messages that may be batched together.
128 void Flush();
131 * Retrieves the next queued GUI message, and removes it from the queue.
132 * The returned value is in the GetScriptInterface() JS context.
134 * This is the only mechanism for the networking code to send messages to
135 * the GUI - it is pull-based (instead of push) so the engine code does not
136 * need to know anything about the code structure of the GUI scripts.
138 * The structure of the messages is <code>{ "type": "...", ... }</code>.
139 * The exact types and associated data are not specified anywhere - the
140 * implementation and GUI scripts must make the same assumptions.
142 * @return next message, or the value 'undefined' if the queue is empty
144 void GuiPoll(JS::MutableHandleValue);
147 * Add a message to the queue, to be read by GuiPoll.
148 * The script value must be in the GetScriptInterface() JS context.
150 void PushGuiMessage(const JS::HandleValue message);
153 * Return a concatenation of all messages in the GUI queue,
154 * for test cases to easily verify the queue contents.
156 std::string TestReadGuiMessages();
159 * Get the script interface associated with this network client,
160 * which is equivalent to the one used by the CGame in the constructor.
162 ScriptInterface& GetScriptInterface();
165 * Send a message to the server.
166 * @param message message to send
167 * @return true on success
169 bool SendMessage(const CNetMessage* message);
172 * Call when the network connection has been successfully initiated.
174 void HandleConnect();
177 * Call when the network connection has been lost.
179 void HandleDisconnect(u32 reason);
182 * Call when a message has been received from the network.
184 bool HandleMessage(CNetMessage* message);
187 * Call when the game has started and all data files have been loaded,
188 * to signal to the server that we are ready to begin the game.
190 void LoadFinished();
192 void SendGameSetupMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface);
194 void SendAssignPlayerMessage(const int playerID, const CStr& guid);
196 void SendChatMessage(const std::wstring& text);
198 void SendReadyMessage(const int status);
200 void SendClearAllReadyMessage();
202 void SendStartGameMessage();
205 * Call when the client has rejoined a running match and finished
206 * the loading screen.
208 void SendRejoinedMessage();
211 * Call to kick/ban a client
213 void SendKickPlayerMessage(const CStrW& playerName, bool ban);
216 * Call when the client has paused or unpaused the game.
218 void SendPausedMessage(bool pause);
220 private:
221 // Net message / FSM transition handlers
222 static bool OnConnect(void* context, CFsmEvent* event);
223 static bool OnHandshake(void* context, CFsmEvent* event);
224 static bool OnHandshakeResponse(void* context, CFsmEvent* event);
225 static bool OnAuthenticate(void* context, CFsmEvent* event);
226 static bool OnChat(void* context, CFsmEvent* event);
227 static bool OnReady(void* context, CFsmEvent* event);
228 static bool OnGameSetup(void* context, CFsmEvent* event);
229 static bool OnPlayerAssignment(void* context, CFsmEvent* event);
230 static bool OnInGame(void* context, CFsmEvent* event);
231 static bool OnGameStart(void* context, CFsmEvent* event);
232 static bool OnJoinSyncStart(void* context, CFsmEvent* event);
233 static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
234 static bool OnRejoined(void* context, CFsmEvent* event);
235 static bool OnKicked(void* context, CFsmEvent* event);
236 static bool OnClientTimeout(void* context, CFsmEvent* event);
237 static bool OnClientPerformance(void* context, CFsmEvent* event);
238 static bool OnClientsLoading(void* context, CFsmEvent* event);
239 static bool OnClientPaused(void* context, CFsmEvent* event);
240 static bool OnLoadedGame(void* context, CFsmEvent* event);
243 * Take ownership of a session object, and use it for all network communication.
245 void SetAndOwnSession(CNetClientSession* session);
248 * Push a message onto the GUI queue listing the current player assignments.
250 void PostPlayerAssignmentsToScript();
252 CGame *m_Game;
253 CStrW m_UserName;
255 /// Current network session (or NULL if not connected)
256 CNetClientSession* m_Session;
258 /// Turn manager associated with the current game (or NULL if we haven't started the game yet)
259 CNetClientTurnManager* m_ClientTurnManager;
261 /// Unique-per-game identifier of this client, used to identify the sender of simulation commands
262 u32 m_HostID;
264 /// True if the player is currently rejoining or has already rejoined the game.
265 bool m_Rejoin;
267 /// Whether to prevent the client of the host from timing out
268 bool m_IsLocalClient;
270 /// Latest copy of game setup attributes heard from the server
271 JS::PersistentRootedValue m_GameAttributes;
273 /// Latest copy of player assignments heard from the server
274 PlayerAssignmentMap m_PlayerAssignments;
276 /// Globally unique identifier to distinguish users beyond the lifetime of a single network session
277 CStr m_GUID;
279 /// Queue of messages for GuiPoll
280 std::deque<JS::Heap<JS::Value>> m_GuiMessageQueue;
282 /// Serialized game state received when joining an in-progress game
283 std::string m_JoinSyncBuffer;
285 /// Time when the server was last checked for timeouts and bad latency
286 std::time_t m_LastConnectionCheck;
289 /// Global network client for the standard game
290 extern CNetClient *g_NetClient;
292 #endif // NETCLIENT_H