sys_lobby.h 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code 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 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "sys_lobby_backend.h"
  21. #define INVALID_LOBBY_USER_NAME " " // Used to be "INVALID" but Sony might not like that.
  22. class idSessionCallbacks;
  23. class idDebugGraph;
  24. /*
  25. ========================
  26. idLobby
  27. ========================
  28. */
  29. class idLobby : public idLobbyBase {
  30. public:
  31. idLobby();
  32. enum lobbyType_t {
  33. TYPE_PARTY = 0,
  34. TYPE_GAME = 1,
  35. TYPE_GAME_STATE = 2,
  36. TYPE_INVALID = 0xff
  37. };
  38. enum lobbyState_t {
  39. STATE_IDLE,
  40. STATE_CREATE_LOBBY_BACKEND,
  41. STATE_SEARCHING,
  42. STATE_OBTAINING_ADDRESS,
  43. STATE_CONNECT_HELLO_WAIT,
  44. STATE_FINALIZE_CONNECT,
  45. STATE_FAILED,
  46. NUM_STATES
  47. };
  48. enum failedReason_t {
  49. FAILED_UNKNOWN,
  50. FAILED_CONNECT_FAILED,
  51. FAILED_MIGRATION_CONNECT_FAILED,
  52. };
  53. void Initialize( lobbyType_t sessionType_, class idSessionCallbacks * callbacks );
  54. void StartHosting( const idMatchParameters & parms );
  55. void StartFinding( const idMatchParameters & parms_ );
  56. void Pump();
  57. void ProcessSnapAckQueue();
  58. void Shutdown( bool retainMigrationInfo = false, bool skipGoodbye = false ); // Goto idle state
  59. void HandlePacket( lobbyAddress_t & remoteAddress, idBitMsg fragMsg, idPacketProcessor::sessionId_t sessionID );
  60. lobbyState_t GetState() { return state; }
  61. virtual bool HasActivePeers() const;
  62. virtual bool IsLobbyFull() const { return NumFreeSlots() == 0; }
  63. int NumFreeSlots() const;
  64. public:
  65. enum reliablePlayerToPlayer_t {
  66. //RELIABLE_PLAYER_TO_PLAYER_VOICE_EVENT,
  67. RELIABLE_PLAYER_TO_PLAYER_GAME_DATA,
  68. // Game messages would be reserved here in the same way that RELIABLE_GAME_DATA is.
  69. // I'm worried about using up the 0xff values we have for reliable type, so I'm not
  70. // going to reserve anything here just yet.
  71. NUM_RELIABLE_PLAYER_TO_PLAYER,
  72. };
  73. enum reliableType_t {
  74. RELIABLE_HELLO, // host to peer : connection established
  75. RELIABLE_USER_CONNECTED, // host to peer : a new session user connected
  76. RELIABLE_USER_DISCONNECTED, // host to peer : a session user disconnected
  77. RELIABLE_START_LOADING, // host to peer : peer should begin loading the map
  78. RELIABLE_LOADING_DONE, // peer to host : finished loading map
  79. RELIABLE_IN_GAME, // peer to host : first full snap received, in game now
  80. RELIABLE_SNAPSHOT_ACK, // peer to host : got a snapshot
  81. RELIABLE_RESOURCE_ACK, // peer to host : got some new resources
  82. RELIABLE_CONNECT_AND_MOVE_TO_LOBBY, // host to peer : connect to this server
  83. RELIABLE_PARTY_CONNECT_OK, // host to peer
  84. RELIABLE_PARTY_LEAVE_GAME_LOBBY, // host to peer : leave game lobby
  85. RELIABLE_MATCH_PARMS, // host to peer : update in match parms
  86. RELIABLE_UPDATE_MATCH_PARMS, // peer to host : peer updating match parms
  87. // User join in progress msg's (join in progress for the party/game lobby, not inside a match)
  88. RELIABLE_USER_CONNECT_REQUEST, // peer to host: local user wants to join session in progress
  89. RELIABLE_USER_CONNECT_DENIED, // host to peer: user join session in progress denied (not enough slots)
  90. // User leave in progress msg's (leave in progress for the party/game lobby, not inside a match)
  91. RELIABLE_USER_DISCONNECT_REQUEST, // peer to host: request host to remove user from session
  92. RELIABLE_KICK_PLAYER, // host to peer : kick a player
  93. RELIABLE_MATCHFINISHED, // host to peer - Match is in post looking at score board
  94. RELIABLE_ENDMATCH, // host to peer - End match, and go to game lobby
  95. RELIABLE_ENDMATCH_PREMATURE, // host to peer - End match prematurely, and go to game lobby (onl possible in unrated/custom games)
  96. RELIABLE_SESSION_USER_MODIFIED, // peer to host : user changed something (emblem, name, etc)
  97. RELIABLE_UPDATE_SESSION_USER, // host to peers : inform all peers of the change
  98. RELIABLE_HEADSET_STATE, // * to * : headset state change for user
  99. RELIABLE_VOICE_STATE, // * to * : voice state changed for user pair (mute, unmute, etc)
  100. RELIABLE_PING, // * to * : send host->peer, then reflected
  101. RELIABLE_PING_VALUES, // host to peers : ping data from lobbyUser_t for everyone
  102. RELIABLE_BANDWIDTH_VALUES, // peer to host: data back about bandwidth test
  103. RELIABLE_ARBITRATE, // host to peer : start arbitration
  104. RELIABLE_ARBITRATE_OK, // peer to host : ack arbitration request
  105. RELIABLE_POST_STATS, // host to peer : here, write these stats now (hacky)
  106. RELIABLE_MIGRATION_GAME_DATA, // host to peers: game data to use incase of a migration
  107. RELIABLE_START_MATCH_GAME_LOBBY_HOST, // game lobby host to game state lobby host: start the match, since all players are in
  108. RELIABLE_DUMMY_MSG, // used as a placeholder for old removed msg's
  109. RELIABLE_PLAYER_TO_PLAYER_BEGIN,
  110. // use reliablePlayerToPlayer_t
  111. RELIABLE_PLAYER_TO_PLAYER_END = RELIABLE_PLAYER_TO_PLAYER_BEGIN + NUM_RELIABLE_PLAYER_TO_PLAYER,
  112. // * to * : misc reliable game data above this
  113. RELIABLE_GAME_DATA = RELIABLE_PLAYER_TO_PLAYER_END
  114. };
  115. // JGM: Reliable type in packet is a byte and there are a lot of reliable game messages.
  116. // Feel free to bump this up since it's arbitrary anyway, but take a look at gameReliable_t.
  117. // At the moment, both Doom and Rage have around 32 gameReliable_t values.
  118. compile_time_assert( RELIABLE_GAME_DATA < 64 );
  119. static const char * stateToString[ NUM_STATES ];
  120. // Consts
  121. static const int PEER_HEARTBEAT_IN_SECONDS = 5; // Make sure something was sent every 5 seconds, so we don't time out
  122. static const int CONNECT_REQUEST_FREQUENCY_IN_SECONDS = 5; // Frequency at which we resend a request to connect to a server (will increase in frequency over time down to MIN_CONNECT_FREQUENCY_IN_SECONDS)
  123. static const int MIN_CONNECT_FREQUENCY_IN_SECONDS = 1; // Min frequency of connection attempts
  124. static const int MAX_CONNECT_ATTEMPTS = 5;
  125. static const int BANDWIDTH_REPORTING_MAX = 10240; // make bps to report receiving (clamp if higher). For quantizing
  126. static const int BANDWIDTH_REPORTING_BITS = 16; // number of bits to use for bandwidth reporting
  127. static const int MAX_BPS_HISTORY = 32; // size of outgoing bps history to maintain for each client
  128. static const int MAX_SNAP_SIZE = idPacketProcessor::MAX_MSG_SIZE;
  129. static const int MAX_SNAPSHOT_QUEUE = 64;
  130. static const int OOB_HELLO = 0;
  131. static const int OOB_GOODBYE = 1;
  132. static const int OOB_GOODBYE_W_PARTY = 2;
  133. static const int OOB_GOODBYE_FULL = 3;
  134. static const int OOB_RESOURCE_LIST = 4;
  135. static const int OOB_VOICE_AUDIO = 5;
  136. static const int OOB_MATCH_QUERY = 6;
  137. static const int OOB_MATCH_QUERY_ACK = 7;
  138. static const int OOB_SYSTEMLINK_QUERY = 8;
  139. static const int OOB_MIGRATE_INVITE = 9;
  140. static const int OOB_BANDWIDTH_TEST = 10;
  141. enum connectionState_t {
  142. CONNECTION_FREE = 0, // Free peer slot
  143. CONNECTION_CONNECTING = 1, // Waiting for response from host for initial connection
  144. CONNECTION_ESTABLISHED = 2, // Connection is established and active
  145. };
  146. struct peer_t {
  147. peer_t() {
  148. loaded = false;
  149. inGame = false;
  150. networkChecksum = 0;
  151. lastSnapTime = 0;
  152. snapHz = 0.0f;
  153. numResources = 0;
  154. lastHeartBeat = 0;
  155. connectionState = CONNECTION_FREE;
  156. packetProc = NULL;
  157. snapProc = NULL;
  158. nextPing = 0; // do it asap
  159. lastPingRtt = 0;
  160. sessionID = idPacketProcessor::SESSION_ID_INVALID;
  161. startResourceLoadTime = 0;
  162. nextThrottleCheck = 0;
  163. maxSnapQueueSize = 0;
  164. throttledSnapRate = 0;
  165. pauseSnapshots = false;
  166. receivedBps = -1.0f;
  167. maxSnapBps = -1.0f;
  168. receivedThrottle = 0;
  169. receivedThrottleTime = 0;
  170. throttleSnapsForXSeconds = 0;
  171. recoverPing = 0;
  172. failedPingRecoveries = 0;
  173. rightBeforeSnapsPing = 0;
  174. bandwidthTestLastSendTime = 0;
  175. bandwidthSequenceNum = 0;
  176. bandwidthTestBytes = 0;
  177. bandwidthChallengeStartSendTime = 0;
  178. bandwidthChallengeResults = false;
  179. bandwidthChallengeSendComplete = false;
  180. numSnapsSent = 0;
  181. ResetConnectState();
  182. };
  183. void ResetConnectState() {
  184. lastResourceTime = 0;
  185. lastSnapTime = 0;
  186. snapHz =
  187. lastProcTime = 0;
  188. lastInBandProcTime = 0;
  189. lastFragmentSendTime = 0;
  190. needToSubmitPendingSnap = false;
  191. lastSnapJobTime = true;
  192. startResourceLoadTime = 0;
  193. receivedBps = -1.0;
  194. maxSnapBps = -1.0f;
  195. receivedThrottle = 0;
  196. receivedThrottleTime = 0;
  197. throttleSnapsForXSeconds = 0;
  198. recoverPing = 0;
  199. failedPingRecoveries = 0;
  200. rightBeforeSnapsPing = 0;
  201. bandwidthTestLastSendTime = 0;
  202. bandwidthSequenceNum = 0;
  203. bandwidthTestBytes = 0;
  204. bandwidthChallengeStartSendTime = 0;
  205. bandwidthChallengeResults = false;
  206. bandwidthChallengeSendComplete = false;
  207. memset( sentBpsHistory, 0, sizeof( sentBpsHistory ) );
  208. receivedBpsIndex = 0;
  209. debugGraphs.Clear();
  210. }
  211. void ResetAllData() {
  212. ResetConnectState();
  213. ResetMatchData();
  214. }
  215. void ResetMatchData() {
  216. loaded = false;
  217. networkChecksum = 0;
  218. inGame = false;
  219. numResources = 0;
  220. needToSubmitPendingSnap = false;
  221. throttledSnapRate = 0;
  222. maxSnapQueueSize = 0;
  223. receivedBpsIndex = -1;
  224. numSnapsSent = 0;
  225. pauseSnapshots = false;
  226. // Reset the snapshot processor
  227. if ( snapProc != NULL ) {
  228. snapProc->Reset( false );
  229. }
  230. }
  231. void Print() {
  232. idLib::Printf(" lastResourceTime: %d\n", lastResourceTime );
  233. idLib::Printf(" lastSnapTime: %d\n", lastSnapTime );
  234. idLib::Printf(" lastProcTime: %d\n", lastProcTime );
  235. idLib::Printf(" lastInBandProcTime: %d\n", lastInBandProcTime );
  236. idLib::Printf(" lastFragmentSendTime: %d\n", lastFragmentSendTime );
  237. idLib::Printf(" needToSubmitPendingSnap: %d\n", needToSubmitPendingSnap );
  238. idLib::Printf(" lastSnapJobTime: %d\n", lastSnapJobTime );
  239. }
  240. bool IsActive() const { return connectionState != CONNECTION_FREE; }
  241. bool IsConnected() const { return connectionState == CONNECTION_ESTABLISHED; }
  242. connectionState_t GetConnectionState() const;
  243. connectionState_t connectionState;
  244. bool loaded; // true if this peer has finished loading the map
  245. bool inGame; // true if this peer received the first snapshot, and is in-game
  246. int lastSnapTime; // Last time a snapshot was sent on the network to this peer
  247. float snapHz;
  248. int lastProcTime; // Used to determine when a packet was processed for sending to this peer
  249. int lastInBandProcTime; // Last time a in-band packet was processed for sending
  250. int lastFragmentSendTime; // Last time a fragment was sent out (fragments are processed msg's, waiting to be fully sent)
  251. unsigned long networkChecksum; // Checksum used to determine if a peer loaded the network resources the EXACT same as the server did
  252. int pauseSnapshots;
  253. lobbyAddress_t address;
  254. int numResources; // number of network resources we know the peer has
  255. idPacketProcessor * packetProc; // Processes packets for this peer
  256. idSnapshotProcessor * snapProc; // Processes snapshots for this peer
  257. idStaticList< idDebugGraph *, 4 > debugGraphs;//
  258. int lastResourceTime; // Used to throttle the sending of resources
  259. int lastHeartBeat;
  260. int nextPing; // next Sys_Milliseconds when I'll send this peer a RELIABLE_PING
  261. int lastPingRtt;
  262. bool needToSubmitPendingSnap;
  263. int lastSnapJobTime; // Last time a snapshot was sent to the joblist for this peer
  264. int startResourceLoadTime; // Used to determine how long a peer has been loading resources
  265. int maxSnapQueueSize; // how big has the snap queue gotten?
  266. int throttledSnapRate; // effective snap rate for this peer
  267. int nextThrottleCheck;
  268. int numSnapsSent;
  269. float sentBpsHistory[ MAX_BPS_HISTORY ];
  270. int receivedBpsIndex;
  271. float receivedBps; // peer's reported bps (they tell us their effective downstream)
  272. float maxSnapBps;
  273. float receivedThrottle; // amount of accumlated time this client has been lagging behind
  274. int receivedThrottleTime; // last time we did received based throttle calculations
  275. int throttleSnapsForXSeconds;
  276. int recoverPing;
  277. int failedPingRecoveries;
  278. int rightBeforeSnapsPing;
  279. int bandwidthChallengeStartSendTime; // time we sent first packet of bw challenge to this peer
  280. int bandwidthTestLastSendTime; // last time in MS we sent them a bw challenge packet
  281. int bandwidthTestBytes; // used to measure number of bytes we sent them
  282. int bandwidthSequenceNum; // number of challenge sequences we sent them
  283. bool bandwidthChallengeResults; // we got results back
  284. bool bandwidthChallengeSendComplete; // we finished sending everything
  285. idPacketProcessor::sessionId_t sessionID;
  286. };
  287. const char * GetLobbyName() {
  288. switch ( lobbyType ) {
  289. case TYPE_PARTY: return "TYPE_PARTY";
  290. case TYPE_GAME: return "TYPE_GAME";
  291. case TYPE_GAME_STATE: return "TYPE_GAME_STATE";
  292. }
  293. return "LOBBY_INVALID";
  294. }
  295. virtual lobbyUserID_t AllocLobbyUserSlotForBot( const char * botName ); // find a open user slot for the bot, and return the userID.
  296. virtual void RemoveBotFromLobbyUserList( lobbyUserID_t lobbyUserID ); // release the session user slot, so that it can be claimed by a player, etc.
  297. virtual bool GetLobbyUserIsBot( lobbyUserID_t lobbyUserID ) const; // check to see if the lobby user is a bot or not
  298. virtual int GetNumLobbyUsers() const { return userList.Num(); }
  299. virtual int GetNumActiveLobbyUsers() const;
  300. virtual bool AllPeersInGame() const;
  301. lobbyUser_t * GetLobbyUser( int index ) { return ( index >= 0 && index < GetNumLobbyUsers() ) ? userList[index] : NULL; }
  302. const lobbyUser_t * GetLobbyUser( int index ) const { return ( index >= 0 && index < GetNumLobbyUsers() ) ? userList[index] : NULL; }
  303. virtual bool IsLobbyUserConnected( int index ) const { return !IsLobbyUserDisconnected( index ); }
  304. virtual int PeerIndexFromLobbyUser( lobbyUserID_t lobbyUserID ) const;
  305. virtual int GetPeerTimeSinceLastPacket( int peerIndex ) const;
  306. virtual int PeerIndexForHost() const { return host; }
  307. virtual int PeerIndexOnHost() const { return peerIndexOnHost; } // Returns -1 if we are the host
  308. virtual const idMatchParameters & GetMatchParms() const { return parms; }
  309. lobbyType_t GetActingGameStateLobbyType() const;
  310. // If IsHost is true, we are a host accepting connections from peers
  311. bool IsHost() const { return isHost; }
  312. // If IsPeer is true, we are a peer, with an active connection to a host
  313. bool IsPeer() const {
  314. if ( host == -1 ) {
  315. return false; // Can't possibly be a peer if we haven't setup a host
  316. }
  317. assert( !IsHost() );
  318. return peers[host].IsConnected();
  319. }
  320. bool IsConnectingPeer() const {
  321. if ( host == -1 ) {
  322. return false; // Can't possibly be a peer if we haven't setup a host
  323. }
  324. assert( !IsHost() );
  325. return peers[host].connectionState == CONNECTION_CONNECTING;
  326. }
  327. // IsRunningAsHostOrPeer means we are either an active host, and can accept connections from peers, or we are a peer with an active connection to a host
  328. bool IsRunningAsHostOrPeer() const { return IsHost() || IsPeer(); }
  329. bool IsLobbyActive() const { return IsRunningAsHostOrPeer(); }
  330. struct reliablePlayerToPlayerHeader_t {
  331. int fromSessionUserIndex;
  332. int toSessionUserIndex;
  333. reliablePlayerToPlayerHeader_t();
  334. // Both read and write return false if the data is invalid.
  335. // The state of the msg and object are undefined if false is returned.
  336. // The network packets contain userIds, and Read/Write will translate from userId to a
  337. // sessionUserIndex. The sessionUserIndex should be the same on all peers, but the
  338. // userId has to be used in case the target player quits while the message is on the
  339. // wire from the originating peer to the server.
  340. bool Read( idLobby * lobby, idBitMsg & msg );
  341. bool Write( idLobby * lobby, idBitMsg & msg );
  342. };
  343. int GetTotalOutgoingRate(); // returns total instant outgoing bandwidth in B/s
  344. //private:
  345. public: // Turning this on for now, for the sake of getting this up and running to see where things are
  346. // State functions
  347. void State_Idle();
  348. void State_Create_Lobby_Backend();
  349. void State_Searching();
  350. void State_Obtaining_Address();
  351. void State_Finalize_Connect();
  352. void State_Connect_Hello_Wait();
  353. void SetState( lobbyState_t newState );
  354. void StartCreating();
  355. int FindPeer( const lobbyAddress_t & remoteAddress, idPacketProcessor::sessionId_t sessionID, bool ignoreSessionID = false );
  356. int FindAnyPeer( const lobbyAddress_t & remoteAddress ) const;
  357. int FindFreePeer() const;
  358. int AddPeer( const lobbyAddress_t & remoteAddress, idPacketProcessor::sessionId_t sessionID );
  359. void DisconnectPeerFromSession( int p );
  360. void SetPeerConnectionState( int p, connectionState_t newState, bool skipGoodbye = false );
  361. void DisconnectAllPeers();
  362. virtual void SendReliable( int type, idBitMsg & msg, bool callReceiveReliable = true, peerMask_t sessionUserMask = MAX_UNSIGNED_TYPE( peerMask_t ) );
  363. virtual void SendReliableToLobbyUser( lobbyUserID_t lobbyUserID, int type, idBitMsg & msg );
  364. virtual void SendReliableToHost( int type, idBitMsg & msg );
  365. void SendGoodbye( const lobbyAddress_t & remoteAddress, bool wasFull = false );
  366. void QueueReliableMessage( int peerNum, byte type ) { QueueReliableMessage( peerNum, type, NULL, 0 ); }
  367. void QueueReliableMessage( int p, byte type, const byte * data, int dataLen );
  368. virtual int GetNumConnectedPeers() const;
  369. virtual int GetNumConnectedPeersInGame() const;
  370. void SendMatchParmsToPeers();
  371. static bool IsReliablePlayerToPlayerType( byte type );
  372. void HandleReliablePlayerToPlayerMsg( int peerNum, idBitMsg & msg, int type );
  373. void HandleReliablePlayerToPlayerMsg( const reliablePlayerToPlayerHeader_t & info, idBitMsg & msg, int reliableType );
  374. void SendConnectionLess( const lobbyAddress_t & remoteAddress, byte type ) { SendConnectionLess( remoteAddress, type, NULL, 0 ); }
  375. void SendConnectionLess( const lobbyAddress_t & remoteAddress, byte type, const byte * data, int dataLen );
  376. void SendConnectionRequest();
  377. void ConnectTo( const lobbyConnectInfo_t & connectInfo, bool fromInvite );
  378. void HandleGoodbyeFromPeer( int peerNum, lobbyAddress_t & remoteAddress, int msgType );
  379. void HandleConnectionAttemptFailed();
  380. bool ConnectToNextSearchResult();
  381. bool CheckVersion( idBitMsg & msg, lobbyAddress_t peerAddress );
  382. bool VerifyNumConnectingUsers( idBitMsg & msg );
  383. bool VerifyLobbyUserIDs( idBitMsg & msg );
  384. int HandleInitialPeerConnection( idBitMsg & msg, const lobbyAddress_t & peerAddress, int peerNum );
  385. void InitStateLobbyHost();
  386. void SendMembersToLobby( lobbyType_t destLobbyType, const lobbyConnectInfo_t & connectInfo, bool waitForOtherMembers );
  387. void SendMembersToLobby( idLobby & destLobby, bool waitForOtherMembers );
  388. void SendPeerMembersToLobby( int peerIndex, lobbyType_t destLobbyType, const lobbyConnectInfo_t & connectInfo, bool waitForOtherMembers );
  389. void SendPeerMembersToLobby( int peerIndex, lobbyType_t destLobbyType, bool waitForOtherMembers );
  390. void NotifyPartyOfLeavingGameLobby();
  391. uint32 GetPartyTokenAsHost();
  392. virtual void DrawDebugNetworkHUD() const;
  393. virtual void DrawDebugNetworkHUD2() const;
  394. virtual void DrawDebugNetworkHUD_ServerSnapshotMetrics( bool draw );
  395. void CheckHeartBeats();
  396. bool IsLosingConnectionToHost() const;
  397. bool IsMigratedStatsGame() const;
  398. bool ShouldRelaunchMigrationGame() const;
  399. bool ShouldShowMigratingDialog() const;
  400. bool IsMigrating() const;
  401. // Pings
  402. struct pktPing_t {
  403. int timestamp;
  404. };
  405. void PingPeers();
  406. void SendPingValues();
  407. void PumpPings();
  408. void HandleReliablePing( int p, idBitMsg & msg );
  409. void HandlePingReply( int p, const pktPing_t & ping );
  410. void HandlePingValues( idBitMsg & msg );
  411. void HandleBandwidhTestValue( int p, idBitMsg & msg );
  412. void HandleMigrationGameData( idBitMsg & msg );
  413. void HandleHeadsetStateChange( int fromPeer, idBitMsg & msg );
  414. bool SendAnotherFragment( int p );
  415. bool CanSendMoreData( int p );
  416. void ProcessOutgoingMsg( int p, const void * data, int size, bool isOOB, int userData );
  417. void ResendReliables( int p );
  418. void PumpPackets();
  419. void UpdateMatchParms( const idMatchParameters & p );
  420. // SessionID helpers
  421. idPacketProcessor::sessionId_t EncodeSessionID( uint32 key ) const;
  422. void DecodeSessionID( idPacketProcessor::sessionId_t sessionID, uint32 & key ) const;
  423. idPacketProcessor::sessionId_t GenerateSessionID() const;
  424. bool SessionIDCanBeUsedForInBand( idPacketProcessor::sessionId_t sessionID ) const;
  425. idPacketProcessor::sessionId_t IncrementSessionID( idPacketProcessor::sessionId_t sessionID ) const;
  426. void HandleHelloAck( int p, idBitMsg & msg );
  427. virtual const char * GetLobbyUserName( lobbyUserID_t lobbyUserID ) const;
  428. virtual bool GetLobbyUserWeaponAutoReload( lobbyUserID_t lobbyUserID ) const;
  429. virtual bool GetLobbyUserWeaponAutoSwitch( lobbyUserID_t lobbyUserID ) const;
  430. virtual int GetLobbyUserSkinIndex( lobbyUserID_t lobbyUserID ) const;
  431. virtual int GetLobbyUserLevel( lobbyUserID_t lobbyUserID ) const;
  432. virtual int GetLobbyUserQoS( lobbyUserID_t lobbyUserID ) const;
  433. virtual int GetLobbyUserTeam( lobbyUserID_t lobbyUserID ) const;
  434. virtual bool SetLobbyUserTeam( lobbyUserID_t lobbyUserID, int teamNumber );
  435. virtual int GetLobbyUserPartyToken( lobbyUserID_t lobbyUserID ) const;
  436. virtual idPlayerProfile * GetProfileFromLobbyUser( lobbyUserID_t lobbyUserID );
  437. virtual idLocalUser * GetLocalUserFromLobbyUser( lobbyUserID_t lobbyUserID );
  438. virtual int GetNumLobbyUsersOnTeam( int teamNumber ) const;
  439. const char * GetPeerName( int peerNum ) const;
  440. virtual const char * GetHostUserName() const;
  441. void HandleReliableMsg( int p, idBitMsg & msg );
  442. // Bandwidth / Qos / Throttling
  443. void BeginBandwidthTest();
  444. bool BandwidthTestStarted();
  445. void ServerUpdateBandwidthTest();
  446. void ClientUpdateBandwidthTest();
  447. void ThrottlePeerSnapRate( int peerNum );
  448. //
  449. // sys_session_instance_users.cpp
  450. //
  451. lobbyUser_t * AllocUser( const lobbyUser_t & defaults );
  452. void FreeUser( lobbyUser_t * user );
  453. bool VerifyUser( const lobbyUser_t * lobbyUser ) const;
  454. void FreeAllUsers();
  455. void RegisterUser( lobbyUser_t * lobbyUser );
  456. void UnregisterUser( lobbyUser_t * lobbyUser );
  457. bool IsSessionUserLocal( const lobbyUser_t * lobbyUser ) const;
  458. bool IsSessionUserIndexLocal( int i ) const;
  459. int GetLobbyUserIndexByID( lobbyUserID_t lobbyUserId, bool ignoreLobbyType = false ) const;
  460. lobbyUser_t * GetLobbyUserByID( lobbyUserID_t lobbyUserId, bool ignoreLobbyType = false );
  461. // Helper function to create a lobby user from a local user
  462. lobbyUser_t CreateLobbyUserFromLocalUser( const idLocalUser * localUser );
  463. // This function is designed to initialize the session users of type lobbyType (TYPE_GAME or TYPE_PARTY)
  464. // to the current list of local users that are being tracked by the sign-in manager
  465. void InitSessionUsersFromLocalUsers( bool onlineMatch );
  466. // Convert an local userhandle to a session user (-1 if there is no session user with this handle)
  467. int GetLobbyUserIndexByLocalUserHandle( const localUserHandle_t localUserHandle ) const;
  468. // This takes a session user, and converts to a controller user
  469. idLocalUser * GetLocalUserFromLobbyUserIndex( int lobbyUserIndex );
  470. // Takes a controller user, and converts to a session user (will return NULL if there is no session user for this controller user)
  471. lobbyUser_t * GetSessionUserFromLocalUser( const idLocalUser * controller );
  472. void RemoveUsersWithDisconnectedPeers();
  473. void RemoveSessionUsersByIDList( idList< lobbyUserID_t > & usersToRemoveByID );
  474. void SendNewUsersToPeers( int skipPeer, int userStart, int numUsers );
  475. void SendPeersMicStatusToNewUsers( int peerNumber );
  476. void AddUsersFromMsg( idBitMsg & msg, int fromPeer );
  477. void UpdateSessionUserOnPeers( idBitMsg & msg );
  478. void HandleUpdateSessionUser( idBitMsg & msg );
  479. void CreateUserUpdateMessage( int userIndex, idBitMsg & msg );
  480. void UpdateLocalSessionUsers();
  481. int PeerIndexForSessionUserIndex( int sessionUserIndex ) const;
  482. void HandleUserConnectFailure( int p, idBitMsg & inMsg, int reliableType );
  483. void ProcessUserDisconnectMsg( idBitMsg & msg );
  484. void CompactDisconnectedUsers();
  485. // Sends a request to the host to join a local user to a session
  486. void RequestLocalUserJoin( idLocalUser * localUser );
  487. // Sends a request to the host to remove a session user from the session
  488. void RequestSessionUserDisconnect( int sessionUserIndex );
  489. // This function sycs the session users with the current list of of local users on the signin manager.
  490. // It will remove the session users that are either no longer on the signin manager, or it
  491. // will remove them if they are no longer allowed to be in the session.
  492. // If it finds a local users that are not in a particular session, it will add that user if allowed.
  493. void SyncLobbyUsersWithLocalUsers( bool allowJoin, bool onlineMatch );
  494. bool ValidateConnectedUser( const lobbyUser_t * user ) const;
  495. virtual bool IsLobbyUserDisconnected( int userIndex ) const;
  496. virtual bool IsLobbyUserValid( lobbyUserID_t lobbyUserID ) const;
  497. virtual bool IsLobbyUserLoaded( lobbyUserID_t lobbyUserID ) const;
  498. virtual bool LobbyUserHasFirstFullSnap( lobbyUserID_t lobbyUserID ) const;
  499. virtual lobbyUserID_t GetLobbyUserIdByOrdinal( int userIndex ) const;
  500. virtual int GetLobbyUserIndexFromLobbyUserID( lobbyUserID_t lobbyUserID ) const;
  501. virtual void EnableSnapshotsForLobbyUser( lobbyUserID_t lobbyUserID );
  502. virtual bool IsPeerDisconnected( int peerIndex ) const { return !peers[peerIndex].IsConnected(); }
  503. float GetAverageSessionLevel();
  504. float GetAverageLocalUserLevel( bool onlineOnly );
  505. void QueueReliablePlayerToPlayerMessage( int fromSessionUserIndex, int toSessionUserIndex, reliablePlayerToPlayer_t type, const byte * data, int dataLen );
  506. virtual void KickLobbyUser( lobbyUserID_t lobbyUserID );
  507. int GetNumConnectedUsers() const;
  508. //
  509. // sys_session_instance_migrate.cpp
  510. //
  511. bool IsBetterHost( int ping1, lobbyUserID_t userId1, int ping2, lobbyUserID_t userId2 );
  512. int FindMigrationInviteIndex( lobbyAddress_t & address );
  513. void UpdateHostMigration();
  514. void BuildMigrationInviteList( bool inviteOldHost );
  515. void PickNewHost( bool forceMe = false, bool inviteOldHost = false );
  516. void PickNewHostInternal( bool forceMe, bool inviteOldHost );
  517. void BecomeHost();
  518. void EndMigration();
  519. void ResetAllMigrationState();
  520. void SendMigrationGameData();
  521. bool GetMigrationGameData( idBitMsg &msg, bool reading );
  522. bool GetMigrationGameDataUser( lobbyUserID_t lobbyUserID, idBitMsg &msg, bool reading );
  523. //
  524. // Snapshots
  525. // sys_session_instance_snapshot.cpp
  526. //
  527. void UpdateSnaps();
  528. bool SendCompletedSnaps();
  529. bool SendResources( int p );
  530. bool SubmitPendingSnap( int p );
  531. void SendCompletedPendingSnap( int p );
  532. void CheckPeerThrottle( int p );
  533. void ApplySnapshotDelta( int p, int snapshotNumber );
  534. bool ApplySnapshotDeltaInternal( int p, int snapshotNumber );
  535. void SendSnapshotToPeer( idSnapShot & ss, int p );
  536. bool AllPeersHaveBaseState();
  537. void ThrottleSnapsForXSeconds( int p, int seconds, bool recoverPing );
  538. bool FirstSnapHasBeenSent( int p );
  539. virtual bool EnsureAllPeersHaveBaseState();
  540. virtual bool AllPeersHaveStaleSnapObj( int objId );
  541. virtual bool AllPeersHaveExpectedSnapObj( int objId );
  542. virtual void MarkSnapObjDeleted( int objId );
  543. virtual void RefreshSnapObj( int objId );
  544. void ResetBandwidthStats();
  545. void DetectSaturation( int p );
  546. virtual void AddSnapObjTemplate( int objID, idBitMsg & msg );
  547. static const int MAX_PEERS = MAX_PLAYERS;
  548. //------------------------
  549. // Pings
  550. //------------------------
  551. struct pktPingValues_t {
  552. idArray<short, MAX_PEERS> pings;
  553. };
  554. static const int PING_INTERVAL_MS = 3000;
  555. int lastPingValuesRecvTime; // so clients can display something when server stops pinging
  556. int nextSendPingValuesTime; // the next time to send RELIABLE_PING_VALUES
  557. static const int MIGRATION_GAME_DATA_INTERVAL_MS = 1000;
  558. int nextSendMigrationGameTime; // when to send next migration game data
  559. int nextSendMigrationGamePeer; // who to send next migration game data to
  560. lobbyType_t lobbyType;
  561. lobbyState_t state; // State of this lobby
  562. failedReason_t failedReason;
  563. int host; // which peer is the host of this type of session (-1 if we are the host)
  564. int peerIndexOnHost; // -1 if we are the host
  565. lobbyAddress_t hostAddress; // address of the host for this type of session
  566. bool isHost; // true if we are the host
  567. idLobbyBackend * lobbyBackend;
  568. int helloStartTime; // Used to determine when the first hello was sent
  569. int lastConnectRequest; // Used to determine when the last hello was sent
  570. int connectionAttempts; // Number of connection attempts
  571. bool needToDisplayMigrateMsg; // If true, we migrated as host, so we need to display the msg as soon as the lobby is active
  572. gameDialogMessages_t migrationDlg; // current migration dialog we should be showing
  573. uint8 migrateMsgFlags; // cached match flags from the old game we migrated from, so we know what type of msg to display
  574. bool joiningMigratedGame; // we are joining a migrated game and need to tell the session mgr if we succeed or fail
  575. // ------------------------
  576. // Bandwidth challenge
  577. // ------------------------
  578. int bandwidthChallengeEndTime; // When the challenge will end/timeout
  579. int bandwidthChallengeStartTime; // time in MS the challenge started
  580. bool bandwidthChallengeFinished; // (HOST) test is finished and we received results back from all peers (or timed out)
  581. int bandwidthChallengeNumGoodSeq; // (PEER) num of good, in order packets we recevieved
  582. int lastSnapBspHistoryUpdateSequence;
  583. void SaveDisconnectedUser( const lobbyUser_t & user ); // This is needed to get the a user's gamertag after disconnection.
  584. idSessionCallbacks * sessionCB;
  585. enum migrationState_t {
  586. MIGRATE_NONE,
  587. MIGRATE_PICKING_HOST,
  588. MIGRATE_BECOMING_HOST,
  589. };
  590. struct migrationInvite_t {
  591. migrationInvite_t() {
  592. lastInviteTime = -1;
  593. pingMs = 0;
  594. migrationGameData = -1;
  595. }
  596. lobbyAddress_t address;
  597. int pingMs;
  598. lobbyUserID_t userId;
  599. int lastInviteTime;
  600. int migrationGameData;
  601. };
  602. struct migrationInfo_t {
  603. migrationInfo_t() {
  604. state = MIGRATE_NONE;
  605. ourPingMs = 0;
  606. ourUserId = lobbyUserID_t();
  607. }
  608. migrationState_t state;
  609. idStaticList< migrationInvite_t, MAX_PEERS > invites;
  610. int migrationStartTime;
  611. int ourPingMs;
  612. lobbyUserID_t ourUserId;
  613. struct persistUntilGameEnds_t {
  614. persistUntilGameEnds_t() {
  615. Clear();
  616. }
  617. void Clear() {
  618. wasMigratedHost = false;
  619. wasMigratedJoin = false;
  620. wasMigratedGame = false;
  621. ourGameData = -1;
  622. hasGameData = false;
  623. hasRelaunchedMigratedGame = false;
  624. memset( gameData, 0, sizeof( gameData ) );
  625. memset( gameDataUser, 0, sizeof( gameDataUser ) );
  626. }
  627. int ourGameData;
  628. bool wasMigratedHost; // we are hosting a migrated session
  629. bool wasMigratedJoin; // we joined a migrated session
  630. bool wasMigratedGame; // If true, we migrated from a game
  631. bool hasRelaunchedMigratedGame;
  632. // A generic blob of data that the gamechallenge (or anything else) can read and write to for host migration
  633. static const int MIGRATION_GAME_DATA_SIZE = 32;
  634. byte gameData[ MIGRATION_GAME_DATA_SIZE ];
  635. static const int MIGRATION_GAME_DATA_USER_SIZE = 64;
  636. byte gameDataUser[ MAX_PLAYERS ][ MIGRATION_GAME_DATA_USER_SIZE ];
  637. bool hasGameData;
  638. } persistUntilGameEndsData;
  639. };
  640. struct disconnectedUser_t {
  641. lobbyUserID_t lobbyUserID; // Locally generated to be unique, and internally keeps the local user handle
  642. char gamertag[lobbyUser_t::MAX_GAMERTAG];
  643. };
  644. migrationInfo_t migrationInfo;
  645. bool showHostLeftTheSession;
  646. bool connectIsFromInvite;
  647. idList< lobbyConnectInfo_t > searchResults;
  648. typedef idStaticList< lobbyUser_t *, MAX_PLAYERS > idLobbyUserList;
  649. typedef idStaticList< lobbyUser_t, MAX_PLAYERS > idLobbyUserPool;
  650. idLobbyUserList userList; // list of currently connected users to this lobby
  651. idLobbyUserList freeUsers; // list of free users
  652. idLobbyUserPool userPool;
  653. idList< disconnectedUser_t> disconnectedUsers; // List of users which were connected, but aren't anymore, for printing their name on the hud
  654. idStaticList< peer_t, MAX_PEERS > peers; // Unique machines connected to this lobby
  655. uint32 partyToken;
  656. idMatchParameters parms;
  657. bool loaded; // Used for game sessions, whether this machine is loaded or not
  658. bool respondToArbitrate; // true when the host has requested us to arbitrate our session (for TYPE_GAME only)
  659. bool everyoneArbitrated;
  660. bool waitForPartyOk;
  661. bool startLoadingFromHost;
  662. //------------------------
  663. // Snapshot jobs
  664. //------------------------
  665. static const int SNAP_OBJ_JOB_MEMORY = 1024 * 128; // 128k of obj memory
  666. lzwCompressionData_t * lzwData; // Shared across all snapshot jobs
  667. uint8 * objMemory; // Shared across all snapshot jobs
  668. bool haveSubmittedSnaps; // True if we previously submitted snaps to jobs
  669. idSnapShot * localReadSS;
  670. struct snapDeltaAck_t {
  671. int p;
  672. int snapshotNumber;
  673. };
  674. idStaticList< snapDeltaAck_t, 16 > snapDeltaAckQueue;
  675. };
  676. /*
  677. ========================
  678. idSessionCallbacks
  679. ========================
  680. */
  681. class idSessionCallbacks {
  682. public:
  683. virtual idLobby & GetPartyLobby() = 0;
  684. virtual idLobby & GetGameLobby() = 0;
  685. virtual idLobby & GetActingGameStateLobby() = 0;
  686. virtual idLobby * GetLobbyFromType( idLobby::lobbyType_t lobbyType ) = 0;
  687. virtual int GetUniquePlayerId() const = 0;
  688. virtual idSignInManagerBase & GetSignInManager() = 0;
  689. virtual void SendRawPacket( const lobbyAddress_t & to, const void * data, int size, bool useDirectPort ) = 0;
  690. virtual bool BecomingHost( idLobby & lobby ) = 0; // Called when a lobby is about to become host
  691. virtual void BecameHost( idLobby & lobby ) = 0; // Called when a lobby becomes a host
  692. virtual bool BecomingPeer( idLobby & lobby ) = 0; // Called when a lobby is about to become peer
  693. virtual void BecamePeer( idLobby & lobby ) = 0; // Called when a lobby becomes a peer
  694. virtual void FailedGameMigration( idLobby & lobby ) = 0;
  695. virtual void MigrationEnded( idLobby & lobby ) = 0;
  696. virtual void GoodbyeFromHost( idLobby & lobby, int peerNum, const lobbyAddress_t & remoteAddress, int msgType ) = 0;
  697. virtual uint32 GetSessionOptions() = 0;
  698. virtual bool AnyPeerHasAddress( const lobbyAddress_t & remoteAddress ) const = 0;
  699. virtual idSession::sessionState_t GetState() const = 0;
  700. virtual void ClearMigrationState() = 0;
  701. // Called when the lobby receives a RELIABLE_ENDMATCH msg
  702. virtual void EndMatchInternal( bool premature=false ) = 0;
  703. // Called when the game lobby receives leaderboard stats
  704. virtual void RecvLeaderboardStats( idBitMsg & msg ) = 0;
  705. // Called once the lobby received its first full snap (used to advance from LOADING to INGAME state)
  706. virtual void ReceivedFullSnap() = 0;
  707. // Called when lobby received RELIABLE_PARTY_LEAVE_GAME_LOBBY msg
  708. virtual void LeaveGameLobby() = 0;
  709. virtual void PrePickNewHost( idLobby & lobby, bool forceMe, bool inviteOldHost ) = 0;
  710. virtual bool PreMigrateInvite( idLobby & lobby ) = 0;
  711. virtual void HandleOobVoiceAudio( const lobbyAddress_t & from, const idBitMsg & msg ) = 0;
  712. // ConnectAndMoveToLobby is called when the lobby receives a RELIABLE_CONNECT_AND_MOVE_TO_LOBBY
  713. virtual void ConnectAndMoveToLobby( idLobby::lobbyType_t destLobbyType, const lobbyConnectInfo_t & connectInfo, bool waitForPartyOk ) = 0;
  714. virtual class idVoiceChatMgr * GetVoiceChat() = 0;
  715. virtual void HandleServerQueryRequest( lobbyAddress_t & remoteAddr, idBitMsg & msg, int msgType ) = 0;
  716. virtual void HandleServerQueryAck( lobbyAddress_t & remoteAddr, idBitMsg & msg ) = 0;
  717. virtual void HandlePeerMatchParamUpdate( int peer, int msg ) = 0;
  718. virtual idLobbyBackend * CreateLobbyBackend( const idMatchParameters & p, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) = 0;
  719. virtual idLobbyBackend * FindLobbyBackend( const idMatchParameters & p, int numPartyUsers, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) = 0;
  720. virtual idLobbyBackend * JoinFromConnectInfo( const lobbyConnectInfo_t & connectInfo , idLobbyBackend::lobbyBackendType_t lobbyType ) = 0;
  721. virtual void DestroyLobbyBackend( idLobbyBackend * lobbyBackend ) = 0;
  722. };