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/>.
21 #include "network/fsm.h"
22 #include "network/NetFileTransfer.h"
23 #include "network/NetHost.h"
24 #include "scriptinterface/ScriptVal.h"
31 class CNetClientSession
;
32 class CNetClientTurnManager
;
34 class ScriptInterface
;
36 typedef struct _ENetHost ENetHost
;
38 // NetClient session FSM states
45 NCS_INITIAL_GAMESETUP
,
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
, bool isLocalClient
);
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 * Returns the GUID of the local client.
95 * Used for distinguishing observers.
97 CStr
GetGUID() const { return m_GUID
; }
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).
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.
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.
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
);
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();
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
264 /// True if the player is currently rejoining or has already rejoined the game.
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
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