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