|
|
//========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef _X360
#include "xbox/xboxstubs.h"
#endif
#include "mm_framework.h"
#include "filesystem.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
static CDlcManager g_DlcManager; CDlcManager *g_pDlcManager = &g_DlcManager;
CON_COMMAND( mm_dlc_debugprint, "Shows information about dlc" ) { KeyValuesDumpAsDevMsg( g_pDlcManager->GetDataInfo(), 1 ); }
//////////////////////////////////////////////////////////////////////////
CDlcManager::CDlcManager() : m_pDataInfo( NULL ), m_eState( STATE_IDLE ), m_flTimestamp( 0.0f ), m_bNeedToDiscoverAllDlcs( true ), m_bNeedToUpdateFileSystem( false ) { #ifdef _X360
m_hEnumerator = NULL; memset( &m_xOverlapped, 0, sizeof( m_xOverlapped ) ); #endif
}
CDlcManager::~CDlcManager() { if ( m_pDataInfo ) m_pDataInfo->deleteThis(); m_pDataInfo = NULL; }
void CDlcManager::Update() { #ifdef _X360
// Per TCR-126 we don't want to open DLC for users who haven't unlocked the game yet
IXboxSystem *pXboxSystem = g_pMatchExtensions->GetIXboxSystem(); if ( !pXboxSystem || !pXboxSystem->IsArcadeTitleUnlocked() ) { return; }
DWORD ret = 0; switch ( m_eState ) { case STATE_XENUMERATE: if ( !XHasOverlappedIoCompleted( &m_xOverlapped ) ) return;
ret = XGetOverlappedResult( &m_xOverlapped, ( DWORD * ) &m_dwNumItems, false ); if ( ret != ERROR_SUCCESS ) { Warning( "DLCMANAGER: XContentCreateEnumerator/XEnumerate async failed with error %d!\n", ret ); m_dwNumItems = 0; m_bNeedToDiscoverAllDlcs = true; } CloseHandle( m_hEnumerator ); m_hEnumerator = NULL;
CreateNextContent(); return;
case STATE_XCONTENT_CREATE: if ( !XHasOverlappedIoCompleted( &m_xOverlapped ) ) return;
ProcessNextContent(); return; } #endif
// Once we are idle check if we need to update the file systems list of DLC
if ( m_eState == STATE_IDLE ) { if ( m_bNeedToUpdateFileSystem ) { m_bNeedToUpdateFileSystem = false; g_pFullFileSystem->DiscoverDLC( XBX_GetPrimaryUserId() ); } } }
void CDlcManager::RequestDlcUpdate() { if ( m_eState > STATE_IDLE ) return;
if ( m_eState == STATE_IDLE && !m_bNeedToDiscoverAllDlcs ) { Msg( "DLCMANAGER: RequestDlcUpdate has no new content.\n" ); return; } // If we specified dlc via the command line we can skip the actual enumeration
const char *pCmdLine = CommandLine()->GetCmdLine(); if ( V_stristr( pCmdLine, "-dlc" ) ) { m_eState = STATE_IDLE; m_bNeedToUpdateFileSystem = true; m_bNeedToDiscoverAllDlcs = false; return; }
#if !defined( NO_STEAM ) && !defined( SWDS )
// Client is requesting a DLC update
m_CallbackOnDLCInstalled.Register( this, &CDlcManager::Steam_OnDLCInstalled ); Steam_OnDLCInstalled( NULL ); #endif
#ifdef _X360
if ( XBX_GetPrimaryUserIsGuest() ) { Msg( "DLCMANAGER: RequestDlcUpdate will not update for guests.\n" ); return; }
DWORD nBufferSize = 0; DWORD ret = XContentCreateEnumerator( XBX_GetPrimaryUserId(), XCONTENTDEVICE_ANY, XCONTENTTYPE_MARKETPLACE, 0, 100, &nBufferSize, &m_hEnumerator ); if ( ret ) { Warning( "DLCMANAGER: XContentCreateEnumerator failed with error %d!\n", ret ); return; }
if ( nBufferSize ) { m_dwNumItems = 0; m_arrContentData.EnsureCapacity( nBufferSize/sizeof( XCONTENT_DATA ) + 1 ); m_arrContentData.RemoveAll(); ret = XEnumerate( m_hEnumerator, m_arrContentData.Base(), nBufferSize, NULL, &m_xOverlapped ); if ( ret && ret != ERROR_IO_PENDING ) { Warning( "DLCMANAGER: XContentCreateEnumerator/XEnumerate failed with error %d!\n", ret ); } Msg( "DLCMANAGER: XContentCreateEnumerator/XEnumerate initiated.\n" ); m_eState = STATE_XENUMERATE; m_flTimestamp = Plat_FloatTime(); m_bNeedToDiscoverAllDlcs = false; return; }
Warning( "DLCMANAGER: XContentCreateEnumerator not starting enumeration!\n" ); ::CloseHandle( m_hEnumerator ); m_hEnumerator = NULL; #endif
}
#ifdef _X360
void CDlcManager::CreateNextContent() { Msg( "DLCMANAGER: enumeration checkpoint after %.3f sec\n", Plat_FloatTime() - m_flTimestamp ); while ( m_dwNumItems -- > 0 ) { XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems; char chKey[ XCONTENT_MAX_FILENAME_LENGTH + 1 ]; memcpy( chKey, pContentData->szFileName, XCONTENT_MAX_FILENAME_LENGTH ); chKey[ XCONTENT_MAX_FILENAME_LENGTH ] = 0;
if ( m_pDataInfo->FindKey( chKey ) ) continue; // Already processed that DLC
// Kick off DLC processing
m_dwLicenseMask = 0; DWORD ret = XContentCreate( XBX_GetPrimaryUserId(), "PKG", pContentData, XCONTENTFLAG_OPENEXISTING, NULL, &m_dwLicenseMask, &m_xOverlapped ); if ( ret && ( ret != ERROR_IO_PENDING ) ) { Warning( "DLCMANAGER: [%.*s] is corrupt\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName ); continue; // assume corrupt
}
m_eState = STATE_XCONTENT_CREATE; return; }
// All done
m_eState = STATE_IDLE; float flTime = Plat_FloatTime() - m_flTimestamp; Msg( "DLCMANAGER: Full update finished after %.3f sec\n", flTime ); KeyValuesDumpAsDevMsg( m_pDataInfo, 1 ); }
void CDlcManager::ProcessNextContent() { DWORD dwResult = 0; DWORD ret = XGetOverlappedResult( &m_xOverlapped, &dwResult, false ); if( ret == ERROR_SUCCESS ) { XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems; char chKey[ XCONTENT_MAX_FILENAME_LENGTH + 1 ]; memcpy( chKey, pContentData->szFileName, XCONTENT_MAX_FILENAME_LENGTH ); chKey[ XCONTENT_MAX_FILENAME_LENGTH ] = 0;
Msg( "DLCMANAGER: [%.*s] has license mask = 0x%08X\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName, m_dwLicenseMask );
if ( !m_pDataInfo ) { m_pDataInfo = new KeyValues( "DlcManager" ); m_pDataInfo->SetUint64( "@info/installed", 0 ); }
if ( KeyValues *pDlc = m_pDataInfo->FindKey( chKey, true ) ) { pDlc->SetInt( "licensemask", m_dwLicenseMask ); pDlc->SetWString( "displayname", pContentData->szDisplayName ); pDlc->SetInt( "deviceid", pContentData->DeviceID ); }
m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | ( 1ull << DLC_LICENSE_ID( m_dwLicenseMask ) ) ); m_bNeedToUpdateFileSystem = true; } else { XCONTENT_DATA *pContentData = m_arrContentData.Base() + m_dwNumItems; Warning( "DLCMANAGER: [%.*s] async open failed with error %d\n", ARRAYSIZE( pContentData->szFileName ), pContentData->szFileName, ret ); } XContentClose( "PKG", NULL ); CreateNextContent(); } #endif
bool CDlcManager::IsDlcUpdateFinished( bool bWaitForFinish ) { if ( m_eState == STATE_IDLE ) return true; if ( !bWaitForFinish ) return false;
float flTimestamp = Plat_FloatTime(); while ( m_eState != STATE_IDLE ) { Update(); ThreadSleep( 1 ); } float flEndTimestamp = Plat_FloatTime();
Warning( "DLCMANAGER: Forcing wait for update to finish stalled for %.3f sec\n", flEndTimestamp - flTimestamp ); return true; }
KeyValues * CDlcManager::GetDataInfo() { return m_pDataInfo; }
void CDlcManager::OnEvent( KeyValues *kvEvent ) { #ifdef _X360
char const *szEvent = kvEvent->GetName();
if ( !Q_stricmp( "OnDowloadableContentInstalled", szEvent ) ) { m_bNeedToDiscoverAllDlcs = true; } else if ( !Q_stricmp( "OnLiveMembershipPurchased", szEvent ) ) { m_bNeedToDiscoverAllDlcs = true; } else if ( !Q_stricmp( "OnSysSigninChange", szEvent ) ) { m_bNeedToDiscoverAllDlcs = true; } #endif
}
#if !defined( NO_STEAM ) && !defined( SWDS )
void CDlcManager::Steam_OnDLCInstalled( DlcInstalled_t *pParam ) { m_bNeedToDiscoverAllDlcs = false;
TitleDlcDescription_t const *dlcs = g_pMatchFramework->GetMatchTitle()->DescribeTitleDlcs(); if ( !dlcs ) return;
TitleDataFieldsDescription_t const *fields = g_pMatchFramework->GetMatchTitle()->DescribeTitleDataStorage();
uint64 uiOldDlcMask = m_pDataInfo->GetUint64( "@info/installed" ); if ( !m_pDataInfo ) { m_pDataInfo = new KeyValues( "DlcManager" ); m_pDataInfo->SetUint64( "@info/installed", 0 ); } IPlayerLocal *pPlayerLocal = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( XBX_GetPrimaryUserId() ); for ( ; dlcs->m_uiLicenseMaskId; ++ dlcs ) { // Check if DLC already detected
if ( ( uiOldDlcMask & dlcs->m_uiLicenseMaskId ) == dlcs->m_uiLicenseMaskId ) continue;
// Check player profile first
TitleDataFieldsDescription_t const *pDlcField = dlcs->m_szTitleDataBitfieldStatName ? TitleDataFieldsDescriptionFindByString( fields, dlcs->m_szTitleDataBitfieldStatName ) : NULL; if ( pDlcField && pPlayerLocal && TitleDataFieldsDescriptionGetBit( pDlcField, pPlayerLocal ) ) { m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | dlcs->m_uiLicenseMaskId ); continue; }
// Check Steam subscription
if ( steamapicontext->SteamApps()->BIsSubscribedApp( dlcs->m_idDlcAppId ) ) { m_pDataInfo->SetUint64( "@info/installed", m_pDataInfo->GetUint64( "@info/installed" ) | dlcs->m_uiLicenseMaskId );
// Set player profile bit
if ( pDlcField && pPlayerLocal ) TitleDataFieldsDescriptionSetBit( pDlcField, pPlayerLocal, true ); } }
// Send the event in case detected DLC installed changes
uint64 uiNewDlcMask = m_pDataInfo->GetUint64( "@info/installed" ); if ( uiNewDlcMask != uiOldDlcMask ) { KeyValues *kvEvent = new KeyValues( "OnDowloadableContentInstalled" ); kvEvent->SetUint64( "installed", uiNewDlcMask ); g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvEvent ); m_bNeedToUpdateFileSystem = true; } } #endif
|