initial
This commit is contained in:
340
matchmaking/mm_dlc.cpp
Normal file
340
matchmaking/mm_dlc.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
//========= Copyright <20> 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user