Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
6.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Handles host migration for a session (not for the game server)
  4. //
  5. //=============================================================================//
  6. #include "matchmaking.h"
  7. // memdbgon must be the last include file in a .cpp file!!!
  8. #include "tier0/memdbgon.h"
  9. //-----------------------------------------------------------------------------
  10. // Purpose: Start a Matchmaking session as the host
  11. //-----------------------------------------------------------------------------
  12. CClientInfo *CMatchmaking::SelectNewHost()
  13. {
  14. // For now, just grab the first guy in the list
  15. CClientInfo *pClient = &m_Local;
  16. for ( int i = 0; i < m_Remote.Count(); ++i )
  17. {
  18. if ( m_Remote[i]->m_id > pClient->m_id )
  19. {
  20. pClient = m_Remote[i];
  21. }
  22. }
  23. return pClient;
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. //-----------------------------------------------------------------------------
  28. void CMatchmaking::StartHostMigration()
  29. {
  30. SwitchToState( MMSTATE_HOSTMIGRATE_STARTINGMIGRATION );
  31. m_pNewHost = SelectNewHost();
  32. if ( m_pNewHost == &m_Local )
  33. {
  34. // We're the new host, so start hosting
  35. Msg( "Starting new host" );
  36. BeginHosting();
  37. }
  38. else
  39. {
  40. Msg( "Waiting for a new host" );
  41. SwitchToNewHost();
  42. }
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Purpose:
  46. //-----------------------------------------------------------------------------
  47. void CMatchmaking::BeginHosting()
  48. {
  49. m_Session.SetIsHost( true );
  50. m_Host = m_Local;
  51. // Move into private slots
  52. if ( !m_Local.m_bInvited )
  53. {
  54. RemovePlayersFromSession( &m_Local );
  55. m_Local.m_bInvited = true;
  56. AddPlayersToSession( &m_Local );
  57. }
  58. if ( !m_Session.MigrateHost() )
  59. {
  60. Warning( "Session migrate failed!\n" );
  61. SessionNotification( SESSION_NOTIFY_FAIL_MIGRATE );
  62. return;
  63. }
  64. SwitchToState( MMSTATE_HOSTMIGRATE_MIGRATING );
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. void CMatchmaking::TellClientsToMigrate()
  70. {
  71. Msg( "Sending migrate request\n" );
  72. XSESSION_INFO info;
  73. m_Session.GetNewSessionInfo( &info );
  74. MM_Migrate msg;
  75. msg.m_MsgType = MM_Migrate::MESSAGE_HOSTING;
  76. msg.m_Id = m_Local.m_id;
  77. msg.m_sessionId = info.sessionID;
  78. msg.m_xnaddr = info.hostAddress;
  79. msg.m_key = info.keyExchangeKey;
  80. for ( int i = 0; i < m_Remote.Count(); ++i )
  81. {
  82. if ( m_Remote[i]->m_bMigrated )
  83. {
  84. continue;
  85. }
  86. SendMessage( &msg, &m_Remote[i]->m_adr );
  87. }
  88. m_fSendTimer = GetTime();
  89. ++m_nSendCount;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Handle a migration message from our new host
  93. //-----------------------------------------------------------------------------
  94. bool CMatchmaking::ProcessMigrate( MM_Migrate *pMsg )
  95. {
  96. MM_Migrate reply;
  97. int type = pMsg->m_MsgType;
  98. if ( m_CurrentState == MMSTATE_HOSTMIGRATE_WAITINGFORHOST )
  99. {
  100. if ( type == MM_Migrate::MESSAGE_HOSTING )
  101. {
  102. // Make sure this is the host we were expecting
  103. if ( !Q_memcmp( &pMsg->m_xnaddr, &m_Host.m_xnaddr, sizeof( m_Host.m_xnaddr ) ) )
  104. {
  105. // Reply to the host
  106. reply.m_MsgType = MM_Migrate::MESSAGE_MIGRATED;
  107. reply.m_xnaddr = m_Local.m_xnaddr;
  108. SendMessage( &reply, &m_Host.m_adr );
  109. XSESSION_INFO info;
  110. info.sessionID = pMsg->m_sessionId;
  111. info.hostAddress = pMsg->m_xnaddr;
  112. info.keyExchangeKey = pMsg->m_key;
  113. m_Session.SetNewSessionInfo( &info );
  114. m_Session.SetOwnerId( XUSER_INDEX_NONE );
  115. if ( !m_Session.MigrateHost() )
  116. {
  117. Warning( "Session migrate failed!\n" );
  118. SessionNotification( SESSION_NOTIFY_FAIL_MIGRATE );
  119. return true;
  120. }
  121. SwitchToState( MMSTATE_HOSTMIGRATE_MIGRATING );
  122. }
  123. else
  124. {
  125. // Someone else is trying to host
  126. reply.m_MsgType = MM_Migrate::MESSAGE_STANDBY;
  127. SendMessage( &reply, &m_Host.m_adr );
  128. }
  129. }
  130. }
  131. else if ( m_CurrentState == MMSTATE_HOSTMIGRATE_WAITINGFORCLIENTS )
  132. {
  133. if ( type == MM_Migrate::MESSAGE_MIGRATED )
  134. {
  135. // Flag the client as having migrated
  136. bool bClientsOutstanding = false;
  137. for ( int i = 0; i < m_Remote.Count(); ++i )
  138. {
  139. if ( m_Remote[i]->m_id == pMsg->m_Id )
  140. {
  141. m_Remote[i]->m_bMigrated = true;
  142. }
  143. bClientsOutstanding = bClientsOutstanding && m_Remote[i]->m_bMigrated;
  144. }
  145. if ( !bClientsOutstanding )
  146. {
  147. // Everyone's migrated!
  148. EndMigration();
  149. }
  150. }
  151. if ( type == MM_Migrate::MESSAGE_STANDBY )
  152. {
  153. // Someone requested a standby
  154. --m_nSendCount;
  155. }
  156. }
  157. return true;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. //-----------------------------------------------------------------------------
  162. void CMatchmaking::SwitchToNewHost()
  163. {
  164. // Set a timer to wait for the host to contact us
  165. m_fWaitTimer = GetTime();
  166. // Get rid of the current host net channel
  167. MarkChannelForRemoval( &m_Host.m_adr );
  168. AddRemoteChannel( &m_pNewHost->m_adr );
  169. SwitchToState( MMSTATE_HOSTMIGRATE_WAITINGFORHOST );
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. //-----------------------------------------------------------------------------
  174. void CMatchmaking::EndMigration()
  175. {
  176. Msg( "Migration complete\n" );
  177. if ( m_Session.IsHost() )
  178. {
  179. // Drop any clients that failed to migrate
  180. for ( int i = m_Remote.Count()-1; i >= 0; --i )
  181. {
  182. ClientDropped( m_Remote[i] );
  183. }
  184. // Update the lobby to show the new host
  185. SendPlayerInfoToLobby( &m_Local, 0 );
  186. // X360TBD: Figure out what state we should be in
  187. int newState = m_PreMigrateState;
  188. switch( m_PreMigrateState )
  189. {
  190. case MMSTATE_SESSION_CONNECTING:
  191. newState = MMSTATE_ACCEPTING_CONNECTIONS;
  192. break;
  193. default:
  194. Warning( "Unhandled post-migrate state transition" );
  195. }
  196. // Don't use SwitchToState() to set our new state because when changing
  197. // from a client to a host the state transition is usually invalid.
  198. m_CurrentState = newState;
  199. }
  200. else
  201. {
  202. // Still a client, just restore our previous state
  203. m_CurrentState = m_PreMigrateState;
  204. }
  205. }
  206. void CMatchmaking::TestStats()
  207. {
  208. }