1 /*
2 	This file is part of Warzone 2100.
3 	Copyright (C) 1999-2004  Eidos Interactive
4 	Copyright (C) 2005-2020  Warzone 2100 Project
5 
6 	Warzone 2100 is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at your option) any later version.
10 
11 	Warzone 2100 is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with Warzone 2100; if not, write to the Free Software
18 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 /*
21  * Netplay.h
22  *
23  * Alex Lee sep97.
24  */
25 
26 #ifndef _netplay_h
27 #define _netplay_h
28 
29 #include "lib/framework/crc.h"
30 #include "src/factionid.h"
31 #include "nettypes.h"
32 #include <physfs.h>
33 #include <vector>
34 #include <functional>
35 #include <memory>
36 // Lobby Connection errors
37 
38 enum LOBBY_ERROR_TYPES
39 {
40 	ERROR_NOERROR,
41 	ERROR_CONNECTION,
42 	ERROR_FULL,
43 	ERROR_INVALID,
44 	ERROR_KICKED,
45 	ERROR_WRONGVERSION,
46 	ERROR_WRONGPASSWORD,
47 	ERROR_HOSTDROPPED,
48 	ERROR_WRONGDATA,
49 	ERROR_UNKNOWNFILEISSUE
50 };
51 
52 enum CONNECTION_STATUS
53 {
54 	CONNECTIONSTATUS_PLAYER_DROPPED,
55 	CONNECTIONSTATUS_PLAYER_LEAVING,
56 	CONNECTIONSTATUS_DESYNC,
57 	CONNECTIONSTATUS_WAITING_FOR_PLAYER,
58 
59 	CONNECTIONSTATUS_NORMAL
60 };
61 
62 enum MESSAGE_TYPES
63 {
64 	// Net-related messages.
65 	NET_MIN_TYPE = 33,              ///< Minimum-1 valid NET_ type, *MUST* be first.
66 	NET_PING,                       ///< ping players.
67 	NET_PLAYER_STATS,               ///< player stats
68 	NET_TEXTMSG,                    ///< A simple text message between machines.
69 	NET_PLAYERRESPONDING,           ///< computer that sent this is now playing warzone!
70 	NET_OPTIONS,                    ///< welcome a player to a game.
71 	NET_KICK,                       ///< kick a player .
72 	NET_FIREUP,                     ///< campaign game has started, we can go too.. Shortcut message, not to be used in dmatch.
73 	NET_COLOURREQUEST,              ///< player requests a colour change.
74 	NET_FACTIONREQUEST,             ///< player requests a colour change.
75 	NET_AITEXTMSG,                  ///< chat between AIs
76 	NET_BEACONMSG,                  ///< place beacon
77 	NET_TEAMREQUEST,                ///< request team membership
78 	NET_JOIN,                       ///< join a game
79 	NET_ACCEPTED,                   ///< accepted into game
80 	NET_PLAYER_INFO,                ///< basic player info
81 	NET_PLAYER_JOINED,              ///< notice about player joining
82 	NET_PLAYER_LEAVING,             ///< A player is leaving, (nicely)
83 	NET_PLAYER_DROPPED,             ///< notice about player dropped / disconnected
84 	NET_GAME_FLAGS,                 ///< game flags
85 	NET_READY_REQUEST,              ///< player ready to start an mp game
86 	NET_REJECTED,                   ///< nope, you can't join
87 	NET_POSITIONREQUEST,            ///< position in GUI player list
88 	NET_DATA_CHECK,                 ///< Data integrity check
89 	NET_HOST_DROPPED,               ///< Host has dropped
90 	NET_SEND_TO_PLAYER,             ///< Non-host clients aren't directly connected to each other, so they talk via the host using these messages.
91 	NET_SHARE_GAME_QUEUE,           ///< Message contains a game message, which should be inserted into a queue.
92 	NET_FILE_REQUESTED,             ///< Player has requested a file (map/mod/?)
93 	NET_FILE_CANCELLED,             ///< Player cancelled a file request
94 	NET_FILE_PAYLOAD,               ///< sending file to the player that needs it
95 	NET_DEBUG_SYNC,                 ///< Synch error messages, so people don't have to use pastebin.
96 	NET_VOTE,                       ///< player vote
97 	NET_VOTE_REQUEST,               ///< Setup a vote popup
98 	NET_MAX_TYPE,                   ///< Maximum+1 valid NET_ type, *MUST* be last.
99 
100 	// Game-state-related messages, must be processed by all clients at the same game time.
101 	GAME_MIN_TYPE = 111,            ///< Minimum-1 valid GAME_ type, *MUST* be first.
102 	GAME_DROIDINFO,                 ///< update a droid order.
103 	GAME_STRUCTUREINFO,             ///< Structure state.
104 	GAME_RESEARCHSTATUS,            ///< research state.
105 	GAME_TEMPLATE,                  ///< a new template
106 	GAME_TEMPLATEDEST,              ///< remove template
107 	GAME_ALLIANCE,                  ///< alliance data.
108 	GAME_GIFT,                      ///< a luvly gift between players.
109 	GAME_LASSAT,                    ///< lassat firing.
110 	GAME_GAME_TIME,                 ///< Game time. Used for synchronising, so that all messages are executed at the same gameTime on all clients.
111 	GAME_PLAYER_LEFT,               ///< Player has left or dropped.
112 	GAME_DROIDDISEMBARK,            ///< droid disembarked from a Transporter
113 	GAME_SYNC_REQUEST,		///< Game event generated from scripts that is meant to be synced
114 	// The following messages are used for debug mode.
115 	GAME_DEBUG_MODE,                ///< Request enable/disable debug mode.
116 	GAME_DEBUG_ADD_DROID,           ///< Add droid.
117 	GAME_DEBUG_ADD_STRUCTURE,       ///< Add structure.
118 	GAME_DEBUG_ADD_FEATURE,         ///< Add feature.
119 	GAME_DEBUG_REMOVE_DROID,        ///< Remove droid.
120 	GAME_DEBUG_REMOVE_STRUCTURE,    ///< Remove structure.
121 	GAME_DEBUG_REMOVE_FEATURE,      ///< Remove feature.
122 	GAME_DEBUG_FINISH_RESEARCH,     ///< Research has been completed.
123 	// End of debug messages.
124 	GAME_MAX_TYPE                   ///< Maximum+1 valid GAME_ type, *MUST* be last.
125 };
126 
127 #define SYNC_FLAG 0x10000000	//special flag used for logging. (Not sure what this is. Was added in trunk, NUM_GAME_PACKETS not in newnet.)
128 
129 #define WZ_SERVER_DISCONNECT 0
130 #define WZ_SERVER_CONNECT    1
131 #define WZ_SERVER_UPDATE     3
132 
133 // Constants
134 // @NOTE / FIXME: We need a way to detect what should happen if the msg buffer exceeds this.
135 #define MaxMsgSize		16384		// max size of a message in bytes.
136 #define	StringSize		64			// size of strings used.
137 #define MaxGames		11			// max number of concurrently playable games to allow.
138 #define extra_string_size	157		// extra 199 char for future use
139 #define map_string_size		40
140 #define	hostname_string_size	40
141 #define modlist_string_size	255		// For a concatenated list of mods
142 #define password_string_size 64		// longer passwords slow down the join code
143 
144 #define MAX_CONNECTED_PLAYERS   MAX_PLAYERS
145 #define MAX_TMP_SOCKETS         16
146 
147 #define MAX_NET_TRANSFERRABLE_FILE_SIZE	0x8000000
148 
149 struct SESSIONDESC  //Available game storage... JUST FOR REFERENCE!
150 {
151 	int32_t dwSize;
152 	int32_t dwFlags;
153 	char host[40];	// host's ip address (can fit a full IPv4 and IPv6 address + terminating NUL)
154 	int32_t dwMaxPlayers;
155 	int32_t dwCurrentPlayers;
156 	int32_t dwUserFlags[4];
157 };
158 
159 /**
160  * @note when changing this structure, NETsendGAMESTRUCT, NETrecvGAMESTRUCT and
161  *       the lobby server should be changed accordingly.
162  */
163 struct GAMESTRUCT
164 {
165 	/* Version of this structure and thus the binary lobby protocol.
166 	 * @NOTE: <em>MUST</em> be the first item of this struct.
167 	 */
168 	uint32_t	GAMESTRUCT_VERSION;
169 
170 	char		name[StringSize];
171 	SESSIONDESC	desc;
172 	// END of old GAMESTRUCT format
173 	// NOTE: do NOT save the following items in game.c--it will break savegames.
174 	char		secondaryHosts[2][40];
175 	char		extra[extra_string_size];		// extra string (future use)
176 	uint16_t	hostPort;						// server port
177 	char		mapname[map_string_size];		// map server is hosting
178 	char		hostname[hostname_string_size];	// ...
179 	char		versionstring[StringSize];		//
180 	char		modlist[modlist_string_size];	// ???
181 	uint32_t	game_version_major;				//
182 	uint32_t	game_version_minor;				//
183 	uint32_t	privateGame;					// if true, it is a private game
184 	uint32_t	pureMap;						// If this map has mods in it.
185 	uint32_t	Mods;							// number of concatenated mods?
186 	// Game ID, used on the lobby server to link games with multiple address families to eachother
187 	uint32_t	gameId;
188 	uint32_t	limits;							// holds limits bitmask (NO_VTOL|NO_TANKS|NO_BORGS)
189 	uint32_t	future3;						// for future use
190 	uint32_t	future4;						// for future use
191 };
192 
193 // ////////////////////////////////////////////////////////////////////////
194 // Message information. ie. the packets sent between machines.
195 
196 #define NET_ALL_PLAYERS 255
197 #define NET_HOST_ONLY 0
198 // the following structure is going to be used to track if we sync or not
199 struct SYNC_COUNTER
200 {
201 	uint16_t	kicks;
202 	uint16_t	joins;
203 	uint16_t	left;
204 	uint16_t	drops;
205 	uint16_t	cantjoin;
206 	uint16_t	banned;
207 	uint16_t	rejected;
208 };
209 
210 struct WZFile
211 {
212 	//WZFile() : handle(nullptr), size(0), pos(0) { hash.setZero(); }
handleWZFile213 	WZFile(PHYSFS_file *handle, const std::string &filename, Sha256 hash, uint32_t size = 0) : handle(handle), filename(filename), hash(hash), size(size), pos(0) {}
214 
215 	PHYSFS_file *handle;
216 	std::string filename;
217 	Sha256 hash;
218 	uint32_t size;
219 	uint32_t pos;  // Current position, the range [0; currPos[ has been sent or received already.
220 };
221 
222 enum class AIDifficulty : int8_t
223 {
224 	EASY,
225 	MEDIUM,
226 	HARD,
227 	INSANE,
228 	DEFAULT = MEDIUM,
229 	DISABLED = -1,
230 	HUMAN = -2,
231 };
232 
233 enum class NET_LOBBY_OPT_FIELD
234 {
235 	INVALID,
236 	GNAME,
237 	MAPNAME,
238 	HOSTNAME,
239 	MAX
240 };
241 
242 // ////////////////////////////////////////////////////////////////////////
243 // Player information. Filled when players join, never re-ordered. selectedPlayer global points to
244 // currently controlled player.
245 struct PLAYER
246 {
247 	char                name[StringSize];   ///< Player name
248 	int32_t             position;           ///< Map starting position
249 	int32_t             colour;             ///< Which colour slot this player is using
250 	bool                allocated;          ///< Allocated as a human player
251 	uint32_t            heartattacktime;    ///< Time cardiac arrest started
252 	bool                heartbeat;          ///< If we are still alive or not
253 	bool                kick;               ///< If we should kick them
254 	int32_t             connection;         ///< Index into connection list
255 	int32_t             team;               ///< Which team we are on
256 	bool                ready;              ///< player ready to start?
257 	int8_t              ai;                 ///< index into sorted list of AIs, zero is always default AI
258 	AIDifficulty        difficulty;         ///< difficulty level of AI
259 	bool                autoGame;           ///< if we are running a autogame (AI controls us)
260 	std::vector<WZFile> wzFiles;            ///< for each player, we keep track of map/mod download progress
261 	char                IPtextAddress[40];  ///< IP of this player
262 	FactionID			faction;			///< which faction the player has
263 
resetAllPLAYER264 	void resetAll()
265 	{
266 		name[0] = '\0';
267 		position = -1;
268 		colour = 0;
269 		allocated = false;
270 		heartattacktime = 0;
271 		heartbeat = false;
272 		kick = false;
273 		connection = -1;
274 		team = -1;
275 		ready = false;
276 		ai = 0;
277 		difficulty = AIDifficulty::DISABLED;
278 		autoGame = false;
279 		IPtextAddress[0] = '\0';
280 		faction = FACTION_NORMAL;
281 	}
282 };
283 
284 struct PlayerReference;
285 
286 // ////////////////////////////////////////////////////////////////////////
287 // all the luvly Netplay info....
288 struct NETPLAY
289 {
290 	std::vector<PLAYER>	players;	///< The array of players.
291 	uint32_t	playercount;		///< Number of players in game.
292 	uint32_t	hostPlayer;		///< Index of host in player array
293 	uint32_t	bComms;			///< Actually do the comms?
294 	bool		isHost;			///< True if we are hosting the game
295 	bool		isUPNP;				// if we want the UPnP detection routines to run
296 	bool		isUPNP_CONFIGURED;	// if UPnP was successful
297 	bool		isUPNP_ERROR;		//If we had a error during detection/config process
298 	bool		isHostAlive;	/// if the host is still alive
299 	std::vector<WZFile> wzFiles;      ///< Only non-empty during map/mod download.
300 	char gamePassword[password_string_size];		//
301 	bool GamePassworded;				// if we have a password or not.
302 	bool ShowedMOTD;					// only want to show this once
303 	bool HaveUpgrade;					// game updates available
304 	char MOTDbuffer[255];				// buffer for MOTD
305 	char *MOTD = nullptr;
306 
307 	std::vector<std::shared_ptr<PlayerReference>> playerReferences;
308 
309 	NETPLAY();
310 };
311 
312 struct PLAYER_IP
313 {
314 	char	pname[40];
315 	char	IPAddress[40];
316 };
317 #define MAX_BANS 255
318 // ////////////////////////////////////////////////////////////////////////
319 // variables
320 
321 extern NETPLAY NetPlay;
322 extern SYNC_COUNTER sync_counter;
323 extern PLAYER_IP	*IPlist;
324 // update flags
325 extern bool netPlayersUpdated;
326 extern char iptoconnect[PATH_MAX]; // holds IP/hostname from command line
327 extern bool netGameserverPortOverride; // = false; (for cli override)
328 
329 #define ASSERT_HOST_ONLY(failAction) \
330 	if (!NetPlay.isHost) \
331 	{ \
332 		ASSERT(false, "Host only routine detected for client!"); \
333 		failAction; \
334 	}
335 
336 
337 // ////////////////////////////////////////////////////////////////////////
338 // functions available to you.
339 int NETinit(bool bFirstCall);
340 WZ_DECL_NONNULL(2) bool NETsend(NETQUEUE queue, NetMessage const *message);   ///< send to player, or broadcast if player == NET_ALL_PLAYERS.
341 WZ_DECL_NONNULL(1, 2) bool NETrecvNet(NETQUEUE *queue, uint8_t *type);        ///< recv a message from the net queues if possible.
342 WZ_DECL_NONNULL(1, 2) bool NETrecvGame(NETQUEUE *queue, uint8_t *type);       ///< recv a message from the game queues which is sceduled to execute by time, if possible.
343 void NETflush();                                                              ///< Flushes any data stuck in compression buffers.
344 
345 int NETsendFile(WZFile &file, unsigned player);  ///< Send file chunk. Returns 100 when done.
346 int NETrecvFile(NETQUEUE queue);                 ///< Receive file chunk. Returns 100 when done.
347 unsigned NETgetDownloadProgress(unsigned player);     ///< Returns 100 when done.
348 
349 int NETclose();					// close current game
350 int NETshutdown();					// leave the game in play.
351 
352 void NETaddRedirects();
353 void NETremRedirects();
354 void NETdiscoverUPnPDevices();
355 
356 enum NetStatisticType {NetStatisticRawBytes, NetStatisticUncompressedBytes, NetStatisticPackets};
357 size_t NETgetStatistic(NetStatisticType type, bool sent, bool isTotal = false);     // Return some statistic. Call regularly for good results.
358 
359 void NETplayerKicked(UDWORD index);			// Cleanup after player has been kicked
360 
361 // from netjoin.c
362 SDWORD NETgetGameFlags(UDWORD flag);			// return one of the four flags(dword) about the game.
363 int32_t NETgetGameFlagsUnjoined(const GAMESTRUCT& game, unsigned int flag);	// return one of the four flags(dword) about the game.
364 bool NETsetGameFlags(UDWORD flag, SDWORD value);	// set game flag(1-4) to value.
365 bool NEThaltJoining();				// stop new players joining this game
366 bool NETenumerateGames(const std::function<bool (const GAMESTRUCT& game)>& handleEnumerateGameFunc);
367 bool NETfindGames(std::vector<GAMESTRUCT>& results, size_t startingIndex, size_t resultsLimit, bool onlyMatchingLocalVersion = false);
368 bool NETfindGame(uint32_t gameId, GAMESTRUCT& output);
369 bool NETjoinGame(const char *host, uint32_t port, const char *playername); // join game given with playername
370 bool NEThostGame(const char *SessionName, const char *PlayerName,// host a game
371                  SDWORD one, SDWORD two, SDWORD three, SDWORD four, UDWORD plyrs);
372 bool NETchangePlayerName(UDWORD player, char *newName);// change a players name.
373 void NETfixDuplicatePlayerNames();  // Change a player's name automatically, if there are duplicates.
374 
375 #include "netlog.h"
376 
377 void NETsetMasterserverName(const char *hostname);
378 const char *NETgetMasterserverName();
379 void NETsetMasterserverPort(unsigned int port);
380 unsigned int NETgetMasterserverPort();
381 void NETsetGameserverPort(unsigned int port);
382 unsigned int NETgetGameserverPort();
383 void NETsetJoinPreferenceIPv6(bool bTryIPv6First);
384 bool NETgetJoinPreferenceIPv6();
385 
386 bool NETsetupTCPIP(const char *machine);
387 void NETsetGamePassword(const char *password);
388 void NETBroadcastPlayerInfo(uint32_t index);
389 void NETBroadcastTwoPlayerInfo(uint32_t index1, uint32_t index2);
390 bool NETisCorrectVersion(uint32_t game_version_major, uint32_t game_version_minor);
391 int NETGetMajorVersion();
392 int NETGetMinorVersion();
393 void NET_InitPlayer(int i, bool initPosition, bool initTeams = false);
394 void NET_InitPlayers(bool initTeams = false);
395 
396 uint8_t NET_numHumanPlayers(void);
397 void NETsetLobbyOptField(const char *Value, const NET_LOBBY_OPT_FIELD Field);
398 std::vector<uint8_t> NET_getHumanPlayers(void);
399 
400 bool NETGameIsLocked();
401 void NETGameLocked(bool flag);
402 void NETresetGamePassword();
403 bool NETregisterServer(int state);
404 bool NETprocessQueuedServerUpdates();
405 void NETsetPlayerConnectionStatus(CONNECTION_STATUS status, unsigned player);    ///< Cumulative, except that CONNECTIONSTATUS_NORMAL resets.
406 bool NETcheckPlayerConnectionStatus(CONNECTION_STATUS status, unsigned player);  ///< True iff connection status icon hasn't expired for this player. CONNECTIONSTATUS_NORMAL means any status, NET_ALL_PLAYERS means all players.
407 
408 const char *messageTypeToString(unsigned messageType);
409 
410 /// Sync debugging. Only prints anything, if different players would print different things.
411 #define syncDebug(...) do { _syncDebug(__FUNCTION__, __VA_ARGS__); } while(0)
412 #ifdef WZ_CC_MINGW
413 void _syncDebug(const char *function, const char *str, ...) WZ_DECL_FORMAT(__MINGW_PRINTF_FORMAT, 2, 3);
414 #else
415 void _syncDebug(const char *function, const char *str, ...) WZ_DECL_FORMAT(printf, 2, 3);
416 #endif
417 
418 /// Faster than syncDebug. Make sure that str is a format string that takes ints only.
419 void _syncDebugIntList(const char *function, const char *str, int *ints, size_t numInts);
420 #define syncDebugBacktrace() do { _syncDebugBacktrace(__FUNCTION__); } while(0)
421 void _syncDebugBacktrace(const char *function);                  ///< Adds a backtrace to syncDebug, if the platform supports it. Can be a bit slow, don't call way too often, unless desperate.
422 uint32_t syncDebugGetCrc();                                      ///< syncDebug() calls between uint32_t crc = syncDebugGetCrc(); and syncDebugSetCrc(crc); appear in synch debug logs, but without triggering a desynch if different.
423 void syncDebugSetCrc(uint32_t crc);                              ///< syncDebug() calls between uint32_t crc = syncDebugGetCrc(); and syncDebugSetCrc(crc); appear in synch debug logs, but without triggering a desynch if different.
424 
425 typedef uint16_t GameCrcType;  // Truncate CRC of game state to 16 bits, to save a bit of bandwidth.
426 void resetSyncDebug();                                              ///< Resets the syncDebug, so syncDebug from a previous game doesn't cause a spurious desynch dump.
427 GameCrcType nextDebugSync();                                        ///< Returns a CRC corresponding to all syncDebug() calls since the last nextDebugSync() or resetSyncDebug() call.
428 bool checkDebugSync(uint32_t checkGameTime, GameCrcType checkCrc);  ///< Dumps all syncDebug() calls from that gameTime, if the CRC doesn't match.
429 
430 /**
431  * This structure provides read-only access to a player, and can be used to identify players uniquely.
432  *
433  * It holds the player data after the player has disconnected, and it is released automatically by reference counting.
434  **/
435 struct PlayerReference
436 {
PlayerReferencePlayerReference437 	PlayerReference(uint32_t index): index(index)
438 	{
439 	}
440 
disconnectPlayerReference441 	void disconnect()
442 	{
443 		detached = std::unique_ptr<PLAYER>(new PLAYER(NetPlay.players[index]));
444 	}
445 
446 	PLAYER const *operator ->() const
447 	{
448 		return detached? detached.get(): &NetPlay.players[index];
449 	}
450 
451 private:
452 	std::unique_ptr<PLAYER> detached = nullptr;
453 	uint32_t index;
454 };
455 
456 #endif
457