Counter Strike : Global Offensive Source Code
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.

306 lines
8.1 KiB

  1. //===== Copyright � 1996-2009, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "mm_netmsgcontroller.h"
  7. #include "matchmakingqos.h"
  8. #include "proto_oob.h"
  9. #include "bitbuf.h"
  10. #include "fmtstr.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. //
  14. // Implementation
  15. //
  16. CMatchNetworkMsgControllerBase::CMatchNetworkMsgControllerBase()
  17. {
  18. }
  19. CMatchNetworkMsgControllerBase::~CMatchNetworkMsgControllerBase()
  20. {
  21. }
  22. static CMatchNetworkMsgControllerBase g_MatchNetMsgControllerBase;
  23. CMatchNetworkMsgControllerBase *g_pMatchNetMsgControllerBase = &g_MatchNetMsgControllerBase;
  24. //
  25. // A way to copy just value
  26. //
  27. static void CopyValue( KeyValues *pTo, KeyValues *pFrom )
  28. {
  29. switch ( pFrom->GetDataType() )
  30. {
  31. case KeyValues::TYPE_INT:
  32. pTo->SetInt( "", pFrom->GetInt() );
  33. break;
  34. case KeyValues::TYPE_UINT64:
  35. pTo->SetUint64( "", pFrom->GetUint64() );
  36. break;
  37. case KeyValues::TYPE_STRING:
  38. pTo->SetString( "", pFrom->GetString() );
  39. break;
  40. default:
  41. DevWarning( "NetMsgCtrlr::CopyValue using unknown type!\n" );
  42. Assert( 0 );
  43. break;
  44. }
  45. }
  46. //
  47. // Implementation
  48. //
  49. MM_QOS_t CMatchNetworkMsgControllerBase::GetQOS()
  50. {
  51. return MM_GetQos();
  52. }
  53. KeyValues * CMatchNetworkMsgControllerBase::GetActiveServerGameDetails( KeyValues *pRequest )
  54. {
  55. // Query server info
  56. INetSupport::ServerInfo_t si;
  57. g_pMatchExtensions->GetINetSupport()->GetServerInfo( &si );
  58. KeyValues *pDetails = NULL;
  59. if ( si.m_bActive )
  60. {
  61. MEM_ALLOC_CREDIT();
  62. //
  63. // Parse the game details from the values
  64. //
  65. pDetails = KeyValues::FromString(
  66. "GameDetailsServer",
  67. " system { "
  68. " network LIVE "
  69. " access public "
  70. " } "
  71. " server { "
  72. " name = "
  73. " server = "
  74. " adronline = "
  75. " adrlocal = "
  76. " } "
  77. " members { "
  78. " numSlots #int#0 "
  79. " numPlayers #int#0 "
  80. " } "
  81. );
  82. //
  83. // For a listen server and other MM session overlay the session settings
  84. //
  85. if ( !si.m_bDedicated && g_pMatchFramework->GetMatchSession() )
  86. {
  87. pDetails->MergeFrom( g_pMatchFramework->GetMatchSession()->GetSessionSettings(), KeyValues::MERGE_KV_BORROW );
  88. }
  89. //
  90. // Get server information
  91. //
  92. pDetails->SetString( "server/name", si.m_szServerName );
  93. pDetails->SetString( "server/server", si.m_bDedicated ? "dedicated" : "listen" );
  94. pDetails->SetString( "server/adronline", si.m_netAdrOnline.ToString() );
  95. pDetails->SetString( "server/adrlocal", si.m_netAdr.ToString() );
  96. if ( si.m_bDedicated && si.m_bLobbyExclusive && si.m_bGroupExclusive )
  97. pDetails->SetString( "system/access", "friends" );
  98. si.m_numMaxHumanPlayers = ClampArrayBounds( si.m_numMaxHumanPlayers, g_pMMF->GetMatchTitle()->GetTotalNumPlayersSupported() );
  99. pDetails->SetInt( "members/numSlots", si.m_numMaxHumanPlayers );
  100. si.m_numHumanPlayers = ClampArrayBounds( si.m_numHumanPlayers, si.m_numMaxHumanPlayers );
  101. pDetails->SetInt( "members/numPlayers", si.m_numHumanPlayers );
  102. static ConVarRef host_info_show( "host_info_show" );
  103. if ( host_info_show.GetInt() < 2 )
  104. pDetails->SetString( "options/action", "crypt" );
  105. }
  106. else if ( IVEngineClient *pIVEngineClient = g_pMatchExtensions->GetIVEngineClient() )
  107. {
  108. if ( pIVEngineClient->IsLevelMainMenuBackground() )
  109. return NULL;
  110. char const *szLevelName = pIVEngineClient->GetLevelNameShort();
  111. if ( !szLevelName || !*szLevelName )
  112. return NULL;
  113. MEM_ALLOC_CREDIT();
  114. pDetails = new KeyValues( "GameDetailsClient" );
  115. }
  116. if ( !pDetails )
  117. return NULL;
  118. // Allow title to add game-specific settings
  119. g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendServerDetails( pDetails, pRequest );
  120. return pDetails;
  121. }
  122. static KeyValues * GetLobbyDetailsTemplate( char const *szReason = "", KeyValues *pSettings = NULL )
  123. {
  124. KeyValues *pDetails = KeyValues::FromString(
  125. "settings",
  126. " system { "
  127. " network #empty# "
  128. " access #empty# "
  129. " netflag #empty# "
  130. " lock #empty# "
  131. " } "
  132. " options { "
  133. " server #empty# "
  134. " } "
  135. " members { "
  136. " numSlots #int#0 "
  137. " numPlayers #int#0 "
  138. " } "
  139. );
  140. g_pMMF->GetMatchTitleGameSettingsMgr()->ExtendLobbyDetailsTemplate( pDetails, szReason, pSettings );
  141. return pDetails;
  142. }
  143. KeyValues * CMatchNetworkMsgControllerBase::UnpackGameDetailsFromQOS( MM_GameDetails_QOS_t const *pvQosReply )
  144. {
  145. //
  146. // Check if we have correct header
  147. //
  148. CUtlBuffer bufQos( pvQosReply->m_pvData, pvQosReply->m_numDataBytes, CUtlBuffer::READ_ONLY );
  149. bufQos.ActivateByteSwapping( !CByteswap::IsMachineBigEndian() );
  150. int iProtocol = bufQos.GetInt();
  151. int iVersion = bufQos.GetInt();
  152. if ( iProtocol != g_pMatchExtensions->GetINetSupport()->GetEngineBuildNumber() )
  153. return NULL;
  154. if ( 0 != iVersion )
  155. return NULL;
  156. //
  157. // Read the game details that we have received
  158. //
  159. MEM_ALLOC_CREDIT();
  160. KeyValues *pDetails = new KeyValues( "" );
  161. if ( !pDetails->ReadAsBinary( bufQos ) )
  162. {
  163. pDetails->deleteThis();
  164. return NULL;
  165. }
  166. // Read the terminator
  167. int iTerm = bufQos.GetInt();
  168. if ( iTerm != 0 )
  169. {
  170. DevWarning( "UnpackGameDetailsFromQOS found bad QOS block terminator!\n" );
  171. }
  172. return pDetails;
  173. }
  174. void CMatchNetworkMsgControllerBase::PackageGameDetailsForQOS( KeyValues *pSettings, CUtlBuffer &buf )
  175. {
  176. KeyValues *pDetails = GetLobbyDetailsTemplate( "qos", pSettings );
  177. KeyValues::AutoDelete autodelete( pDetails );
  178. // Keep only keys specified in the template
  179. pDetails->MergeFrom( pSettings, KeyValues::MERGE_KV_BORROW );
  180. // Write the details as binary
  181. buf.PutInt( g_pMatchExtensions->GetINetSupport()->GetEngineBuildNumber() );
  182. buf.PutInt( 0 );
  183. pDetails->WriteAsBinary( buf );
  184. buf.PutInt( 0 );
  185. }
  186. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  187. static void UnpackGameDetailsFromSteamLobbyInKey( uint64 uiLobbyID, char const *szPath, KeyValues *pKey )
  188. {
  189. // Iterate over all the values
  190. for ( KeyValues *val = pKey->GetFirstValue(); val; val = val->GetNextValue() )
  191. {
  192. char const *szLobbyData = steamapicontext->SteamMatchmaking()
  193. ->GetLobbyData( uiLobbyID, CFmtStr( "%s%s", szPath, val->GetName() ) );
  194. switch ( val->GetDataType() )
  195. {
  196. case KeyValues::TYPE_INT:
  197. val->SetInt( "", atoi( szLobbyData ) );
  198. break;
  199. case KeyValues::TYPE_STRING:
  200. val->SetString( "", szLobbyData );
  201. break;
  202. default:
  203. DevWarning( "UnpackGameDetailsFromSteamLobby defined unknown type in schema!\n" );
  204. Assert( 0 );
  205. break;
  206. }
  207. }
  208. // Iterate over subkeys
  209. for ( KeyValues *sub = pKey->GetFirstTrueSubKey(); sub; sub = sub->GetNextTrueSubKey() )
  210. {
  211. UnpackGameDetailsFromSteamLobbyInKey( uiLobbyID, CFmtStr( "%s%s:", szPath, sub->GetName() ), sub );
  212. }
  213. }
  214. #endif
  215. KeyValues * CMatchNetworkMsgControllerBase::UnpackGameDetailsFromSteamLobby( uint64 uiLobbyID )
  216. {
  217. #if !defined( _X360 ) && !defined( NO_STEAM ) && !defined( SWDS )
  218. // Make sure the basic metadata is set on the lobby
  219. char const *arrRequiredMetadata[] = { "system:network", "system:access" };
  220. for ( int k = 0; k < ARRAYSIZE( arrRequiredMetadata ); ++ k )
  221. {
  222. char const *szMetadata = steamapicontext->SteamMatchmaking()->GetLobbyData( uiLobbyID, arrRequiredMetadata[k] );
  223. if ( !szMetadata || !*szMetadata )
  224. return NULL;
  225. }
  226. // Allocate details template
  227. KeyValues *pDetails = GetLobbyDetailsTemplate();
  228. // Iterate over all the keys
  229. UnpackGameDetailsFromSteamLobbyInKey( uiLobbyID, "", pDetails );
  230. // Get members info
  231. if ( KeyValues *kvMembers = pDetails->FindKey( "members", true ) )
  232. {
  233. int numSlots = steamapicontext->SteamMatchmaking()->GetLobbyMemberLimit( uiLobbyID );
  234. numSlots = ClampArrayBounds( numSlots, g_pMMF->GetMatchTitle()->GetTotalNumPlayersSupported() );
  235. kvMembers->SetInt( "numSlots", numSlots );
  236. int numPlayers = steamapicontext->SteamMatchmaking()->GetNumLobbyMembers( uiLobbyID );
  237. numPlayers = ClampArrayBounds( numPlayers, numSlots );
  238. kvMembers->SetInt( "numPlayers", numPlayers );
  239. }
  240. return pDetails;
  241. #endif
  242. return NULL;
  243. }
  244. KeyValues * CMatchNetworkMsgControllerBase::PackageGameDetailsForReservation( KeyValues *pSettings )
  245. {
  246. KeyValues *res = GetLobbyDetailsTemplate( "reserve", pSettings );
  247. res->SetName( COM_GetModDirectory() );
  248. // Keep only keys specified in the template
  249. res->MergeFrom( pSettings, KeyValues::MERGE_KV_BORROW );
  250. return res;
  251. }