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.

340 lines
9.4 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #ifndef _X360
  7. #include "xbox/xboxstubs.h"
  8. #endif
  9. #include "mm_framework.h"
  10. #include "filesystem.h"
  11. // NOTE: This has to be the last file included!
  12. #include "tier0/memdbgon.h"
  13. static CDlcManager g_DlcManager;
  14. CDlcManager *g_pDlcManager = &g_DlcManager;
  15. CON_COMMAND( mm_dlc_debugprint, "Shows information about dlc" )
  16. {
  17. KeyValuesDumpAsDevMsg( g_pDlcManager->GetDataInfo(), 1 );
  18. }
  19. //////////////////////////////////////////////////////////////////////////
  20. CDlcManager::CDlcManager() :
  21. m_pDataInfo( NULL ),
  22. m_eState( STATE_IDLE ),
  23. m_flTimestamp( 0.0f ),
  24. m_bNeedToDiscoverAllDlcs( true ),
  25. m_bNeedToUpdateFileSystem( false )
  26. {
  27. #ifdef _X360
  28. m_hEnumerator = NULL;
  29. memset( &m_xOverlapped, 0, sizeof( m_xOverlapped ) );
  30. #endif
  31. }
  32. CDlcManager::~CDlcManager()
  33. {
  34. if ( m_pDataInfo )
  35. m_pDataInfo->deleteThis();
  36. m_pDataInfo = NULL;
  37. }
  38. void CDlcManager::Update()
  39. {
  40. #ifdef _X360
  41. // Per TCR-126 we don't want to open DLC for users who haven't unlocked the game yet
  42. IXboxSystem *pXboxSystem = g_pMatchExtensions->GetIXboxSystem();
  43. if ( !pXboxSystem || !pXboxSystem->IsArcadeTitleUnlocked() )
  44. {
  45. return;
  46. }
  47. DWORD ret = 0;
  48. switch ( m_eState )
  49. {
  50. case STATE_XENUMERATE:
  51. if ( !XHasOverlappedIoCompleted( &m_xOverlapped ) )
  52. return;
  53. ret = XGetOverlappedResult( &m_xOverlapped, ( DWORD * ) &m_dwNumItems, false );
  54. if ( ret != ERROR_SUCCESS )
  55. {
  56. Warning( "DLCMANAGER: XContentCreateEnumerator/XEnumerate async failed with error %d!\n", ret );
  57. m_dwNumItems = 0;
  58. m_bNeedToDiscoverAllDlcs = true;
  59. }
  60. CloseHandle( m_hEnumerator );
  61. m_hEnumerator = NULL;
  62. CreateNextContent();
  63. return;
  64. case STATE_XCONTENT_CREATE:
  65. if ( !XHasOverlappedIoCompleted( &m_xOverlapped ) )
  66. return;
  67. ProcessNextContent();
  68. return;
  69. }
  70. #endif
  71. // Once we are idle check if we need to update the file systems list of DLC
  72. if ( m_eState == STATE_IDLE )
  73. {
  74. if ( m_bNeedToUpdateFileSystem )
  75. {
  76. m_bNeedToUpdateFileSystem = false;
  77. g_pFullFileSystem->DiscoverDLC( XBX_GetPrimaryUserId() );
  78. }
  79. }
  80. }
  81. void CDlcManager::RequestDlcUpdate()
  82. {
  83. if ( m_eState > STATE_IDLE )
  84. return;
  85. if ( m_eState == STATE_IDLE && !m_bNeedToDiscoverAllDlcs )
  86. {
  87. Msg( "DLCMANAGER: RequestDlcUpdate has no new content.\n" );
  88. return;
  89. }
  90. // If we specified dlc via the command line we can skip the actual enumeration
  91. const char *pCmdLine = CommandLine()->GetCmdLine();
  92. if ( V_stristr( pCmdLine, "-dlc" ) )
  93. {
  94. m_eState = STATE_IDLE;
  95. m_bNeedToUpdateFileSystem = true;
  96. m_bNeedToDiscoverAllDlcs = false;
  97. return;
  98. }
  99. #if !defined( NO_STEAM ) && !defined( SWDS )
  100. // Client is requesting a DLC update
  101. m_CallbackOnDLCInstalled.Register( this, &CDlcManager::Steam_OnDLCInstalled );
  102. Steam_OnDLCInstalled( NULL );
  103. #endif
  104. #ifdef _X360
  105. if ( XBX_GetPrimaryUserIsGuest() )
  106. {
  107. Msg( "DLCMANAGER: RequestDlcUpdate will not update for guests.\n" );
  108. return;
  109. }
  110. DWORD nBufferSize = 0;
  111. DWORD ret = XContentCreateEnumerator( XBX_GetPrimaryUserId(), XCONTENTDEVICE_ANY,
  112. XCONTENTTYPE_MARKETPLACE, 0, 100, &nBufferSize, &m_hEnumerator );
  113. if ( ret )
  114. {
  115. Warning( "DLCMANAGER: XContentCreateEnumerator failed with error %d!\n", ret );
  116. return;
  117. }
  118. if ( nBufferSize )
  119. {
  120. m_dwNumItems = 0;
  121. m_arrContentData.EnsureCapacity( nBufferSize/sizeof( XCONTENT_DATA ) + 1 );
  122. m_arrContentData.RemoveAll();
  123. ret = XEnumerate( m_hEnumerator, m_arrContentData.Base(), nBufferSize, NULL, &m_xOverlapped );
  124. if ( ret && ret != ERROR_IO_PENDING )
  125. {
  126. Warning( "DLCMANAGER: XContentCreateEnumerator/XEnumerate failed with error %d!\n", ret );
  127. }
  128. Msg( "DLCMANAGER: XContentCreateEnumerator/XEnumerate initiated.\n" );
  129. m_eState = STATE_XENUMERATE;
  130. m_flTimestamp = Plat_FloatTime();
  131. m_bNeedToDiscoverAllDlcs = false;
  132. return;
  133. }
  134. Warning( "DLCMANAGER: XContentCreateEnumerator not starting enumeration!\n" );
  135. ::CloseHandle( m_hEnumerator );
  136. m_hEnumerator = NULL;
  137. #endif
  138. }
  139. #ifdef _X360
  140. void CDlcManager::CreateNextContent()
  141. {
  142. Msg( "DLCMANAGER: enumeration checkpoint after %.3f sec\n", Plat_FloatTime() - m_flTimestamp );
  143. while ( m_dwNumItems -- > 0 )
  144. {
  145. XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems;
  146. char chKey[ XCONTENT_MAX_FILENAME_LENGTH + 1 ];
  147. memcpy( chKey, pContentData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
  148. chKey[ XCONTENT_MAX_FILENAME_LENGTH ] = 0;
  149. if ( m_pDataInfo->FindKey( chKey ) )
  150. continue; // Already processed that DLC
  151. // Kick off DLC processing
  152. m_dwLicenseMask = 0;
  153. DWORD ret = XContentCreate( XBX_GetPrimaryUserId(), "PKG", pContentData, XCONTENTFLAG_OPENEXISTING, NULL, &m_dwLicenseMask, &m_xOverlapped );
  154. if ( ret && ( ret != ERROR_IO_PENDING ) )
  155. {
  156. Warning( "DLCMANAGER: [%.*s] is corrupt\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName );
  157. continue; // assume corrupt
  158. }
  159. m_eState = STATE_XCONTENT_CREATE;
  160. return;
  161. }
  162. // All done
  163. m_eState = STATE_IDLE;
  164. float flTime = Plat_FloatTime() - m_flTimestamp;
  165. Msg( "DLCMANAGER: Full update finished after %.3f sec\n", flTime );
  166. KeyValuesDumpAsDevMsg( m_pDataInfo, 1 );
  167. }
  168. void CDlcManager::ProcessNextContent()
  169. {
  170. DWORD dwResult = 0;
  171. DWORD ret = XGetOverlappedResult( &m_xOverlapped, &dwResult, false );
  172. if( ret == ERROR_SUCCESS )
  173. {
  174. XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems;
  175. char chKey[ XCONTENT_MAX_FILENAME_LENGTH + 1 ];
  176. memcpy( chKey, pContentData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
  177. chKey[ XCONTENT_MAX_FILENAME_LENGTH ] = 0;
  178. Msg( "DLCMANAGER: [%.*s] has license mask = 0x%08X\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName, m_dwLicenseMask );
  179. if ( !m_pDataInfo )
  180. {
  181. m_pDataInfo = new KeyValues( "DlcManager" );
  182. m_pDataInfo->SetUint64( "@info/installed", 0 );
  183. }
  184. if ( KeyValues *pDlc = m_pDataInfo->FindKey( chKey, true ) )
  185. {
  186. pDlc->SetInt( "licensemask", m_dwLicenseMask );
  187. pDlc->SetWString( "displayname", pContentData->szDisplayName );
  188. pDlc->SetInt( "deviceid", pContentData->DeviceID );
  189. }
  190. m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | ( 1ull << DLC_LICENSE_ID( m_dwLicenseMask ) ) );
  191. m_bNeedToUpdateFileSystem = true;
  192. }
  193. else
  194. {
  195. XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems;
  196. Warning( "DLCMANAGER: [%.*s] async open failed with error %d\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName, ret );
  197. }
  198. XContentClose( "PKG", NULL );
  199. CreateNextContent();
  200. }
  201. #endif
  202. bool CDlcManager::IsDlcUpdateFinished( bool bWaitForFinish )
  203. {
  204. if ( m_eState == STATE_IDLE )
  205. return true;
  206. if ( !bWaitForFinish )
  207. return false;
  208. float flTimestamp = Plat_FloatTime();
  209. while ( m_eState != STATE_IDLE )
  210. {
  211. Update();
  212. ThreadSleep( 1 );
  213. }
  214. float flEndTimestamp = Plat_FloatTime();
  215. Warning( "DLCMANAGER: Forcing wait for update to finish stalled for %.3f sec\n", flEndTimestamp - flTimestamp );
  216. return true;
  217. }
  218. KeyValues * CDlcManager::GetDataInfo()
  219. {
  220. return m_pDataInfo;
  221. }
  222. void CDlcManager::OnEvent( KeyValues *kvEvent )
  223. {
  224. #ifdef _X360
  225. char const *szEvent = kvEvent->GetName();
  226. if ( !Q_stricmp( "OnDowloadableContentInstalled", szEvent ) )
  227. {
  228. m_bNeedToDiscoverAllDlcs = true;
  229. }
  230. else if ( !Q_stricmp( "OnLiveMembershipPurchased", szEvent ) )
  231. {
  232. m_bNeedToDiscoverAllDlcs = true;
  233. }
  234. else if ( !Q_stricmp( "OnSysSigninChange", szEvent ) )
  235. {
  236. m_bNeedToDiscoverAllDlcs = true;
  237. }
  238. #endif
  239. }
  240. #if !defined( NO_STEAM ) && !defined( SWDS )
  241. void CDlcManager::Steam_OnDLCInstalled( DlcInstalled_t *pParam )
  242. {
  243. m_bNeedToDiscoverAllDlcs = false;
  244. TitleDlcDescription_t const *dlcs = g_pMatchFramework->GetMatchTitle()->DescribeTitleDlcs();
  245. if ( !dlcs )
  246. return;
  247. TitleDataFieldsDescription_t const *fields = g_pMatchFramework->GetMatchTitle()->DescribeTitleDataStorage();
  248. uint64 uiOldDlcMask = m_pDataInfo->GetUint64( "@info/installed" );
  249. if ( !m_pDataInfo )
  250. {
  251. m_pDataInfo = new KeyValues( "DlcManager" );
  252. m_pDataInfo->SetUint64( "@info/installed", 0 );
  253. }
  254. IPlayerLocal *pPlayerLocal = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( XBX_GetPrimaryUserId() );
  255. for ( ; dlcs->m_uiLicenseMaskId; ++ dlcs )
  256. {
  257. // Check if DLC already detected
  258. if ( ( uiOldDlcMask & dlcs->m_uiLicenseMaskId ) == dlcs->m_uiLicenseMaskId )
  259. continue;
  260. // Check player profile first
  261. TitleDataFieldsDescription_t const *pDlcField = dlcs->m_szTitleDataBitfieldStatName ?
  262. TitleDataFieldsDescriptionFindByString( fields, dlcs->m_szTitleDataBitfieldStatName ) : NULL;
  263. if ( pDlcField && pPlayerLocal &&
  264. TitleDataFieldsDescriptionGetBit( pDlcField, pPlayerLocal ) )
  265. {
  266. m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | dlcs->m_uiLicenseMaskId );
  267. continue;
  268. }
  269. // Check Steam subscription
  270. if ( steamapicontext->SteamApps()->BIsSubscribedApp( dlcs->m_idDlcAppId ) )
  271. {
  272. m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | dlcs->m_uiLicenseMaskId );
  273. // Set player profile bit
  274. if ( pDlcField && pPlayerLocal )
  275. TitleDataFieldsDescriptionSetBit( pDlcField, pPlayerLocal, true );
  276. }
  277. }
  278. // Send the event in case detected DLC installed changes
  279. uint64 uiNewDlcMask = m_pDataInfo->GetUint64( "@info/installed" );
  280. if ( uiNewDlcMask != uiOldDlcMask )
  281. {
  282. KeyValues *kvEvent = new KeyValues( "OnDowloadableContentInstalled" );
  283. kvEvent->SetUint64( "installed", uiNewDlcMask );
  284. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvEvent );
  285. m_bNeedToUpdateFileSystem = true;
  286. }
  287. }
  288. #endif