1 /* Copyright (C) 2022 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 "network/FSM.h"
22 #include "network/NetFileTransfer.h"
23 #include "network/NetHost.h"
24 #include "scriptinterface/Object.h"
33 class CNetClientSession
;
34 class CNetClientTurnManager
;
35 class ScriptInterface
;
37 typedef struct _ENetHost ENetHost
;
39 // NetClient session FSM states
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
;
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
);
72 virtual ~CNetClient();
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
80 static void Trace(JSTracer
*trc
, void *data
)
82 reinterpret_cast<CNetClient
*>(data
)->TraceMember(trc
);
85 void TraceMember(JSTracer
*trc
);
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
);
94 * Store the JID of the host.
95 * This is needed for the secure lobby authentication.
97 void SetHostJID(const CStr
& jid
);
99 void SetControllerSecret(const std::string
& secret
);
101 bool IsController() const { return m_IsController
; }
104 * Set the game password.
105 * Must be called after SetUserName, as that is used to hash further.
107 void SetGamePassword(const CStr
& hashedPassword
);
110 * Returns the GUID of the local client.
111 * Used for distinguishing observers.
113 CStr
GetGUID() const { return m_GUID
; }
116 * Set connection data to the remote networked server.
117 * @param address IP address or host name to connect to
119 void SetupServerData(CStr address
, u16 port
, bool stun
);
122 * Set up a connection to the remote networked server.
123 * Must call SetupServerData first.
124 * @return true on success, false on connection failure
126 bool SetupConnection(ENetHost
* enetClient
);
129 * Request connection information over the lobby.
131 void SetupConnectionViaLobby();
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
139 bool TryToConnect(const CStr
& hostJID
, bool localNetwork
);
142 * Destroy the connection to the server.
143 * This client probably cannot be used again.
145 void DestroyConnection();
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).
155 * Locally triggers a GUI message if the connection to the server is being lost or has bad latency.
157 void CheckServerConnection();
160 * Retrieves the next queued GUI message, and removes it from the queue.
161 * The returned value is in the GetScriptInterface() JS context.
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.
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.
171 * @return next message, or the value 'undefined' if the queue is empty
173 void GuiPoll(JS::MutableHandleValue
);
176 * Add a message to the queue, to be read by GuiPoll.
177 * The script value must be in the GetScriptInterface() JS context.
179 template<typename
... Args
>
180 void PushGuiMessage(Args
const&... args
)
182 ScriptRequest
rq(GetScriptInterface());
184 JS::RootedValue
message(rq
.cx
);
185 Script::CreateObject(rq
, &message
, args
...);
186 m_GuiMessageQueue
.push_back(JS::Heap
<JS::Value
>(message
));
190 * Return a concatenation of all messages in the GUI queue,
191 * for test cases to easily verify the queue contents.
193 std::string
TestReadGuiMessages();
196 * Get the script interface associated with this network client,
197 * which is equivalent to the one used by the CGame in the constructor.
199 const ScriptInterface
& GetScriptInterface();
202 * Send a message to the server.
203 * @param message message to send
204 * @return true on success
206 bool SendMessage(const CNetMessage
* message
);
209 * Call when the network connection has been successfully initiated.
211 void HandleConnect();
214 * Call when the network connection has been lost.
216 void HandleDisconnect(u32 reason
);
219 * Call when a message has been received from the network.
221 bool HandleMessage(CNetMessage
* message
);
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.
229 void SendGameSetupMessage(JS::MutableHandleValue attrs
, const ScriptInterface
& scriptInterface
);
231 void SendAssignPlayerMessage(const int playerID
, const CStr
& guid
);
233 void SendChatMessage(const std::wstring
& text
);
235 void SendReadyMessage(const int status
);
237 void SendClearAllReadyMessage();
239 void SendStartGameMessage(const CStr
& initAttribs
);
242 * Call when the client has rejoined a running match and finished
243 * the loading screen.
245 void SendRejoinedMessage();
248 * Call to kick/ban a client
250 void SendKickPlayerMessage(const CStrW
& playerName
, bool ban
);
253 * Call when the client has paused or unpaused the game.
255 void SendPausedMessage(bool pause
);
258 * @return Whether the NetClient is shutting down.
260 bool ShouldShutdown() const;
263 * Called when fetching connection data from the host failed, to inform JS code.
265 void HandleGetServerDataFailed(const CStr
& error
);
268 void SendAuthenticateMessage();
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
);
293 * Take ownership of a session object, and use it for all network communication.
295 void SetAndOwnSession(CNetClientSession
* session
);
298 * Push a message onto the GUI queue listing the current player assignments.
300 void PostPlayerAssignmentsToScript();
306 CStr m_ServerAddress
;
311 * Password to join the game.
315 /// The 'secret' used to identify the controller of the game.
316 std::string m_ControllerSecret
;
318 /// Note that this is just a "gui hint" with no actual impact on being controller.
319 bool m_IsController
= false;
321 /// Current network session (or NULL if not connected)
322 CNetClientSession
* m_Session
;
324 std::thread m_PollingThread
;
326 /// Turn manager associated with the current game (or NULL if we haven't started the game yet)
327 CNetClientTurnManager
* m_ClientTurnManager
;
329 /// Unique-per-game identifier of this client, used to identify the sender of simulation commands
332 /// True if the player is currently rejoining or has already rejoined the game.
335 /// Latest copy of player assignments heard from the server
336 PlayerAssignmentMap m_PlayerAssignments
;
338 /// Globally unique identifier to distinguish users beyond the lifetime of a single network session
341 /// Queue of messages for GuiPoll
342 std::deque
<JS::Heap
<JS::Value
>> m_GuiMessageQueue
;
344 /// Serialized game state received when joining an in-progress game
345 std::string m_JoinSyncBuffer
;
347 /// Time when the server was last checked for timeouts and bad latency
348 std::time_t m_LastConnectionCheck
;
351 /// Global network client for the standard game
352 extern CNetClient
*g_NetClient
;
354 #endif // NETCLIENT_H