summaryrefslogtreecommitdiff
path: root/engine/xboxsystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/xboxsystem.cpp')
-rw-r--r--engine/xboxsystem.cpp1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/engine/xboxsystem.cpp b/engine/xboxsystem.cpp
new file mode 100644
index 0000000..1770aca
--- /dev/null
+++ b/engine/xboxsystem.cpp
@@ -0,0 +1,1081 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Interface to Xbox 360 system functions. Helps deal with the async system and Live
+// functions by either providing a handle for the caller to check results or handling
+// automatic cleanup of the async data when the caller doesn't care about the results.
+//
+//=====================================================================================//
+
+#include "host.h"
+#include "tier3/tier3.h"
+#include "vgui/ILocalize.h"
+#include "ixboxsystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+static wchar_t g_szModSaveContainerDisplayName[XCONTENT_MAX_DISPLAYNAME_LENGTH] = L"";
+static char g_szModSaveContainerName[XCONTENT_MAX_FILENAME_LENGTH] = "";
+
+//-----------------------------------------------------------------------------
+// Implementation of IXboxSystem interface
+//-----------------------------------------------------------------------------
+class CXboxSystem : public IXboxSystem
+{
+public:
+ CXboxSystem( void );
+
+ virtual ~CXboxSystem( void );
+
+ virtual AsyncHandle_t CreateAsyncHandle( void );
+ virtual void ReleaseAsyncHandle( AsyncHandle_t handle );
+ virtual int GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait );
+ virtual void CancelOverlappedOperation( AsyncHandle_t handle );
+
+ // Save/Load
+ virtual void GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName );
+ virtual uint GetContainerRemainingSpace( void );
+ virtual bool DeviceCapacityAdequate( DWORD nDeviceID, const char *pModName );
+ virtual DWORD DiscoverUserData( DWORD nUserID, const char *pModName );
+
+ // XUI
+ virtual bool ShowDeviceSelector( bool bForce, uint *pStorageID, AsyncHandle_t *pHandle );
+ virtual void ShowSigninUI( uint nPanes, uint nFlags );
+
+ // Rich Presence and Matchmaking
+ virtual int UserSetContext( uint nUserIdx, uint nContextID, uint nContextValue, bool bAsync, AsyncHandle_t *pHandle);
+ virtual int UserSetProperty( uint nUserIndex, uint nPropertyId, uint nBytes, const void *pvValue, bool bAsync, AsyncHandle_t *pHandle );
+
+ // Matchmaking
+ virtual int CreateSession( uint nFlags, uint nUserIdx, uint nMaxPublicSlots, uint nMaxPrivateSlots, uint64 *pNonce, void *pSessionInfo, XboxHandle_t *pSessionHandle, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual uint DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL );
+ virtual uint SessionSearch( uint nProcedureIndex, uint nUserIndex, uint nNumResults, uint nNumUsers, uint nNumProperties, uint nNumContexts, XUSER_PROPERTY *pSearchProperties, XUSER_CONTEXT *pSearchContexts, uint *pcbResultsBuffer, XSESSION_SEARCHRESULT_HEADER *pSearchResults, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual uint SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual uint SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlot, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual int SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle );
+
+ // Stats
+ virtual int WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle );
+
+ // Achievements
+ virtual int EnumerateAchievements( uint nUserIdx, uint64 xuid, uint nStartingIdx, uint nCount, void *pBuffer, uint nBufferBytes, bool bAsync, AsyncHandle_t *pAsyncHandle );
+ virtual void AwardAchievement( uint nUserIdx, uint nAchievementId );
+
+ virtual void FinishContainerWrites( void );
+ virtual uint GetContainerOpenResult( void );
+ virtual uint OpenContainers( void );
+ virtual void CloseContainers( void );
+
+private:
+ virtual uint CreateSavegameContainer( uint nCreationFlags );
+ virtual uint CreateUserSettingsContainer( uint nCreationFlags );
+
+ uint m_OpenContainerResult;
+};
+
+static CXboxSystem s_XboxSystem;
+IXboxSystem *g_pXboxSystem = &s_XboxSystem;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CXboxSystem, IXboxSystem, XBOXSYSTEM_INTERFACE_VERSION, s_XboxSystem );
+
+#define ASYNC_RESULT(ph) ((AsyncResult_t*)*ph);
+
+#if defined( _X360 )
+//-----------------------------------------------------------------------------
+// Holds the overlapped object and any persistent data for async system calls
+//-----------------------------------------------------------------------------
+typedef struct AsyncResult_s
+{
+ XOVERLAPPED overlapped;
+ bool bAutoRelease;
+ void *pInputData;
+ AsyncResult_s *pNext;
+} AsyncResult_t;
+
+static AsyncResult_t * g_pAsyncResultHead = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove an AsyncResult_t from the list
+//-----------------------------------------------------------------------------
+static void ReleaseAsyncResult( AsyncResult_t *pAsyncResult )
+{
+ if ( pAsyncResult == g_pAsyncResultHead )
+ {
+ g_pAsyncResultHead = pAsyncResult->pNext;
+ free( pAsyncResult->pInputData );
+ delete pAsyncResult;
+ return;
+ }
+
+ AsyncResult_t *pNode = g_pAsyncResultHead;
+ while ( pNode->pNext )
+ {
+ if ( pNode->pNext == pAsyncResult )
+ {
+ pNode->pNext = pAsyncResult->pNext;
+ free( pAsyncResult->pInputData );
+ delete pAsyncResult;
+ return;
+ }
+ pNode = pNode->pNext;
+ }
+ Warning( "AsyncResult_t not found in ReleaseAsyncResult.\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove an AsyncResult_t from the list
+//-----------------------------------------------------------------------------
+static void ReleaseAsyncResult( XOVERLAPPED *pOverlapped )
+{
+ AsyncResult_t *pResult = g_pAsyncResultHead;
+ while ( pResult )
+ {
+ if ( &pResult->overlapped == pOverlapped )
+ {
+ ReleaseAsyncResult( pResult );
+ return;
+ }
+ }
+ Warning( "XOVERLAPPED couldn't be found in ReleaseAsyncResult.\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Release async results that were marked for auto-release.
+//-----------------------------------------------------------------------------
+static void CleanupFinishedAsyncResults()
+{
+ AsyncResult_t *pResult = g_pAsyncResultHead;
+ AsyncResult_t *pNext;
+ while( pResult )
+ {
+ pNext = pResult->pNext;
+ if ( pResult->bAutoRelease )
+ {
+ if ( XHasOverlappedIoCompleted( &pResult->overlapped ) )
+ {
+ ReleaseAsyncResult( pResult );
+ }
+ }
+ pResult = pNext;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a new AsyncResult_t object to the list
+//-----------------------------------------------------------------------------
+static AsyncResult_t *CreateAsyncResult( bool bAutoRelease )
+{
+ // Take this opportunity to clean up finished operations
+ CleanupFinishedAsyncResults();
+
+ AsyncResult_t *pAsyncResult = new AsyncResult_t;
+ memset( pAsyncResult, 0, sizeof( AsyncResult_t ) );
+
+ pAsyncResult->pNext = g_pAsyncResultHead;
+ g_pAsyncResultHead = pAsyncResult;
+
+ if ( bAutoRelease )
+ {
+ pAsyncResult->bAutoRelease = true;
+ }
+
+ return pAsyncResult;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return an AsyncResult_t object to the pool
+//-----------------------------------------------------------------------------
+static void InitializeAsyncHandle( AsyncHandle_t *pHandle )
+{
+ XOVERLAPPED *pOverlapped = &((AsyncResult_t *)*pHandle)->overlapped;
+ memset( pOverlapped, 0, sizeof( XOVERLAPPED ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize or create and async handle
+//-----------------------------------------------------------------------------
+static AsyncResult_t *InitializeAsyncResult( AsyncHandle_t **ppAsyncHandle )
+{
+ AsyncResult_t *pResult = NULL;
+ if ( *ppAsyncHandle )
+ {
+ InitializeAsyncHandle( *ppAsyncHandle );
+ pResult = ASYNC_RESULT( *ppAsyncHandle );
+ }
+ else
+ {
+ // No handle provided, create one
+ pResult = CreateAsyncResult( true );
+ }
+ return pResult;
+}
+
+CXboxSystem::CXboxSystem( void ) : m_OpenContainerResult( ERROR_SUCCESS )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Force overlapped operations to finish and clean up
+//-----------------------------------------------------------------------------
+CXboxSystem::~CXboxSystem()
+{
+ // Force async operations to finish.
+ AsyncResult_t *pResult = g_pAsyncResultHead;
+ while ( pResult )
+ {
+ AsyncResult_t *pNext = pResult->pNext;
+ GetOverlappedResult( (AsyncHandle_t)pResult, NULL, true );
+ pResult = pNext;
+ }
+
+ // Release any remaining handles - should have been released by the client that created them.
+ int ct = 0;
+ while ( g_pAsyncResultHead )
+ {
+ ReleaseAsyncResult( g_pAsyncResultHead );
+ ++ct;
+ }
+
+ if ( ct )
+ {
+ Warning( "Released %d async handles\n", ct );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check on the result of an overlapped operation
+//-----------------------------------------------------------------------------
+int CXboxSystem::GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait )
+{
+ if ( !handle )
+ return ERROR_INVALID_HANDLE;
+
+ return XGetOverlappedResult( &((AsyncResult_t*)handle)->overlapped, (DWORD*)pResultCode, bWait );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cancel an overlapped operation
+//-----------------------------------------------------------------------------
+void CXboxSystem::CancelOverlappedOperation( AsyncHandle_t handle )
+{
+ XCancelOverlapped( &((AsyncResult_t*)handle)->overlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new AsyncHandle_t
+//-----------------------------------------------------------------------------
+AsyncHandle_t CXboxSystem::CreateAsyncHandle( void )
+{
+ return (AsyncHandle_t)CreateAsyncResult( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete an AsyncHandle_t
+//-----------------------------------------------------------------------------
+void CXboxSystem::ReleaseAsyncHandle( AsyncHandle_t handle )
+{
+ ReleaseAsyncResult( (AsyncResult_t*)handle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Close the open containers
+//-----------------------------------------------------------------------------
+void CXboxSystem::CloseContainers( void )
+{
+ XContentClose( GetCurrentMod(), NULL );
+ XContentClose( XBX_USER_SETTINGS_CONTAINER_DRIVE, NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+uint CXboxSystem::OpenContainers( void )
+{
+ // Close the containers (force dismount)
+ CloseContainers();
+
+ m_OpenContainerResult = ERROR_SUCCESS;
+
+ // Open the save games
+ if ( ( m_OpenContainerResult = CreateUserSettingsContainer( XCONTENTFLAG_OPENALWAYS ) ) != ERROR_SUCCESS )
+ return m_OpenContainerResult;
+
+ // If we're TF, we don't care about save game space
+ if ( !Q_stricmp( GetCurrentMod(), "tf" ) )
+ return m_OpenContainerResult;
+
+ // Open the user settings
+ if ( ( m_OpenContainerResult = CreateSavegameContainer( XCONTENTFLAG_OPENALWAYS ) ) != ERROR_SUCCESS )
+ {
+ CloseContainers();
+ return m_OpenContainerResult;
+ }
+
+ return m_OpenContainerResult;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the results from the last container opening
+//-----------------------------------------------------------------------------
+uint CXboxSystem::GetContainerOpenResult( void )
+{
+ return m_OpenContainerResult;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open the save game container for the current mod
+//-----------------------------------------------------------------------------
+uint CXboxSystem::CreateSavegameContainer( uint nCreationFlags )
+{
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
+ return ERROR_INVALID_HANDLE;
+
+ // Don't allow any of our saves or user data to be transferred to another user
+ nCreationFlags |= XCONTENTFLAG_NOPROFILE_TRANSFER;
+
+ const wchar_t *pchContainerDisplayName;
+ const char *pchContainerName;
+ g_pXboxSystem->GetModSaveContainerNames( GetCurrentMod(), &pchContainerDisplayName, &pchContainerName );
+
+ XCONTENT_DATA contentData;
+ contentData.DeviceID = XBX_GetStorageDeviceId();
+ contentData.dwContentType = XCONTENTTYPE_SAVEDGAME;
+ Q_wcsncpy( contentData.szDisplayName, pchContainerDisplayName, sizeof ( contentData.szDisplayName ) );
+ Q_snprintf( contentData.szFileName, sizeof( contentData.szFileName ), pchContainerName );
+
+ SIZE_T dwFileCacheSize = 0; // Use the smallest size (default)
+ ULARGE_INTEGER ulSize;
+ ulSize.QuadPart = XBX_PERSISTENT_BYTES_NEEDED;
+
+ int nRet = XContentCreateEx( XBX_GetPrimaryUserId(), GetCurrentMod(), &contentData, nCreationFlags, NULL, NULL, dwFileCacheSize, ulSize, NULL );
+ if ( nRet == ERROR_SUCCESS )
+ {
+ BOOL bUserIsCreator = false;
+ XContentGetCreator( XBX_GetPrimaryUserId(), &contentData, &bUserIsCreator, NULL, NULL );
+ if( bUserIsCreator == false )
+ {
+ XContentClose( GetCurrentMod(), NULL );
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ return nRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open the user settings container for the current mod
+//-----------------------------------------------------------------------------
+uint CXboxSystem::CreateUserSettingsContainer( uint nCreationFlags )
+{
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
+ return ERROR_INVALID_HANDLE;
+
+ // Don't allow any of our saves or user data to be transferred to another user
+ nCreationFlags |= XCONTENTFLAG_NOPROFILE_TRANSFER;
+
+ XCONTENT_DATA contentData;
+ contentData.DeviceID = XBX_GetStorageDeviceId();
+ contentData.dwContentType = XCONTENTTYPE_SAVEDGAME;
+ Q_wcsncpy( contentData.szDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_UserSettings" ), sizeof( contentData.szDisplayName ) );
+ Q_snprintf( contentData.szFileName, sizeof( contentData.szFileName ), "UserSettings" );
+
+ SIZE_T dwFileCacheSize = 0; // Use the smallest size (default)
+ ULARGE_INTEGER ulSize;
+ ulSize.QuadPart = XBX_USER_SETTINGS_BYTES;
+
+ int nRet = XContentCreateEx( XBX_GetPrimaryUserId(), XBX_USER_SETTINGS_CONTAINER_DRIVE, &contentData, nCreationFlags, NULL, NULL, dwFileCacheSize, ulSize, NULL );
+ if ( nRet == ERROR_SUCCESS )
+ {
+ BOOL bUserIsCreator = false;
+ XContentGetCreator( XBX_GetPrimaryUserId(), &contentData, &bUserIsCreator, NULL, NULL );
+ if( bUserIsCreator == false )
+ {
+ XContentClose( XBX_USER_SETTINGS_CONTAINER_DRIVE, NULL );
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ return nRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CXboxSystem::FinishContainerWrites( void )
+{
+ // Finish all writes
+ XContentFlush( GetCurrentMod(), NULL );
+ XContentFlush( XBX_USER_SETTINGS_CONTAINER_DRIVE, NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieve the names used for our save game container
+// Input : *pchModName - Name of the mod we're running (tf, hl2, etc)
+// **ppchDisplayName - Display name that will be presented to users by the console
+// **ppchName - Filename of the container
+//-----------------------------------------------------------------------------
+void CXboxSystem::GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName )
+{
+ // If the strings haven't been setup
+ if ( g_szModSaveContainerDisplayName[ 0 ] == '\0' )
+ {
+ if ( Q_stricmp( pchModName, "episodic" ) == 0 )
+ {
+ Q_wcsncpy( g_szModSaveContainerDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_Ep1_Saves" ), sizeof( g_szModSaveContainerDisplayName ) );
+ }
+ else if ( Q_stricmp( pchModName, "ep2" ) == 0 )
+ {
+ Q_wcsncpy( g_szModSaveContainerDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_Ep2_Saves" ), sizeof( g_szModSaveContainerDisplayName ) );
+ }
+ else if ( Q_stricmp( pchModName, "portal" ) == 0 )
+ {
+ Q_wcsncpy( g_szModSaveContainerDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_Portal_Saves" ), sizeof( g_szModSaveContainerDisplayName ) );
+ }
+ else if ( Q_stricmp( pchModName, "tf" ) == 0 )
+ {
+ Q_wcsncpy( g_szModSaveContainerDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_TF2_Saves" ), sizeof( g_szModSaveContainerDisplayName ) );
+ }
+ else
+ {
+ Q_wcsncpy( g_szModSaveContainerDisplayName, g_pVGuiLocalize->Find( "#GameUI_Console_HL2_Saves" ), sizeof( g_szModSaveContainerDisplayName ) );
+ }
+
+ // Create a filename with the format "mod_saves"
+ Q_snprintf( g_szModSaveContainerName, sizeof( g_szModSaveContainerName ), "%s_saves", pchModName );
+ }
+
+ // Return pointers to these internally kept strings
+ *ppchDisplayName = g_szModSaveContainerDisplayName;
+ *ppchName = g_szModSaveContainerName;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Search the device and find out if we have adequate space to start a game
+// Input : nStorageID - Device to check
+// *pModName - Name of the mod we want to check for
+//-----------------------------------------------------------------------------
+bool CXboxSystem::DeviceCapacityAdequate( DWORD nStorageID, const char *pModName )
+{
+ // If we don't have a valid user id, we can't poll the device
+ if ( XBX_GetPrimaryUserId() == XBX_INVALID_USER_ID )
+ return false;
+
+ // Must be a valid storage device to poll
+ if ( nStorageID == XBX_INVALID_STORAGE_ID )
+ return false;
+
+ // Get the actual amount on the drive
+ XDEVICE_DATA deviceData;
+ if ( XContentGetDeviceData( nStorageID, &deviceData ) != ERROR_SUCCESS )
+ return false;
+
+ const ULONGLONG nSaveGameSize = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED, 1 );
+ const ULONGLONG nUserSettingsSize = XContentCalculateSize( XBX_USER_SETTINGS_BYTES, 1 );
+ bool bIsTF2 = ( !Q_stricmp( pModName, "tf" ) );
+ ULONGLONG nTotalSpaceNeeded = ( bIsTF2 ) ? nUserSettingsSize : ( nSaveGameSize + nUserSettingsSize );
+ ULONGLONG nAvailableSpace = deviceData.ulDeviceFreeBytes; // Take the first device's free space to compare this against
+
+ // If they've already got enough space, early out
+ if ( nAvailableSpace >= nTotalSpaceNeeded )
+ return true;
+
+ const int nNumItemsToRetrieve = 1;
+ const int fContentFlags = XCONTENTFLAG_ENUM_EXCLUDECOMMON;
+
+ // Save for queries against the storage devices
+ const wchar_t *pchContainerDisplayName;
+ const char *pchContainerName;
+ GetModSaveContainerNames( pModName, &pchContainerDisplayName, &pchContainerName );
+
+ // Look for a user settings block for all products
+ DWORD nBufferSize;
+ HANDLE hEnumerator;
+ if ( XContentCreateEnumerator( XBX_GetPrimaryUserId(),
+ nStorageID,
+ XCONTENTTYPE_SAVEDGAME,
+ fContentFlags,
+ nNumItemsToRetrieve,
+ &nBufferSize,
+ &hEnumerator ) == ERROR_SUCCESS )
+ {
+ // Allocate a buffer of the correct size
+ BYTE *pBuffer = new BYTE[nBufferSize];
+ if ( pBuffer == NULL )
+ return XBX_INVALID_STORAGE_ID;
+
+ char szFilename[XCONTENT_MAX_FILENAME_LENGTH+1];
+ szFilename[XCONTENT_MAX_FILENAME_LENGTH] = 0;
+ XCONTENT_DATA *pData = NULL;
+
+ // Step through all items, looking for ones we care about
+ DWORD nNumItems;
+ while ( XEnumerate( hEnumerator, pBuffer, nBufferSize, &nNumItems, NULL ) == ERROR_SUCCESS )
+ {
+ // Grab the item in question
+ pData = (XCONTENT_DATA *) pBuffer;
+
+ // Safely store this away (null-termination is not guaranteed by the API!)
+ memcpy( szFilename, pData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
+
+ // See if this is our user settings file
+ if ( !Q_stricmp( szFilename, "UserSettings" ) )
+ {
+ nTotalSpaceNeeded -= nUserSettingsSize;
+ }
+ else if ( bIsTF2 == false && !Q_stricmp( szFilename, pchContainerName ) )
+ {
+ nTotalSpaceNeeded -= nSaveGameSize;
+ }
+ }
+
+ // Clean up
+ delete[] pBuffer;
+ CloseHandle( hEnumerator );
+ }
+
+ // Finally, check its complete size
+ if ( nTotalSpaceNeeded <= nAvailableSpace )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Enumerate all devices and search for game data already present. If only one device has it, we return it
+// Input : nUserID - User whose data we're searching for
+// *pModName - Name of the mod we're searching for
+// Output : Device ID which contains our data (-1 if no data was found, or data resided on multiple devices)
+//-----------------------------------------------------------------------------
+DWORD CXboxSystem::DiscoverUserData( DWORD nUserID, const char *pModName )
+{
+ // If we're entering this function without a storage device, then we must pop the UI anyway to choose it!
+ Assert( nUserID != XBX_INVALID_USER_ID );
+ if ( nUserID == XBX_INVALID_USER_ID )
+ return XBX_INVALID_STORAGE_ID;
+
+ const int nNumItemsToRetrieve = 1;
+ const int fContentFlags = XCONTENTFLAG_ENUM_EXCLUDECOMMON;
+ DWORD nFoundDevice = XBX_INVALID_STORAGE_ID;
+
+ // Save for queries against the storage devices
+ const wchar_t *pchContainerDisplayName;
+ const char *pchContainerName;
+ GetModSaveContainerNames( pModName, &pchContainerDisplayName, &pchContainerName );
+
+ const ULONGLONG nSaveGameSize = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED, 1 );
+ const ULONGLONG nUserSettingsSize = XContentCalculateSize( XBX_USER_SETTINGS_BYTES, 1 );
+ ULONGLONG nTotalSpaceNeeded = ( nSaveGameSize + nUserSettingsSize );
+ ULONGLONG nAvailableSpace = 0; // Take the first device's free space to compare this against
+
+ // Look for a user settings block for all products
+ DWORD nBufferSize;
+ HANDLE hEnumerator;
+ if ( XContentCreateEnumerator( nUserID,
+ XCONTENTDEVICE_ANY, // All devices we know about
+ XCONTENTTYPE_SAVEDGAME,
+ fContentFlags,
+ nNumItemsToRetrieve,
+ &nBufferSize,
+ &hEnumerator ) == ERROR_SUCCESS )
+ {
+ // Allocate a buffer of the correct size
+ BYTE *pBuffer = new BYTE[nBufferSize];
+ if ( pBuffer == NULL )
+ return XBX_INVALID_STORAGE_ID;
+
+ char szFilename[XCONTENT_MAX_FILENAME_LENGTH+1];
+ szFilename[XCONTENT_MAX_FILENAME_LENGTH] = 0;
+ XCONTENT_DATA *pData = NULL;
+
+ // Step through all items, looking for ones we care about
+ DWORD nNumItems;
+ while ( XEnumerate( hEnumerator, pBuffer, nBufferSize, &nNumItems, NULL ) == ERROR_SUCCESS )
+ {
+ // Grab the item in question
+ pData = (XCONTENT_DATA *) pBuffer;
+
+ // If they have multiple devices installed, then we must ask
+ if ( nFoundDevice != XBX_INVALID_STORAGE_ID && nFoundDevice != pData->DeviceID )
+ {
+ // Clean up
+ delete[] pBuffer;
+ CloseHandle( hEnumerator );
+
+ return XBX_INVALID_STORAGE_ID;
+ }
+
+ // Hold on to this device ID
+ if ( nFoundDevice != pData->DeviceID )
+ {
+ nFoundDevice = pData->DeviceID;
+
+ XDEVICE_DATA deviceData;
+ if ( XContentGetDeviceData( nFoundDevice, &deviceData ) != ERROR_SUCCESS )
+ continue;
+
+ nAvailableSpace = deviceData.ulDeviceFreeBytes;
+ }
+
+ // Safely store this away (null-termination is not guaranteed by the API!)
+ memcpy( szFilename, pData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
+
+ // See if this is our user settings file
+ if ( !Q_stricmp( szFilename, "UserSettings" ) )
+ {
+ nTotalSpaceNeeded -= nUserSettingsSize;
+ }
+ else if ( !Q_stricmp( szFilename, pchContainerName ) )
+ {
+ nTotalSpaceNeeded -= nSaveGameSize;
+ }
+ }
+
+ // Clean up
+ delete[] pBuffer;
+ CloseHandle( hEnumerator );
+ }
+
+ // If we found nothing, then give up
+ if ( nFoundDevice == XBX_INVALID_STORAGE_ID )
+ return nFoundDevice;
+
+ // Finally, check its complete size
+ if ( nTotalSpaceNeeded <= nAvailableSpace )
+ return nFoundDevice;
+
+ return XBX_INVALID_STORAGE_ID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Space free on the current device
+//-----------------------------------------------------------------------------
+uint CXboxSystem::GetContainerRemainingSpace( void )
+{
+ XDEVICE_DATA deviceData;
+ if ( XContentGetDeviceData( XBX_GetStorageDeviceId(), &deviceData ) != ERROR_SUCCESS )
+ return 0;
+
+ return deviceData.ulDeviceFreeBytes;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Show the storage device selector
+//-----------------------------------------------------------------------------
+bool CXboxSystem::ShowDeviceSelector( bool bForce, uint *pStorageID, AsyncHandle_t *pAsyncHandle )
+{
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+
+ // We validate the size outside of this because we want to look inside our packages to see what's really free
+ ULARGE_INTEGER bytes;
+ bytes.QuadPart = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED + XBX_USER_SETTINGS_BYTES, 1 );
+
+ DWORD showFlags = bForce ? XCONTENTFLAG_FORCE_SHOW_UI : 0;
+ showFlags |= XCONTENTFLAG_MANAGESTORAGE;
+
+ DWORD ret = XShowDeviceSelectorUI( XBX_GetPrimaryUserId(),
+ XCONTENTTYPE_SAVEDGAME,
+ showFlags,
+ bytes,
+ (DWORD*) pStorageID,
+ &pResult->overlapped
+ );
+
+ if ( ret != ERROR_IO_PENDING )
+ {
+ Msg( "Error showing device Selector UI\n" );
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Show the user sign in screen
+//-----------------------------------------------------------------------------
+void CXboxSystem::ShowSigninUI( uint nPanes, uint nFlags )
+{
+ XShowSigninUI( nPanes, nFlags );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set a user context
+//-----------------------------------------------------------------------------
+int CXboxSystem::UserSetContext( uint nUserIdx, uint nContextID, uint nContextValue, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XUserSetContextEx( nUserIdx, nContextID, nContextValue, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set a user property
+//-----------------------------------------------------------------------------
+int CXboxSystem::UserSetProperty( uint nUserIndex, uint nPropertyId, uint nBytes, const void *pvValue, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+ const void *pData = pvValue;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+
+ if ( nBytes && pvValue )
+ {
+ pResult->pInputData = malloc( nBytes );
+ memcpy( pResult->pInputData, pvValue, nBytes );
+ }
+ else
+ {
+ nBytes = 0;
+ }
+
+ pOverlapped = &pResult->overlapped;
+ pData = pResult->pInputData;
+ }
+
+ return XUserSetPropertyEx( nUserIndex, nPropertyId, nBytes, pData, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a matchmaking session
+//-----------------------------------------------------------------------------
+int CXboxSystem::CreateSession( uint nFlags,
+ uint nUserIdx,
+ uint nMaxPublicSlots,
+ uint nMaxPrivateSlots,
+ uint64 *pNonce,
+ void *pSessionInfo,
+ XboxHandle_t *pSessionHandle,
+ bool bAsync,
+ AsyncHandle_t *pAsyncHandle
+ )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ // Create the session
+ return XSessionCreate( nFlags, nUserIdx, nMaxPublicSlots, nMaxPrivateSlots, pNonce, (XSESSION_INFO*)pSessionInfo, pOverlapped, pSessionHandle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy a matchmaking session
+//-----------------------------------------------------------------------------
+uint CXboxSystem::DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ // Delete the session
+ uint ret = XSessionDelete( hSession, pOverlapped );
+ CloseHandle( hSession );
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a matchmaking session
+//-----------------------------------------------------------------------------
+uint CXboxSystem::SessionSearch( uint nProcedureIndex,
+ uint nUserIndex,
+ uint nNumResults,
+ uint nNumUsers,
+ uint nNumProperties,
+ uint nNumContexts,
+ XUSER_PROPERTY *pSearchProperties,
+ XUSER_CONTEXT *pSearchContexts,
+ uint *pcbResultsBuffer,
+ XSESSION_SEARCHRESULT_HEADER *pSearchResults,
+ bool bAsync,
+ AsyncHandle_t *pAsyncHandle
+ )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ // Search for the session
+ return XSessionSearchEx( nProcedureIndex, nUserIndex, nNumResults, nNumUsers, nNumProperties, nNumContexts, pSearchProperties, pSearchContexts, (DWORD*)pcbResultsBuffer, pSearchResults, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Starting a multiplayer game
+//-----------------------------------------------------------------------------
+uint CXboxSystem::SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionStart( hSession, nFlags, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finished a multiplayer game
+//-----------------------------------------------------------------------------
+uint CXboxSystem::SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionEnd( hSession, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Join local users to a session
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionJoinLocal( hSession, nUserCount, (DWORD*)pUserIndexes, (BOOL*)pPrivateSlots, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Join remote users to a session
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionJoinRemote( hSession, nUserCount, pXuids, (BOOL*)pPrivateSlots, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove local users from a session
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionLeaveLocal( hSession, nUserCount, (DWORD*)pUserIndexes, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove remote users from a session
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionLeaveRemote( hSession, nUserCount, pXuids, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Migrate a session to a new host
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionMigrateHost( hSession, nUserIndex, (XSESSION_INFO*)pSessionInfo, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Register for arbitration
+//-----------------------------------------------------------------------------
+int CXboxSystem::SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionArbitrationRegister( hSession, nFlags, nonce, (DWORD*)pBytes, (XSESSION_REGISTRATION_RESULTS*)pBuffer, pOverlapped );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Upload player stats to Xbox Live
+//-----------------------------------------------------------------------------
+int CXboxSystem::WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle )
+{
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ return XSessionWriteStats( hSession, xuid, nViews, (XSESSION_VIEW_PROPERTIES*)pViews, pOverlapped );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Enumerate a player's achievements
+//-----------------------------------------------------------------------------
+int CXboxSystem::EnumerateAchievements( uint nUserIdx,
+ uint64 xuid,
+ uint nStartingIdx,
+ uint nCount,
+ void *pBuffer,
+ uint nBufferBytes,
+ bool bAsync,
+ AsyncHandle_t *pAsyncHandle
+ )
+{
+ HANDLE hEnumerator = INVALID_HANDLE_VALUE;
+ DWORD ret = XUserCreateAchievementEnumerator( 0, nUserIdx, xuid, XACHIEVEMENT_DETAILS_ALL, nStartingIdx, nCount, (DWORD*)pBuffer, &hEnumerator );
+
+ // Just looking for the buffer size needed
+ if ( ret != ERROR_SUCCESS || nBufferBytes == 0 )
+ {
+ CloseHandle( hEnumerator );
+ return ret;
+ }
+
+ if ( nBufferBytes < *(uint*)pBuffer )
+ {
+ Warning( "EnumerateAchievements: Buffer provided not large enough to hold results" );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ XOVERLAPPED *pOverlapped = NULL;
+
+ if ( bAsync )
+ {
+ AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
+ pOverlapped = &pResult->overlapped;
+ }
+
+ DWORD items;
+ ret = XEnumerate( hEnumerator, pBuffer, nBufferBytes, &items, pOverlapped );
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "XEnumerate failed in EnumerateAchievements.\n" );
+ }
+ CloseHandle( hEnumerator );
+
+ return items;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Award an achievement to the current user
+//-----------------------------------------------------------------------------
+void CXboxSystem::AwardAchievement( uint nUserIdx, uint nAchievementId )
+{
+ AsyncResult_t *pResult = CreateAsyncResult( true );
+
+ XUSER_ACHIEVEMENT ach;
+ ach.dwUserIndex = nUserIdx;
+ ach.dwAchievementId = nAchievementId;
+
+ pResult->pInputData = malloc( sizeof( ach ) );
+ Q_memcpy( pResult->pInputData, &ach, sizeof( ach ) );
+
+ DWORD ret = XUserWriteAchievements( 1, (XUSER_ACHIEVEMENT*)pResult->pInputData, &pResult->overlapped );
+ if ( ret != ERROR_IO_PENDING )
+ {
+ Warning( "XUserWriteAchievments failed.\n" );
+ }
+}
+
+#else
+
+// Stubbed interface for win32
+CXboxSystem::~CXboxSystem( void ) {}
+CXboxSystem::CXboxSystem( void ) {}
+AsyncHandle_t CXboxSystem::CreateAsyncHandle( void ) { return NULL; }
+void CXboxSystem::ReleaseAsyncHandle( AsyncHandle_t handle ) {}
+int CXboxSystem::GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait ) { return 0; }
+void CXboxSystem::CancelOverlappedOperation( AsyncHandle_t handle ) {};
+void CXboxSystem::GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName )
+{
+ *ppchDisplayName = g_szModSaveContainerDisplayName;
+ *ppchName = g_szModSaveContainerName;
+}
+DWORD CXboxSystem::DiscoverUserData( DWORD nUserID, const char *pModName ) { return ((DWORD)-1); }
+bool CXboxSystem::DeviceCapacityAdequate( DWORD nDeviceID, const char *pModName ) { return true; }
+uint CXboxSystem::GetContainerRemainingSpace( void ) { return 0; }
+bool CXboxSystem::ShowDeviceSelector( bool bForce, uint *pStorageID, AsyncHandle_t *pHandle ) { return false; }
+void CXboxSystem::ShowSigninUI( uint nPanes, uint nFlags ) {}
+int CXboxSystem::UserSetContext( uint nUserIdx, uint nContextID, uint nContextValue, bool bAsync, AsyncHandle_t *pHandle) { return 0; }
+int CXboxSystem::UserSetProperty( uint nUserIndex, uint nPropertyId, uint nBytes, const void *pvValue, bool bAsync, AsyncHandle_t *pHandle ) { return 0; }
+int CXboxSystem::CreateSession( uint nFlags, uint nUserIdx, uint nMaxPublicSlots, uint nMaxPrivateSlots, uint64 *pNonce, void *pSessionInfo, XboxHandle_t *pSessionHandle, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+uint CXboxSystem::DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+uint CXboxSystem::SessionSearch( uint nProcedureIndex, uint nUserIndex, uint nNumResults, uint nNumUsers, uint nNumProperties, uint nNumContexts, XUSER_PROPERTY *pSearchProperties, XUSER_CONTEXT *pSearchContexts, uint *pcbResultsBuffer, XSESSION_SEARCHRESULT_HEADER *pSearchResults, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+uint CXboxSystem::SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; };
+uint CXboxSystem::SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; };
+int CXboxSystem::SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlot, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+int CXboxSystem::EnumerateAchievements( uint nUserIdx, uint64 xuid, uint nStartingIdx, uint nCount, void *pBuffer, uint nBufferBytes, bool bAsync, AsyncHandle_t *pAsyncHandle ) { return 0; }
+void CXboxSystem::AwardAchievement( uint nUserIdx, uint nAchievementId ) {}
+void CXboxSystem::FinishContainerWrites( void ) {}
+uint CXboxSystem::GetContainerOpenResult( void ) { return 0; }
+uint CXboxSystem::OpenContainers( void ) { return 0; }
+void CXboxSystem::CloseContainers( void ) {}
+uint CXboxSystem::CreateSavegameContainer( uint nCreationFlags ) { return 0; }
+uint CXboxSystem::CreateUserSettingsContainer( uint nCreationFlags ) { return 0; }
+
+#endif // defined _X360