Pyrogenesis  trunk
NetClient.h
Go to the documentation of this file.
1 /* Copyright (C) 2022 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
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.
8  *
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.
13  *
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/>.
16  */
17 
18 #ifndef NETCLIENT_H
19 #define NETCLIENT_H
20 
21 #include "network/FSM.h"
23 #include "network/NetHost.h"
24 #include "scriptinterface/Object.h"
25 
26 #include "ps/CStr.h"
27 
28 #include <ctime>
29 #include <deque>
30 #include <thread>
31 
32 class CGame;
33 class CNetClientSession;
35 class ScriptInterface;
36 
37 typedef struct _ENetHost ENetHost;
38 
39 // NetClient session FSM states
40 enum
41 {
50 };
51 
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).
58  */
59 class CNetClient : public CFsm
60 {
62 
64 
65 public:
66  /**
67  * Construct a client associated with the given game object.
68  * The game must exist for the lifetime of this object.
69  */
70  CNetClient(CGame* game);
71 
72  virtual ~CNetClient();
73 
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.
79  */
80  static void Trace(JSTracer *trc, void *data)
81  {
82  reinterpret_cast<CNetClient*>(data)->TraceMember(trc);
83  }
84 
85  void TraceMember(JSTracer *trc);
86 
87  /**
88  * Set the user's name that will be displayed to all players.
89  * This must not be called after the connection setup.
90  */
91  void SetUserName(const CStrW& username);
92 
93  /**
94  * Store the JID of the host.
95  * This is needed for the secure lobby authentication.
96  */
97  void SetHostJID(const CStr& jid);
98 
99  void SetControllerSecret(const std::string& secret);
100 
101  bool IsController() const { return m_IsController; }
102 
103  /**
104  * Set the game password.
105  * Must be called after SetUserName, as that is used to hash further.
106  */
107  void SetGamePassword(const CStr& hashedPassword);
108 
109  /**
110  * Returns the GUID of the local client.
111  * Used for distinguishing observers.
112  */
113  CStr GetGUID() const { return m_GUID; }
114 
115  /**
116  * Set connection data to the remote networked server.
117  * @param address IP address or host name to connect to
118  */
119  void SetupServerData(CStr address, u16 port, bool stun);
120 
121  /**
122  * Set up a connection to the remote networked server.
123  * Must call SetupServerData first.
124  * @return true on success, false on connection failure
125  */
126  bool SetupConnection(ENetHost* enetClient);
127 
128  /**
129  * Request connection information over the lobby.
130  */
132 
133  /**
134  * Connect to the remote networked server using lobby.
135  * Push netstatus messages on failure.
136  * @param localNetwork - if true, assume we are trying to connect on the local network.
137  * @return true on success, false on connection failure
138  */
139  bool TryToConnect(const CStr& hostJID, bool localNetwork);
140 
141  /**
142  * Destroy the connection to the server.
143  * This client probably cannot be used again.
144  */
145  void DestroyConnection();
146 
147  /**
148  * Poll the connection for messages from the server and process them, and send
149  * any queued messages.
150  * This must be called frequently (i.e. once per frame).
151  */
152  void Poll();
153 
154  /**
155  * Locally triggers a GUI message if the connection to the server is being lost or has bad latency.
156  */
157  void CheckServerConnection();
158 
159  /**
160  * Retrieves the next queued GUI message, and removes it from the queue.
161  * The returned value is in the GetScriptInterface() JS context.
162  *
163  * This is the only mechanism for the networking code to send messages to
164  * the GUI - it is pull-based (instead of push) so the engine code does not
165  * need to know anything about the code structure of the GUI scripts.
166  *
167  * The structure of the messages is <code>{ "type": "...", ... }</code>.
168  * The exact types and associated data are not specified anywhere - the
169  * implementation and GUI scripts must make the same assumptions.
170  *
171  * @return next message, or the value 'undefined' if the queue is empty
172  */
173  void GuiPoll(JS::MutableHandleValue);
174 
175  /**
176  * Add a message to the queue, to be read by GuiPoll.
177  * The script value must be in the GetScriptInterface() JS context.
178  */
179  template<typename... Args>
180  void PushGuiMessage(Args const&... args)
181  {
183 
184  JS::RootedValue message(rq.cx);
185  Script::CreateObject(rq, &message, args...);
186  m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message));
187  }
188 
189  /**
190  * Return a concatenation of all messages in the GUI queue,
191  * for test cases to easily verify the queue contents.
192  */
193  std::string TestReadGuiMessages();
194 
195  /**
196  * Get the script interface associated with this network client,
197  * which is equivalent to the one used by the CGame in the constructor.
198  */
200 
201  /**
202  * Send a message to the server.
203  * @param message message to send
204  * @return true on success
205  */
206  bool SendMessage(const CNetMessage* message);
207 
208  /**
209  * Call when the network connection has been successfully initiated.
210  */
211  void HandleConnect();
212 
213  /**
214  * Call when the network connection has been lost.
215  */
216  void HandleDisconnect(u32 reason);
217 
218  /**
219  * Call when a message has been received from the network.
220  */
221  bool HandleMessage(CNetMessage* message);
222 
223  /**
224  * Call when the game has started and all data files have been loaded,
225  * to signal to the server that we are ready to begin the game.
226  */
227  void LoadFinished();
228 
229  void SendGameSetupMessage(JS::MutableHandleValue attrs, const ScriptInterface& scriptInterface);
230 
231  void SendAssignPlayerMessage(const int playerID, const CStr& guid);
232 
233  void SendChatMessage(const std::wstring& text);
234 
235  void SendReadyMessage(const int status);
236 
238 
239  void SendStartGameMessage(const CStr& initAttribs);
240 
241  /**
242  * Call when the client has rejoined a running match and finished
243  * the loading screen.
244  */
245  void SendRejoinedMessage();
246 
247  /**
248  * Call to kick/ban a client
249  */
250  void SendKickPlayerMessage(const CStrW& playerName, bool ban);
251 
252  /**
253  * Call when the client has paused or unpaused the game.
254  */
255  void SendPausedMessage(bool pause);
256 
257  /**
258  * @return Whether the NetClient is shutting down.
259  */
260  bool ShouldShutdown() const;
261 
262  /**
263  * Called when fetching connection data from the host failed, to inform JS code.
264  */
265  void HandleGetServerDataFailed(const CStr& error);
266 private:
267 
269 
270  // Net message / FSM transition handlers
271  static bool OnConnect(void* context, CFsmEvent* event);
272  static bool OnHandshake(void* context, CFsmEvent* event);
273  static bool OnHandshakeResponse(void* context, CFsmEvent* event);
274  static bool OnAuthenticateRequest(void* context, CFsmEvent* event);
275  static bool OnAuthenticate(void* context, CFsmEvent* event);
276  static bool OnChat(void* context, CFsmEvent* event);
277  static bool OnReady(void* context, CFsmEvent* event);
278  static bool OnGameSetup(void* context, CFsmEvent* event);
279  static bool OnPlayerAssignment(void* context, CFsmEvent* event);
280  static bool OnInGame(void* context, CFsmEvent* event);
281  static bool OnGameStart(void* context, CFsmEvent* event);
282  static bool OnJoinSyncStart(void* context, CFsmEvent* event);
283  static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
284  static bool OnRejoined(void* context, CFsmEvent* event);
285  static bool OnKicked(void* context, CFsmEvent* event);
286  static bool OnClientTimeout(void* context, CFsmEvent* event);
287  static bool OnClientPerformance(void* context, CFsmEvent* event);
288  static bool OnClientsLoading(void* context, CFsmEvent* event);
289  static bool OnClientPaused(void* context, CFsmEvent* event);
290  static bool OnLoadedGame(void* context, CFsmEvent* event);
291 
292  /**
293  * Take ownership of a session object, and use it for all network communication.
294  */
295  void SetAndOwnSession(CNetClientSession* session);
296 
297  /**
298  * Push a message onto the GUI queue listing the current player assignments.
299  */
301 
303  CStrW m_UserName;
304 
305  CStr m_HostJID;
308  bool m_UseSTUN;
309 
310  /**
311  * Password to join the game.
312  */
314 
315  /// The 'secret' used to identify the controller of the game.
316  std::string m_ControllerSecret;
317 
318  /// Note that this is just a "gui hint" with no actual impact on being controller.
319  bool m_IsController = false;
320 
321  /// Current network session (or NULL if not connected)
323 
324  std::thread m_PollingThread;
325 
326  /// Turn manager associated with the current game (or NULL if we haven't started the game yet)
328 
329  /// Unique-per-game identifier of this client, used to identify the sender of simulation commands
331 
332  /// True if the player is currently rejoining or has already rejoined the game.
333  bool m_Rejoin;
334 
335  /// Latest copy of player assignments heard from the server
337 
338  /// Globally unique identifier to distinguish users beyond the lifetime of a single network session
339  CStr m_GUID;
340 
341  /// Queue of messages for GuiPoll
342  std::deque<JS::Heap<JS::Value>> m_GuiMessageQueue;
343 
344  /// Serialized game state received when joining an in-progress game
345  std::string m_JoinSyncBuffer;
346 
347  /// Time when the server was last checked for timeouts and bad latency
349 };
350 
351 /// Global network client for the standard game
352 extern CNetClient *g_NetClient;
353 
354 #endif // NETCLIENT_H
void PushGuiMessage(Args const &... args)
Add a message to the queue, to be read by GuiPoll.
Definition: NetClient.h:180
The container that holds the rules, resources and attributes of the game.
Definition: Game.h:42
CStr m_ServerAddress
Definition: NetClient.h:306
JSContext * cx
Definition: ScriptRequest.h:92
void DestroyConnection()
Destroy the connection to the server.
Definition: NetClient.cpp:338
Manages states, events, actions and transitions between states.
Definition: FSM.h:168
CStr m_HostJID
Definition: NetClient.h:305
void SendAssignPlayerMessage(const int playerID, const CStr &guid)
Definition: NetClient.cpp:489
std::map< CStr, PlayerAssignment > PlayerAssignmentMap
Definition: NetHost.h:54
static bool OnRejoined(void *context, CFsmEvent *event)
Definition: NetClient.cpp:858
bool m_UseSTUN
Definition: NetClient.h:308
std::thread m_PollingThread
Definition: NetClient.h:324
std::time_t m_LastConnectionCheck
Time when the server was last checked for timeouts and bad latency.
Definition: NetClient.h:348
void HandleGetServerDataFailed(const CStr &error)
Called when fetching connection data from the host failed, to inform JS code.
Definition: NetClient.cpp:223
const ScriptInterface & GetScriptInterface()
Get the script interface associated with this network client, which is equivalent to the one used by ...
Definition: NetClient.cpp:424
CNetClientTurnManager * m_ClientTurnManager
Turn manager associated with the current game (or NULL if we haven&#39;t started the game yet) ...
Definition: NetClient.h:327
std::string m_ControllerSecret
The &#39;secret&#39; used to identify the controller of the game.
Definition: NetClient.h:316
struct _ENetHost ENetHost
Definition: NetClient.h:37
uint16_t u16
Definition: types.h:38
Represents a signal in the state machine that a change has occurred.
Definition: FSM.h:52
virtual ~CNetClient()
Definition: NetClient.cpp:158
CNetClientSession * m_Session
Current network session (or NULL if not connected)
Definition: NetClient.h:322
static bool OnAuthenticateRequest(void *context, CFsmEvent *event)
Definition: NetClient.cpp:694
void LoadFinished()
Call when the game has started and all data files have been loaded, to signal to the server that we a...
Definition: NetClient.cpp:588
bool IsController() const
Definition: NetClient.h:101
u16 m_ServerPort
Definition: NetClient.h:307
static bool OnChat(void *context, CFsmEvent *event)
Definition: NetClient.cpp:724
void GuiPoll(JS::MutableHandleValue)
Retrieves the next queued GUI message, and removes it from the queue.
Definition: NetClient.cpp:396
Definition: NetClient.h:43
Definition: NetClient.h:42
void SendKickPlayerMessage(const CStrW &playerName, bool ban)
Call to kick/ban a client.
Definition: NetClient.cpp:530
std::string TestReadGuiMessages()
Return a concatenation of all messages in the GUI queue, for test cases to easily verify the queue co...
Definition: NetClient.cpp:408
static bool OnClientTimeout(void *context, CFsmEvent *event)
Definition: NetClient.cpp:887
static bool OnHandshake(void *context, CFsmEvent *event)
Definition: NetClient.cpp:650
static bool OnLoadedGame(void *context, CFsmEvent *event)
Definition: NetClient.cpp:963
static bool OnInGame(void *context, CFsmEvent *event)
Definition: NetClient.cpp:984
bool m_IsController
Note that this is just a "gui hint" with no actual impact on being controller.
Definition: NetClient.h:319
void HandleConnect()
Call when the network connection has been successfully initiated.
Definition: NetClient.cpp:463
static bool OnAuthenticate(void *context, CFsmEvent *event)
Definition: NetClient.cpp:703
void SetupConnectionViaLobby()
Request connection information over the lobby.
Definition: NetClient.cpp:209
void HandleDisconnect(u32 reason)
Call when the network connection has been lost.
Definition: NetClient.cpp:468
void PostPlayerAssignmentsToScript()
Push a message onto the GUI queue listing the current player assignments.
Definition: NetClient.cpp:429
bool SendMessage(const CNetMessage *message)
Send a message to the server.
Definition: NetClient.cpp:455
Definition: NetClient.h:46
uint32_t u32
Definition: types.h:39
static bool OnReady(void *context, CFsmEvent *event)
Definition: NetClient.cpp:739
Various declarations shared by networking code.
CNetClient(CGame *game)
Construct a client associated with the given game object.
Definition: NetClient.cpp:86
void SendPausedMessage(bool pause)
Call when the client has paused or unpaused the game.
Definition: NetClient.cpp:538
static bool OnConnect(void *context, CFsmEvent *event)
Definition: NetClient.cpp:637
PlayerAssignmentMap m_PlayerAssignments
Latest copy of player assignments heard from the server.
Definition: NetClient.h:336
void SetAndOwnSession(CNetClientSession *session)
Take ownership of a session object, and use it for all network communication.
Definition: NetClient.cpp:332
void SetGamePassword(const CStr &hashedPassword)
Set the game password.
Definition: NetClient.cpp:186
CGame * m_Game
Definition: NetClient.h:302
static bool OnPlayerAssignment(void *context, CFsmEvent *event)
Definition: NetClient.cpp:768
u32 m_HostID
Unique-per-game identifier of this client, used to identify the sender of simulation commands...
Definition: NetClient.h:330
void SendAuthenticateMessage()
Definition: NetClient.cpp:628
Definition: NetClient.h:47
JS::Value CreateObject(const ScriptRequest &rq)
Create a plain object (i.e.
Definition: Object.h:214
void SetUserName(const CStrW &username)
Set the user&#39;s name that will be displayed to all players.
Definition: NetClient.cpp:174
CStrW m_UserName
Definition: NetClient.h:303
bool SetupConnection(ENetHost *enetClient)
Set up a connection to the remote networked server.
Definition: NetClient.cpp:199
static bool OnJoinSyncEndCommandBatch(void *context, CFsmEvent *event)
Definition: NetClient.cpp:842
void SetupServerData(CStr address, u16 port, bool stun)
Set connection data to the remote networked server.
Definition: NetClient.cpp:214
void SendRejoinedMessage()
Call when the client has rejoined a running match and finished the loading screen.
Definition: NetClient.cpp:524
static bool OnGameSetup(void *context, CFsmEvent *event)
Definition: NetClient.cpp:754
void SendGameSetupMessage(JS::MutableHandleValue attrs, const ScriptInterface &scriptInterface)
Definition: NetClient.cpp:482
void TraceMember(JSTracer *trc)
Definition: NetClient.cpp:168
Definition: NetClient.h:45
CStr m_GUID
Globally unique identifier to distinguish users beyond the lifetime of a single network session...
Definition: NetClient.h:339
void SendReadyMessage(const int status)
Definition: NetClient.cpp:504
void Poll()
Poll the connection for messages from the server and process them, and send any queued messages...
Definition: NetClient.cpp:353
std::string m_JoinSyncBuffer
Serialized game state received when joining an in-progress game.
Definition: NetClient.h:345
The base class for all network messages exchanged within the game.
Definition: NetMessage.h:32
CStr GetGUID() const
Returns the GUID of the local client.
Definition: NetClient.h:113
bool HandleMessage(CNetMessage *message)
Call when a message has been received from the network.
Definition: NetClient.cpp:545
static bool OnClientsLoading(void *context, CFsmEvent *event)
Definition: NetClient.cpp:930
static bool OnJoinSyncStart(void *context, CFsmEvent *event)
Definition: NetClient.cpp:826
std::deque< JS::Heap< JS::Value > > m_GuiMessageQueue
Queue of messages for GuiPoll.
Definition: NetClient.h:342
Async task for receiving the initial game state when rejoining an in-progress network game...
Definition: NetClient.cpp:59
Network client.
Definition: NetClient.h:59
void SendChatMessage(const std::wstring &text)
Definition: NetClient.cpp:497
static bool OnKicked(void *context, CFsmEvent *event)
Definition: NetClient.cpp:872
Implementation of CTurnManager for network clients.
Definition: NetClientTurnManager.h:29
static bool OnGameStart(void *context, CFsmEvent *event)
Definition: NetClient.cpp:796
static void Trace(JSTracer *trc, void *data)
We assume that adding a tracing function that&#39;s only called during GC is better for performance than ...
Definition: NetClient.h:80
bool TryToConnect(const CStr &hostJID, bool localNetwork)
Connect to the remote networked server using lobby.
Definition: NetClient.cpp:235
static bool OnClientPaused(void *context, CFsmEvent *event)
Definition: NetClient.cpp:948
Definition: NetClient.h:48
static bool OnClientPerformance(void *context, CFsmEvent *event)
Definition: NetClient.cpp:905
void SendClearAllReadyMessage()
Definition: NetClient.cpp:511
void SetHostJID(const CStr &jid)
Store the JID of the host.
Definition: NetClient.cpp:181
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:71
bool m_Rejoin
True if the player is currently rejoining or has already rejoined the game.
Definition: NetClient.h:333
void SendStartGameMessage(const CStr &initAttribs)
Definition: NetClient.cpp:517
CNetClient * g_NetClient
Global network client for the standard game.
Definition: NetClient.cpp:53
CStr m_Password
Password to join the game.
Definition: NetClient.h:313
bool ShouldShutdown() const
Definition: NetClient.h:49
Spidermonkey maintains some &#39;local&#39; state via the JSContext* object.
Definition: ScriptRequest.h:59
void SetControllerSecret(const std::string &secret)
Definition: NetClient.cpp:193
The client end of a network session.
Definition: NetSession.h:67
Definition: NetClient.h:44
bool error(JSContext *cx, uint argc, JS::Value *vp)
Definition: ScriptInterface.cpp:172
void CheckServerConnection()
Locally triggers a GUI message if the connection to the server is being lost or has bad latency...
Definition: NetClient.cpp:364
NONCOPYABLE(CNetClient)
static bool OnHandshakeResponse(void *context, CFsmEvent *event)
Definition: NetClient.cpp:665