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.
1081 lines
41 KiB
1081 lines
41 KiB
//========= 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
|
|
|