Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2557 lines
75 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Interface to Xbox 360 system functions. Helps deal with the async system and Live
  4. // functions by either providing a handle for the caller to check results or handling
  5. // automatic cleanup of the async data when the caller doesn't care about the results.
  6. //
  7. //=====================================================================================//
  8. #include "host.h"
  9. #include "tier3/tier3.h"
  10. #include "vgui/ILocalize.h"
  11. #include "ixboxsystem.h"
  12. #ifdef IS_WINDOWS_PC
  13. #include "winerror.h"
  14. #endif
  15. #ifdef _X360
  16. #include <xparty.h>
  17. #endif
  18. #include "vstdlib/random.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. static wchar_t g_szModSaveContainerDisplayName[XCONTENT_MAX_DISPLAYNAME_LENGTH] = L"";
  22. static char g_szModSaveContainerName[XCONTENT_MAX_FILENAME_LENGTH] = "";
  23. #define XBX_USER_SETTINGS_CONTAINER_ENABLED 1
  24. #if !defined( CSTRIKE_TRIAL_MODE )
  25. #if defined( _CERT ) && defined( _X360 )
  26. # define CSTRIKE_TRIAL_MODE 1
  27. #else
  28. # define CSTRIKE_TRIAL_MODE 0
  29. #endif
  30. #endif
  31. //-----------------------------------------------------------------------------
  32. // Implementation of IXboxSystem interface
  33. //-----------------------------------------------------------------------------
  34. class CXboxSystem : public IXboxSystem
  35. {
  36. public:
  37. CXboxSystem( void );
  38. virtual ~CXboxSystem( void );
  39. virtual AsyncHandle_t CreateAsyncHandle( void );
  40. virtual void ReleaseAsyncHandle( AsyncHandle_t handle );
  41. virtual int GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait );
  42. virtual void CancelOverlappedOperation( AsyncHandle_t handle );
  43. // Save/Load
  44. virtual bool GameHasSavegames( void );
  45. virtual void GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName );
  46. virtual uint GetContainerRemainingSpace( DWORD nDeviceID );
  47. virtual bool DeviceCapacityAdequate( int iController, DWORD nDeviceID, const char *pModName );
  48. virtual DWORD DiscoverUserData( DWORD nUserID, const char *pModName );
  49. // XUI
  50. virtual bool ShowDeviceSelector( int iController, bool bForce, uint *pStorageID, AsyncHandle_t *pHandle );
  51. virtual void ShowSigninUI( uint nPanes, uint nFlags );
  52. // Rich Presence and Matchmaking
  53. virtual int UserSetContext( uint nUserIdx, XUSER_CONTEXT const &xc, bool bAsync, AsyncHandle_t *pHandle);
  54. virtual int UserSetProperty( uint nUserIndex, XUSER_PROPERTY const &xp, bool bAsync, AsyncHandle_t *pHandle );
  55. virtual int UserGetContext( uint nUserIdx, uint nContextID, uint &nContextValue);
  56. virtual int UserGetPropertyInt( uint nUserIndex, uint nPropertyId, uint &nPropertyValue);
  57. // Matchmaking
  58. virtual int CreateSession( uint nFlags, uint nUserIdx, uint nMaxPublicSlots, uint nMaxPrivateSlots, uint64 *pNonce, void *pSessionInfo, XboxHandle_t *pSessionHandle, bool bAsync, AsyncHandle_t *pAsyncHandle );
  59. virtual uint DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL );
  60. 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 );
  61. virtual uint SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle );
  62. virtual uint SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle );
  63. virtual int SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle );
  64. virtual int SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlot, bool bAsync, AsyncHandle_t *pAsyncHandle );
  65. virtual int SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle );
  66. virtual int SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle );
  67. virtual int SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle );
  68. virtual int SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle );
  69. // Friends
  70. virtual int EnumerateFriends( uint userIndex, void **pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle = NULL );
  71. // Stats
  72. virtual int WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle );
  73. virtual int FlushStats( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle );
  74. virtual int EnumerateStatsByRank( uint nStartingRank, uint nNumRows, uint nNumSpecs, void *pSpecs, void **ppResults, bool bAsync, AsyncHandle_t *pAsyncHandle );
  75. virtual int EnumerateStatsByXuid( XUID nUserId, uint nNumRows, uint nNumSpecs, void *pSpecs, void **ppResults, bool bAsync, AsyncHandle_t *pAsyncHandle );
  76. // Achievements
  77. virtual int EnumerateAchievements( uint nUserIdx, uint64 xuid, uint nStartingIdx, uint nCount, void *pBuffer, uint nBufferBytes, bool bAsync, AsyncHandle_t *pAsyncHandle );
  78. virtual int AwardAchievement( uint nUserIdx, uint nAchievementId, AsyncHandle_t *ppOverlappedResult );
  79. virtual int AwardAvatarAsset( uint nUserIdx, uint nAwardId, AsyncHandle_t *ppOverlappedResult );
  80. // Arcade titles
  81. virtual void ShowUnlockFullGameUI( void );
  82. virtual bool UpdateArcadeTitleUnlockStatus( void );
  83. virtual bool IsArcadeTitleUnlocked( void );
  84. virtual float GetArcadeRemainingTrialTime( int nSlot = 0 );
  85. virtual void FinishContainerWrites( int iController );
  86. virtual uint GetContainerOpenResult( int iController );
  87. virtual uint OpenContainers( int iController );
  88. virtual void CloseContainers( int iController );
  89. virtual void FinishAllContainerWrites( void );
  90. virtual void CloseAllContainers( void );
  91. //
  92. // Overlapped
  93. //
  94. virtual int Io_HasOverlappedIoCompleted( XOVERLAPPED *pOverlapped );
  95. //
  96. // XNet
  97. //
  98. virtual int NetRandom( byte *pb, unsigned numBytes );
  99. virtual DWORD NetGetTitleXnAddr( XNADDR *pxna );
  100. virtual int NetXnAddrToMachineId( const XNADDR *pxnaddr, uint64 *pqwMachineId );
  101. virtual int NetInAddrToXnAddr( const IN_ADDR ina, XNADDR *pxna, XNKID *pxnkid );
  102. virtual int NetXnAddrToInAddr( const XNADDR *pxna, const XNKID *pxnkid, IN_ADDR *pina );
  103. //
  104. // User
  105. //
  106. virtual XUSER_SIGNIN_STATE UserGetSigninState( int iCtrlr );
  107. private:
  108. virtual uint CreateSavegameContainer( int iController, uint nCreationFlags );
  109. virtual uint CreateUserSettingsContainer( int iController, uint nCreationFlags );
  110. uint m_OpenContainerResult[ 4 ];
  111. };
  112. static CXboxSystem s_XboxSystem;
  113. IXboxSystem *g_pXboxSystem = &s_XboxSystem;
  114. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CXboxSystem, IXboxSystem, XBOXSYSTEM_INTERFACE_VERSION, s_XboxSystem );
  115. #define ASYNC_RESULT(ph) ((AsyncResult_t*)*ph);
  116. //-----------------------------------------------------------------------------
  117. // Holds the overlapped object and any persistent data for async system calls
  118. //-----------------------------------------------------------------------------
  119. typedef struct AsyncResult_s
  120. {
  121. XOVERLAPPED overlapped;
  122. bool bAutoRelease;
  123. void *pInputData;
  124. AsyncResult_s *pNext;
  125. } AsyncResult_t;
  126. static AsyncResult_t * g_pAsyncResultHead = NULL;
  127. //-----------------------------------------------------------------------------
  128. // Purpose: Remove an AsyncResult_t from the list
  129. //-----------------------------------------------------------------------------
  130. static void ReleaseAsyncResult( AsyncResult_t *pAsyncResult )
  131. {
  132. if ( pAsyncResult == g_pAsyncResultHead )
  133. {
  134. g_pAsyncResultHead = pAsyncResult->pNext;
  135. free( pAsyncResult->pInputData );
  136. delete pAsyncResult;
  137. return;
  138. }
  139. AsyncResult_t *pNode = g_pAsyncResultHead;
  140. while ( pNode->pNext )
  141. {
  142. if ( pNode->pNext == pAsyncResult )
  143. {
  144. pNode->pNext = pAsyncResult->pNext;
  145. free( pAsyncResult->pInputData );
  146. delete pAsyncResult;
  147. return;
  148. }
  149. pNode = pNode->pNext;
  150. }
  151. Warning( "AsyncResult_t not found in ReleaseAsyncResult.\n" );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Remove an AsyncResult_t from the list
  155. //-----------------------------------------------------------------------------
  156. static void ReleaseAsyncResult( XOVERLAPPED *pOverlapped )
  157. {
  158. AsyncResult_t *pResult = g_pAsyncResultHead;
  159. while ( pResult )
  160. {
  161. if ( &pResult->overlapped == pOverlapped )
  162. {
  163. ReleaseAsyncResult( pResult );
  164. return;
  165. }
  166. }
  167. Warning( "XOVERLAPPED couldn't be found in ReleaseAsyncResult.\n" );
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose: Release async results that were marked for auto-release.
  171. //-----------------------------------------------------------------------------
  172. static void CleanupFinishedAsyncResults()
  173. {
  174. AsyncResult_t *pResult = g_pAsyncResultHead;
  175. AsyncResult_t *pNext;
  176. while( pResult )
  177. {
  178. pNext = pResult->pNext;
  179. if ( pResult->bAutoRelease )
  180. {
  181. #ifdef _X360
  182. bool bCompleted = XHasOverlappedIoCompleted( &pResult->overlapped );
  183. #else
  184. bool bCompleted = true;
  185. #endif
  186. if ( bCompleted )
  187. {
  188. ReleaseAsyncResult( pResult );
  189. }
  190. }
  191. pResult = pNext;
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: Add a new AsyncResult_t object to the list
  196. //-----------------------------------------------------------------------------
  197. static AsyncResult_t *CreateAsyncResult( bool bAutoRelease )
  198. {
  199. // Take this opportunity to clean up finished operations
  200. CleanupFinishedAsyncResults();
  201. AsyncResult_t *pAsyncResult = new AsyncResult_t;
  202. memset( pAsyncResult, 0, sizeof( AsyncResult_t ) );
  203. pAsyncResult->pNext = g_pAsyncResultHead;
  204. g_pAsyncResultHead = pAsyncResult;
  205. if ( bAutoRelease )
  206. {
  207. pAsyncResult->bAutoRelease = true;
  208. }
  209. return pAsyncResult;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: Return an AsyncResult_t object to the pool
  213. //-----------------------------------------------------------------------------
  214. static void InitializeAsyncHandle( AsyncHandle_t *pHandle )
  215. {
  216. XOVERLAPPED *pOverlapped = &((AsyncResult_t *)*pHandle)->overlapped;
  217. memset( pOverlapped, 0, sizeof( XOVERLAPPED ) );
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose: Initialize or create and async handle
  221. //-----------------------------------------------------------------------------
  222. static AsyncResult_t *InitializeAsyncResult( AsyncHandle_t **ppAsyncHandle )
  223. {
  224. AsyncResult_t *pResult = NULL;
  225. if ( *ppAsyncHandle )
  226. {
  227. InitializeAsyncHandle( *ppAsyncHandle );
  228. pResult = ASYNC_RESULT( *ppAsyncHandle );
  229. }
  230. else
  231. {
  232. // No handle provided, create one
  233. pResult = CreateAsyncResult( true );
  234. }
  235. return pResult;
  236. }
  237. CXboxSystem::CXboxSystem( void )
  238. {
  239. memset( m_OpenContainerResult, 0, sizeof( m_OpenContainerResult ) );
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose: Force overlapped operations to finish and clean up
  243. //-----------------------------------------------------------------------------
  244. CXboxSystem::~CXboxSystem()
  245. {
  246. // Force async operations to finish.
  247. AsyncResult_t *pResult = g_pAsyncResultHead;
  248. while ( pResult )
  249. {
  250. AsyncResult_t *pNext = pResult->pNext;
  251. GetOverlappedResult( (AsyncHandle_t)pResult, NULL, true );
  252. pResult = pNext;
  253. }
  254. // Release any remaining handles - should have been released by the client that created them.
  255. int ct = 0;
  256. while ( g_pAsyncResultHead )
  257. {
  258. ReleaseAsyncResult( g_pAsyncResultHead );
  259. ++ct;
  260. }
  261. if ( ct )
  262. {
  263. Warning( "Released %d async handles\n", ct );
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose: Check on the result of an overlapped operation
  268. //-----------------------------------------------------------------------------
  269. int CXboxSystem::GetOverlappedResult( AsyncHandle_t handle, uint *pResultCode, bool bWait )
  270. {
  271. #ifdef _X360
  272. if ( !handle )
  273. return ERROR_INVALID_HANDLE;
  274. return XGetOverlappedResult( &((AsyncResult_t*)handle)->overlapped, (DWORD*)pResultCode, bWait );
  275. #else
  276. if ( pResultCode )
  277. *pResultCode = ERROR_SUCCESS;
  278. return ERROR_SUCCESS;
  279. #endif
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Cancel an overlapped operation
  283. //-----------------------------------------------------------------------------
  284. void CXboxSystem::CancelOverlappedOperation( AsyncHandle_t handle )
  285. {
  286. #ifdef _X360
  287. XCancelOverlapped( &((AsyncResult_t*)handle)->overlapped );
  288. #else
  289. (void) 0;
  290. #endif
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose: Create a new AsyncHandle_t
  294. //-----------------------------------------------------------------------------
  295. AsyncHandle_t CXboxSystem::CreateAsyncHandle( void )
  296. {
  297. #ifdef _X360
  298. return (AsyncHandle_t)CreateAsyncResult( false );
  299. #else
  300. return NULL;
  301. #endif
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose: Delete an AsyncHandle_t
  305. //-----------------------------------------------------------------------------
  306. void CXboxSystem::ReleaseAsyncHandle( AsyncHandle_t handle )
  307. {
  308. #ifdef _X360
  309. ReleaseAsyncResult( (AsyncResult_t*)handle );
  310. #else
  311. (void) 0;
  312. #endif
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose: Close the open containers
  316. //-----------------------------------------------------------------------------
  317. void CXboxSystem::CloseContainers( int iController )
  318. {
  319. #ifdef _X360
  320. char szRootName[XCONTENT_MAX_FILENAME_LENGTH];
  321. DWORD ret = 0;
  322. XBX_MakeStorageContainerRoot( iController, XBX_USER_SAVES_CONTAINER_DRIVE, szRootName, XCONTENT_MAX_FILENAME_LENGTH );
  323. ret = XContentClose( szRootName, NULL );
  324. DevMsg( "XContentClose( %s ) = 0x%08X\n", szRootName, ret );
  325. #if XBX_USER_SETTINGS_CONTAINER_ENABLED
  326. XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, szRootName, XCONTENT_MAX_FILENAME_LENGTH );
  327. ret = XContentClose( szRootName, NULL );
  328. DevMsg( "XContentClose( %s ) = 0x%08X\n", szRootName, ret );
  329. #endif
  330. #else
  331. #endif
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose: Close all open containers
  335. //-----------------------------------------------------------------------------
  336. void CXboxSystem::CloseAllContainers( void )
  337. {
  338. for ( DWORD k = 0; k < XUSER_MAX_COUNT; ++ k )
  339. CloseContainers( k );
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose:
  343. //-----------------------------------------------------------------------------
  344. uint CXboxSystem::OpenContainers( int iController )
  345. {
  346. #ifdef _X360
  347. if ( iController < 0 || iController >= XUSER_MAX_COUNT )
  348. return ERROR_NO_SUCH_USER;
  349. if ( UserGetSigninState( iController ) == eXUserSigninState_NotSignedIn )
  350. return ERROR_NO_SUCH_PRIVILEGE;
  351. // Close the containers (force dismount)
  352. CloseContainers( iController );
  353. m_OpenContainerResult[ iController ] = ERROR_SUCCESS;
  354. // Open the save games
  355. if ( ( m_OpenContainerResult[ iController ] =
  356. CreateUserSettingsContainer( iController, XCONTENTFLAG_OPENALWAYS ) )
  357. != ERROR_SUCCESS )
  358. return m_OpenContainerResult[ iController ];
  359. // If we don't care about save game space
  360. if ( !GameHasSavegames() )
  361. return m_OpenContainerResult[ iController ];
  362. // Open the user settings
  363. if ( ( m_OpenContainerResult[ iController ] =
  364. CreateSavegameContainer( iController, XCONTENTFLAG_OPENALWAYS ) )
  365. != ERROR_SUCCESS )
  366. {
  367. CloseContainers( iController );
  368. return m_OpenContainerResult[ iController ];
  369. }
  370. #else
  371. m_OpenContainerResult[ iController ] = ERROR_SUCCESS;
  372. #endif
  373. return m_OpenContainerResult[ iController ];
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Purpose: Returns the results from the last container opening
  377. //-----------------------------------------------------------------------------
  378. uint CXboxSystem::GetContainerOpenResult( int iController )
  379. {
  380. #ifdef _X360
  381. if ( iController < 0 || iController >= XUSER_MAX_COUNT )
  382. return ERROR_NO_SUCH_USER;
  383. if ( UserGetSigninState( iController ) == eXUserSigninState_NotSignedIn )
  384. return ERROR_NO_SUCH_PRIVILEGE;
  385. #else
  386. m_OpenContainerResult[ iController ] = ERROR_SUCCESS;
  387. #endif
  388. return m_OpenContainerResult[ iController ];
  389. }
  390. #ifdef _X360
  391. uint XHelper_CreateContainer( int iController, uint nCreationFlags, XCONTENT_DATA &contentData, uint64 uiBytesNeeded, char const *szContainerRoot )
  392. {
  393. if ( iController < 0 || iController >= XUSER_MAX_COUNT )
  394. return ERROR_NO_SUCH_USER;
  395. DWORD dwStorageDevice = XBX_GetStorageDeviceId( iController );
  396. if ( !XBX_DescribeStorageDevice( dwStorageDevice ) )
  397. return ERROR_INVALID_HANDLE;
  398. // Don't allow any of our saves or user data to be transferred to another user
  399. nCreationFlags |= XCONTENTFLAG_NOPROFILE_TRANSFER;
  400. contentData.DeviceID = dwStorageDevice;
  401. contentData.dwContentType = XCONTENTTYPE_SAVEDGAME;
  402. SIZE_T dwFileCacheSize = 0; // Use the smallest size (default)
  403. ULARGE_INTEGER ulSize;
  404. ulSize.QuadPart = uiBytesNeeded;
  405. char szRootName[XCONTENT_MAX_FILENAME_LENGTH];
  406. XBX_MakeStorageContainerRoot( iController, szContainerRoot, szRootName, XCONTENT_MAX_FILENAME_LENGTH );
  407. int nRet = ERROR_SUCCESS;
  408. bool bFound = false;
  409. if ( ( nCreationFlags & XCONTENTFLAG_OPENALWAYS ) == XCONTENTFLAG_OPENALWAYS )
  410. {
  411. uint nTestingFlag = ( nCreationFlags & ~XCONTENTFLAG_OPENALWAYS ) | XCONTENTFLAG_OPENEXISTING;
  412. nRet = XContentCreateEx( iController, szRootName, &contentData, nTestingFlag, NULL, NULL, dwFileCacheSize, ulSize, NULL );
  413. if ( nRet == ERROR_SUCCESS )
  414. {
  415. bFound = true;
  416. }
  417. }
  418. if ( !bFound && nRet != ERROR_FILE_CORRUPT )
  419. {
  420. nRet = XContentCreateEx( iController, szRootName, &contentData, nCreationFlags, NULL, NULL, dwFileCacheSize, ulSize, NULL );
  421. }
  422. if ( nRet == ERROR_SUCCESS )
  423. {
  424. BOOL bUserIsCreator = false;
  425. XContentGetCreator( iController, &contentData, &bUserIsCreator, NULL, NULL );
  426. if( bUserIsCreator == false )
  427. {
  428. XContentClose( szRootName, NULL );
  429. return ERROR_ACCESS_DENIED;
  430. }
  431. DevMsg( "XContentCreateEx( %s ): %s for %d\n", szRootName, contentData.szFileName, iController );
  432. }
  433. return nRet;
  434. }
  435. #endif
  436. //-----------------------------------------------------------------------------
  437. // Purpose: Open the save game container for the current mod
  438. //-----------------------------------------------------------------------------
  439. uint CXboxSystem::CreateSavegameContainer( int iController, uint nCreationFlags )
  440. {
  441. #ifdef _X360
  442. const wchar_t *pchContainerDisplayName;
  443. const char *pchContainerName;
  444. g_pXboxSystem->GetModSaveContainerNames( GetCurrentMod(), &pchContainerDisplayName, &pchContainerName );
  445. XCONTENT_DATA contentData;
  446. memset( &contentData, 0, sizeof( contentData ) );
  447. Q_wcsncpy( contentData.szDisplayName, pchContainerDisplayName, sizeof ( contentData.szDisplayName ) );
  448. Q_snprintf( contentData.szFileName, sizeof( contentData.szFileName ), pchContainerName );
  449. return XHelper_CreateContainer( iController, nCreationFlags, contentData, XBX_PERSISTENT_BYTES_NEEDED, XBX_USER_SAVES_CONTAINER_DRIVE );
  450. #else
  451. return ERROR_SUCCESS;
  452. #endif
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Purpose: Open the user settings container for the current mod
  456. //-----------------------------------------------------------------------------
  457. uint CXboxSystem::CreateUserSettingsContainer( int iController, uint nCreationFlags )
  458. {
  459. #ifdef _X360
  460. #if XBX_USER_SETTINGS_CONTAINER_ENABLED
  461. XCONTENT_DATA contentData;
  462. memset( &contentData, 0, sizeof( contentData ) );
  463. Q_wcsncpy( contentData.szDisplayName, g_pVGuiLocalize->FindSafe( "#GameUI_Console_UserSettings" ), sizeof( contentData.szDisplayName ) );
  464. Q_snprintf( contentData.szFileName, sizeof( contentData.szFileName ), "UserSettings" );
  465. return XHelper_CreateContainer( iController, nCreationFlags, contentData, XBX_USER_SETTINGS_BYTES, XBX_USER_SETTINGS_CONTAINER_DRIVE );
  466. #else
  467. return ERROR_SUCCESS;
  468. #endif
  469. #else
  470. return ERROR_SUCCESS;
  471. #endif
  472. }
  473. #ifdef _GAMECONSOLE
  474. ConVar host_write_last_time( "host_write_last_time", "0", FCVAR_DEVELOPMENTONLY );
  475. #endif
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. void CXboxSystem::FinishContainerWrites( int iController )
  480. {
  481. #ifdef _X360
  482. char szRootName[XCONTENT_MAX_FILENAME_LENGTH];
  483. XBX_MakeStorageContainerRoot( iController, XBX_USER_SAVES_CONTAINER_DRIVE, szRootName, XCONTENT_MAX_FILENAME_LENGTH );
  484. XContentFlush( szRootName, NULL );
  485. #ifdef XBX_USER_SETTINGS_CONTAINER_ENABLED
  486. XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, szRootName, XCONTENT_MAX_FILENAME_LENGTH );
  487. XContentFlush( szRootName, NULL );
  488. #endif
  489. static ConVarRef host_write_last_time( "host_write_last_time" );
  490. float flTimeSinceLastWrite = Plat_FloatTime() - host_write_last_time.GetFloat();
  491. if ( flTimeSinceLastWrite < 3.0f )
  492. {
  493. DevWarning( "CXboxSystem::FinishContainerWrites when only %.2f sec elapsed after last write!\n", flTimeSinceLastWrite );
  494. }
  495. host_write_last_time.SetValue( ( float ) Plat_FloatTime() );
  496. #else
  497. #endif
  498. }
  499. void CXboxSystem::FinishAllContainerWrites( void )
  500. {
  501. for ( DWORD k = 0; k < XUSER_MAX_COUNT; ++ k )
  502. FinishContainerWrites( k );
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Purpose: Determine if game has savegame containers
  506. //-----------------------------------------------------------------------------
  507. bool CXboxSystem::GameHasSavegames( void )
  508. {
  509. static bool s_bInitialized = false;
  510. static bool s_bHasSavegames = true;
  511. #ifdef _GAMECONSOLE
  512. if ( XBX_GetNumGameUsers() != 1 )
  513. return false;
  514. if ( XBX_GetPrimaryUserIsGuest() )
  515. return false;
  516. #endif
  517. if ( !s_bInitialized )
  518. {
  519. const char *pszMod = GetCurrentMod();
  520. if ( !Q_stricmp( pszMod, "left4dead2" ) )
  521. s_bHasSavegames = false;
  522. else if ( !Q_stricmp( pszMod, "tf" ) )
  523. s_bHasSavegames = false;
  524. s_bInitialized = true;
  525. }
  526. return s_bHasSavegames;
  527. }
  528. //-----------------------------------------------------------------------------
  529. // Purpose: Retrieve the names used for our save game container
  530. // Input : *pchModName - Name of the mod we're running (tf, hl2, etc)
  531. // **ppchDisplayName - Display name that will be presented to users by the console
  532. // **ppchName - Filename of the container
  533. //-----------------------------------------------------------------------------
  534. void CXboxSystem::GetModSaveContainerNames( const char *pchModName, const wchar_t **ppchDisplayName, const char **ppchName )
  535. {
  536. // If the strings haven't been setup
  537. if ( g_szModSaveContainerDisplayName[ 0 ] == '\0' )
  538. {
  539. char chFmtString[256] = {0};
  540. Q_snprintf( chFmtString, sizeof( chFmtString ), "#GameUI_Console_%s_Saves", pchModName );
  541. wchar_t const *wszLocStr = g_pVGuiLocalize->Find( chFmtString );
  542. if ( !wszLocStr || !*wszLocStr )
  543. wszLocStr = g_pVGuiLocalize->Find( "#GameUI_Console_SaveGames" );
  544. if ( !wszLocStr || !*wszLocStr )
  545. wszLocStr = L"SAVES";
  546. Q_wcsncpy( g_szModSaveContainerDisplayName, wszLocStr, sizeof( g_szModSaveContainerDisplayName ) );
  547. // Create a filename with the format "mod_saves"
  548. Q_snprintf( g_szModSaveContainerName, sizeof( g_szModSaveContainerName ), "%s_saves", pchModName );
  549. }
  550. // Return pointers to these internally kept strings
  551. *ppchDisplayName = g_szModSaveContainerDisplayName;
  552. *ppchName = g_szModSaveContainerName;
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose: Search the device and find out if we have adequate space to start a game
  556. // Input : nStorageID - Device to check
  557. // *pModName - Name of the mod we want to check for
  558. //-----------------------------------------------------------------------------
  559. bool CXboxSystem::DeviceCapacityAdequate( int iController, DWORD nStorageID, const char *pModName )
  560. {
  561. #ifdef _X360
  562. // If we don't have a valid user id, we can't poll the device
  563. if ( iController == XBX_INVALID_USER_ID )
  564. return false;
  565. if ( XUserGetSigninState( iController ) == eXUserSigninState_NotSignedIn )
  566. return XBX_INVALID_STORAGE_ID;
  567. // Must be a valid storage device to poll
  568. if ( !XBX_DescribeStorageDevice( nStorageID ) )
  569. return false;
  570. // Get the actual amount on the drive
  571. XDEVICE_DATA deviceData;
  572. if ( XContentGetDeviceData( nStorageID, &deviceData ) != ERROR_SUCCESS )
  573. return false;
  574. const ULONGLONG nSaveGameSize = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED, 1 );
  575. const ULONGLONG nUserSettingsSize = XContentCalculateSize( XBX_USER_SETTINGS_BYTES, 1 );
  576. bool bHasSaves = GameHasSavegames();
  577. ULONGLONG nTotalSpaceNeeded = ( !bHasSaves ) ? nUserSettingsSize : ( nSaveGameSize + nUserSettingsSize );
  578. ULONGLONG nAvailableSpace = deviceData.ulDeviceFreeBytes; // Take the first device's free space to compare this against
  579. // If they've already got enough space, early out
  580. if ( nAvailableSpace >= nTotalSpaceNeeded )
  581. return true;
  582. const int nNumItemsToRetrieve = 1;
  583. const int fContentFlags = XCONTENTFLAG_ENUM_EXCLUDECOMMON;
  584. // Save for queries against the storage devices
  585. const wchar_t *pchContainerDisplayName;
  586. const char *pchContainerName;
  587. GetModSaveContainerNames( pModName, &pchContainerDisplayName, &pchContainerName );
  588. // Look for a user settings block for all products
  589. DWORD nBufferSize;
  590. HANDLE hEnumerator;
  591. if ( XContentCreateEnumerator( iController,
  592. nStorageID,
  593. XCONTENTTYPE_SAVEDGAME,
  594. fContentFlags,
  595. nNumItemsToRetrieve,
  596. &nBufferSize,
  597. &hEnumerator ) == ERROR_SUCCESS )
  598. {
  599. // Allocate a buffer of the correct size
  600. BYTE *pBuffer = new BYTE[nBufferSize];
  601. if ( pBuffer == NULL )
  602. return XBX_INVALID_STORAGE_ID;
  603. char szFilename[XCONTENT_MAX_FILENAME_LENGTH+1];
  604. szFilename[XCONTENT_MAX_FILENAME_LENGTH] = 0;
  605. XCONTENT_DATA *pData = NULL;
  606. // Step through all items, looking for ones we care about
  607. DWORD nNumItems;
  608. while ( XEnumerate( hEnumerator, pBuffer, nBufferSize, &nNumItems, NULL ) == ERROR_SUCCESS )
  609. {
  610. // Grab the item in question
  611. pData = (XCONTENT_DATA *) pBuffer;
  612. // Safely store this away (null-termination is not guaranteed by the API!)
  613. memcpy( szFilename, pData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
  614. // See if this is our user settings file
  615. if ( !Q_stricmp( szFilename, "UserSettings" ) )
  616. {
  617. nTotalSpaceNeeded -= nUserSettingsSize;
  618. }
  619. else if ( bHasSaves && !Q_stricmp( szFilename, pchContainerName ) )
  620. {
  621. nTotalSpaceNeeded -= nSaveGameSize;
  622. }
  623. }
  624. // Clean up
  625. delete[] pBuffer;
  626. CloseHandle( hEnumerator );
  627. }
  628. // Finally, check its complete size
  629. if ( nTotalSpaceNeeded <= nAvailableSpace )
  630. return true;
  631. return false;
  632. #else
  633. return true;
  634. #endif
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Enumerate all devices and search for game data already present. If only one device has it, we return it
  638. // Input : nUserID - User whose data we're searching for
  639. // *pModName - Name of the mod we're searching for
  640. // Output : Device ID which contains our data (-1 if no data was found, or data resided on multiple devices)
  641. //-----------------------------------------------------------------------------
  642. DWORD CXboxSystem::DiscoverUserData( DWORD nUserID, const char *pModName )
  643. {
  644. #ifdef _X360
  645. // If we're entering this function without a storage device, then we must pop the UI anyway to choose it!
  646. Assert( nUserID != XBX_INVALID_USER_ID );
  647. if ( nUserID == XBX_INVALID_USER_ID )
  648. return XBX_INVALID_STORAGE_ID;
  649. if ( XUserGetSigninState( nUserID ) == eXUserSigninState_NotSignedIn )
  650. return XBX_INVALID_STORAGE_ID;
  651. const int nNumItemsToRetrieve = 1;
  652. const int fContentFlags = XCONTENTFLAG_ENUM_EXCLUDECOMMON;
  653. DWORD nFoundDevice = XBX_INVALID_STORAGE_ID;
  654. // Save for queries against the storage devices
  655. const wchar_t *pchContainerDisplayName;
  656. const char *pchContainerName;
  657. GetModSaveContainerNames( pModName, &pchContainerDisplayName, &pchContainerName );
  658. const ULONGLONG nSaveGameSize = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED, 1 );
  659. const ULONGLONG nUserSettingsSize = XContentCalculateSize( XBX_USER_SETTINGS_BYTES, 1 );
  660. bool bHasSaves = GameHasSavegames();
  661. ULONGLONG nTotalSpaceNeeded = ( !bHasSaves ) ? nUserSettingsSize : ( nSaveGameSize + nUserSettingsSize );
  662. ULONGLONG nAvailableSpace = 0; // Take the first device's free space to compare this against
  663. // Look for a user settings block for all products
  664. DWORD nBufferSize;
  665. HANDLE hEnumerator;
  666. if ( XContentCreateEnumerator( nUserID,
  667. XCONTENTDEVICE_ANY, // All devices we know about
  668. XCONTENTTYPE_SAVEDGAME,
  669. fContentFlags,
  670. nNumItemsToRetrieve,
  671. &nBufferSize,
  672. &hEnumerator ) == ERROR_SUCCESS )
  673. {
  674. // Allocate a buffer of the correct size
  675. BYTE *pBuffer = new BYTE[nBufferSize];
  676. if ( pBuffer == NULL )
  677. return XBX_INVALID_STORAGE_ID;
  678. char szFilename[XCONTENT_MAX_FILENAME_LENGTH+1];
  679. szFilename[XCONTENT_MAX_FILENAME_LENGTH] = 0;
  680. XCONTENT_DATA *pData = NULL;
  681. // Step through all items, looking for ones we care about
  682. DWORD nNumItems;
  683. while ( XEnumerate( hEnumerator, pBuffer, nBufferSize, &nNumItems, NULL ) == ERROR_SUCCESS )
  684. {
  685. // Grab the item in question
  686. pData = (XCONTENT_DATA *) pBuffer;
  687. // If they have multiple devices installed, then we must ask
  688. if ( nFoundDevice != XBX_INVALID_STORAGE_ID && nFoundDevice != pData->DeviceID )
  689. {
  690. // Clean up
  691. delete[] pBuffer;
  692. CloseHandle( hEnumerator );
  693. return XBX_INVALID_STORAGE_ID;
  694. }
  695. // Hold on to this device ID
  696. if ( nFoundDevice != pData->DeviceID )
  697. {
  698. nFoundDevice = pData->DeviceID;
  699. XDEVICE_DATA deviceData;
  700. if ( XContentGetDeviceData( nFoundDevice, &deviceData ) != ERROR_SUCCESS )
  701. continue;
  702. nAvailableSpace = deviceData.ulDeviceFreeBytes;
  703. }
  704. // Safely store this away (null-termination is not guaranteed by the API!)
  705. memcpy( szFilename, pData->szFileName, XCONTENT_MAX_FILENAME_LENGTH );
  706. // See if this is our user settings file
  707. if ( !Q_stricmp( szFilename, "UserSettings" ) )
  708. {
  709. nTotalSpaceNeeded -= nUserSettingsSize;
  710. }
  711. else if ( bHasSaves && !Q_stricmp( szFilename, pchContainerName ) )
  712. {
  713. nTotalSpaceNeeded -= nSaveGameSize;
  714. }
  715. }
  716. // Clean up
  717. delete[] pBuffer;
  718. CloseHandle( hEnumerator );
  719. }
  720. // If we found nothing, then give up
  721. if ( nFoundDevice == XBX_INVALID_STORAGE_ID )
  722. return nFoundDevice;
  723. // Finally, check its complete size
  724. if ( nTotalSpaceNeeded <= nAvailableSpace )
  725. return nFoundDevice;
  726. return XBX_INVALID_STORAGE_ID;
  727. #else
  728. return XBX_INVALID_STORAGE_ID;
  729. #endif
  730. }
  731. //-----------------------------------------------------------------------------
  732. // Purpose: Space free on the current device
  733. //-----------------------------------------------------------------------------
  734. uint CXboxSystem::GetContainerRemainingSpace( DWORD nStorageID )
  735. {
  736. #ifdef _X360
  737. XDEVICE_DATA deviceData;
  738. if ( XContentGetDeviceData( nStorageID, &deviceData ) != ERROR_SUCCESS )
  739. return 0;
  740. return deviceData.ulDeviceFreeBytes;
  741. #else
  742. return 1024*1024*1024; // 1 Gb
  743. #endif
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Purpose: Show the storage device selector
  747. //-----------------------------------------------------------------------------
  748. bool CXboxSystem::ShowDeviceSelector( int iController, bool bForce, uint *pStorageID, AsyncHandle_t *pAsyncHandle )
  749. {
  750. #ifdef _X360
  751. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  752. // We validate the size outside of this because we want to look inside our packages to see what's really free
  753. ULARGE_INTEGER bytes;
  754. bytes.QuadPart = XContentCalculateSize( XBX_PERSISTENT_BYTES_NEEDED + XBX_USER_SETTINGS_BYTES, 1 );
  755. DWORD showFlags = bForce ? XCONTENTFLAG_FORCE_SHOW_UI : 0;
  756. showFlags |= XCONTENTFLAG_MANAGESTORAGE;
  757. DWORD ret = XShowDeviceSelectorUI( iController,
  758. XCONTENTTYPE_SAVEDGAME,
  759. showFlags,
  760. bytes,
  761. (DWORD*) pStorageID,
  762. &pResult->overlapped
  763. );
  764. if ( ret != ERROR_IO_PENDING )
  765. {
  766. Msg( "Error showing device Selector UI\n" );
  767. return false;
  768. }
  769. return true;
  770. #else
  771. return false;
  772. #endif
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Purpose: Show the user sign in screen
  776. //-----------------------------------------------------------------------------
  777. void CXboxSystem::ShowSigninUI( uint nPanes, uint nFlags )
  778. {
  779. #ifdef _X360
  780. XShowSigninUI( nPanes, nFlags );
  781. #else
  782. #endif
  783. }
  784. //-----------------------------------------------------------------------------
  785. // Purpose: Set a user context
  786. //-----------------------------------------------------------------------------
  787. int CXboxSystem::UserSetContext( uint nUserIdx, XUSER_CONTEXT const &xc, bool bAsync, AsyncHandle_t *pAsyncHandle )
  788. {
  789. #ifdef _X360
  790. XOVERLAPPED *pOverlapped = NULL;
  791. if ( bAsync )
  792. {
  793. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  794. pOverlapped = &pResult->overlapped;
  795. }
  796. return XUserSetContextEx( nUserIdx, xc.dwContextId, xc.dwValue, pOverlapped );
  797. #else
  798. return 0;
  799. #endif
  800. }
  801. //-----------------------------------------------------------------------------
  802. // Purpose: Set a user property
  803. //-----------------------------------------------------------------------------
  804. int CXboxSystem::UserSetProperty( uint nUserIndex, XUSER_PROPERTY const &xp, bool bAsync, AsyncHandle_t *pAsyncHandle )
  805. {
  806. #ifdef _X360
  807. XOVERLAPPED *pOverlapped = NULL;
  808. int nBytes = 0;
  809. void const *pvData = NULL;
  810. switch ( xp.value.type )
  811. {
  812. case XUSER_DATA_TYPE_INT32:
  813. nBytes = sizeof( xp.value.nData );
  814. pvData = &xp.value.nData;
  815. break;
  816. case XUSER_DATA_TYPE_INT64:
  817. nBytes = sizeof( xp.value.i64Data );
  818. pvData = &xp.value.i64Data;
  819. break;
  820. case XUSER_DATA_TYPE_DOUBLE:
  821. nBytes = sizeof( xp.value.dblData );
  822. pvData = &xp.value.dblData;
  823. break;
  824. case XUSER_DATA_TYPE_UNICODE:
  825. nBytes = xp.value.string.cbData;
  826. pvData = xp.value.string.pwszData;
  827. break;
  828. case XUSER_DATA_TYPE_FLOAT:
  829. nBytes = sizeof( xp.value.fData );
  830. pvData = &xp.value.fData;
  831. break;
  832. case XUSER_DATA_TYPE_BINARY:
  833. nBytes = xp.value.binary.cbData;
  834. pvData = xp.value.binary.pbData;
  835. break;
  836. default:
  837. Warning( "UserSetProperty for unsupported property type %d!\n", xp.value.type );
  838. break;
  839. }
  840. if ( bAsync )
  841. {
  842. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  843. if ( nBytes && pvData )
  844. {
  845. pResult->pInputData = malloc( nBytes );
  846. memcpy( pResult->pInputData, pvData, nBytes );
  847. }
  848. else
  849. {
  850. nBytes = 0;
  851. }
  852. pOverlapped = &pResult->overlapped;
  853. pvData = pResult->pInputData;
  854. }
  855. return XUserSetPropertyEx( nUserIndex, xp.dwPropertyId, nBytes, pvData, pOverlapped );
  856. #else
  857. return 0;
  858. #endif
  859. }
  860. //-----------------------------------------------------------------------------
  861. // Purpose: Get a user context
  862. //-----------------------------------------------------------------------------
  863. int CXboxSystem::UserGetContext( uint nUserIdx, uint nContextID, uint &nContextValue)
  864. {
  865. #ifdef _X360
  866. XUSER_CONTEXT context;
  867. context.dwContextId = nContextID;
  868. context.dwValue = 0;
  869. int retValue = XUserGetContext(nUserIdx,&context,NULL);
  870. nContextValue = context.dwValue;
  871. return retValue;
  872. #else
  873. return 0;
  874. #endif
  875. };
  876. int CXboxSystem::UserGetPropertyInt( uint nUserIndex, uint nPropertyId, uint &nPropertyValue)
  877. {
  878. #ifdef _X360
  879. XUSER_PROPERTY prop;
  880. prop.dwPropertyId = nPropertyId;
  881. prop.value.nData = 0;
  882. DWORD size = sizeof(XUSER_PROPERTY);
  883. int retVal = XUserGetProperty(nUserIndex,&size,&prop,NULL);
  884. nPropertyValue = prop.value.nData;
  885. return retVal;
  886. #else
  887. return 0;
  888. #endif
  889. }
  890. //-----------------------------------------------------------------------------
  891. // Purpose: Create a matchmaking session
  892. //-----------------------------------------------------------------------------
  893. int CXboxSystem::CreateSession( uint nFlags,
  894. uint nUserIdx,
  895. uint nMaxPublicSlots,
  896. uint nMaxPrivateSlots,
  897. uint64 *pNonce,
  898. void *pSessionInfo,
  899. XboxHandle_t *pSessionHandle,
  900. bool bAsync,
  901. AsyncHandle_t *pAsyncHandle
  902. )
  903. {
  904. #ifdef _X360
  905. XOVERLAPPED *pOverlapped = NULL;
  906. if ( bAsync )
  907. {
  908. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  909. pOverlapped = &pResult->overlapped;
  910. }
  911. // Create the session
  912. return XSessionCreate( nFlags, nUserIdx, nMaxPublicSlots, nMaxPrivateSlots, pNonce, (XSESSION_INFO*)pSessionInfo, pOverlapped, pSessionHandle );
  913. #else
  914. return ERROR_ACCESS_DISABLED_BY_POLICY;
  915. #endif
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Purpose: Destroy a matchmaking session
  919. //-----------------------------------------------------------------------------
  920. uint CXboxSystem::DeleteSession( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle )
  921. {
  922. #ifdef _X360
  923. XOVERLAPPED *pOverlapped = NULL;
  924. if ( bAsync )
  925. {
  926. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  927. pOverlapped = &pResult->overlapped;
  928. }
  929. // Delete the session
  930. uint ret = XSessionDelete( hSession, pOverlapped );
  931. CloseHandle( hSession );
  932. return ret;
  933. #else
  934. return ERROR_ACCESS_DISABLED_BY_POLICY;
  935. #endif
  936. }
  937. //-----------------------------------------------------------------------------
  938. // Purpose: Create a matchmaking session
  939. //-----------------------------------------------------------------------------
  940. uint CXboxSystem::SessionSearch( uint nProcedureIndex,
  941. uint nUserIndex,
  942. uint nNumResults,
  943. uint nNumUsers,
  944. uint nNumProperties,
  945. uint nNumContexts,
  946. XUSER_PROPERTY *pSearchProperties,
  947. XUSER_CONTEXT *pSearchContexts,
  948. uint *pcbResultsBuffer,
  949. XSESSION_SEARCHRESULT_HEADER *pSearchResults,
  950. bool bAsync,
  951. AsyncHandle_t *pAsyncHandle
  952. )
  953. {
  954. #ifdef _X360
  955. XOVERLAPPED *pOverlapped = NULL;
  956. if ( bAsync )
  957. {
  958. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  959. pOverlapped = &pResult->overlapped;
  960. }
  961. // Search for the session
  962. return XSessionSearchEx( nProcedureIndex, nUserIndex, nNumResults, nNumUsers, nNumProperties, nNumContexts, pSearchProperties, pSearchContexts, (DWORD*)pcbResultsBuffer, pSearchResults, pOverlapped );
  963. #else
  964. return ERROR_ACCESS_DISABLED_BY_POLICY;
  965. #endif
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose: Starting a multiplayer game
  969. //-----------------------------------------------------------------------------
  970. uint CXboxSystem::SessionStart( XboxHandle_t hSession, uint nFlags, bool bAsync, AsyncHandle_t *pAsyncHandle )
  971. {
  972. #ifdef _X360
  973. XOVERLAPPED *pOverlapped = NULL;
  974. if ( bAsync )
  975. {
  976. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  977. pOverlapped = &pResult->overlapped;
  978. }
  979. return XSessionStart( hSession, nFlags, pOverlapped );
  980. #else
  981. return ERROR_ACCESS_DISABLED_BY_POLICY;
  982. #endif
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose: Finished a multiplayer game
  986. //-----------------------------------------------------------------------------
  987. uint CXboxSystem::SessionEnd( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle )
  988. {
  989. #ifdef _X360
  990. XOVERLAPPED *pOverlapped = NULL;
  991. if ( bAsync )
  992. {
  993. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  994. pOverlapped = &pResult->overlapped;
  995. }
  996. return XSessionEnd( hSession, pOverlapped );
  997. #else
  998. return ERROR_ACCESS_DISABLED_BY_POLICY;
  999. #endif
  1000. }
  1001. //-----------------------------------------------------------------------------
  1002. // Purpose: Join local users to a session
  1003. //-----------------------------------------------------------------------------
  1004. int CXboxSystem::SessionJoinLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1005. {
  1006. #ifdef _X360
  1007. XOVERLAPPED *pOverlapped = NULL;
  1008. if ( bAsync )
  1009. {
  1010. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1011. pOverlapped = &pResult->overlapped;
  1012. }
  1013. return XSessionJoinLocal( hSession, nUserCount, (DWORD*)pUserIndexes, (BOOL*)pPrivateSlots, pOverlapped );
  1014. #else
  1015. return ERROR_SUCCESS;
  1016. #endif
  1017. }
  1018. //-----------------------------------------------------------------------------
  1019. // Purpose: Join remote users to a session
  1020. //-----------------------------------------------------------------------------
  1021. int CXboxSystem::SessionJoinRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, const bool *pPrivateSlots, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1022. {
  1023. #ifdef _X360
  1024. XOVERLAPPED *pOverlapped = NULL;
  1025. if ( bAsync )
  1026. {
  1027. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1028. pOverlapped = &pResult->overlapped;
  1029. }
  1030. return XSessionJoinRemote( hSession, nUserCount, pXuids, (BOOL*)pPrivateSlots, pOverlapped );
  1031. #else
  1032. return ERROR_SUCCESS;
  1033. #endif
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Purpose: Remove local users from a session
  1037. //-----------------------------------------------------------------------------
  1038. int CXboxSystem::SessionLeaveLocal( XboxHandle_t hSession, uint nUserCount, const uint *pUserIndexes, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1039. {
  1040. #ifdef _X360
  1041. XOVERLAPPED *pOverlapped = NULL;
  1042. if ( bAsync )
  1043. {
  1044. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1045. pOverlapped = &pResult->overlapped;
  1046. }
  1047. return XSessionLeaveLocal( hSession, nUserCount, (DWORD*)pUserIndexes, pOverlapped );
  1048. #else
  1049. return ERROR_SUCCESS;
  1050. #endif
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: Remove remote users from a session
  1054. //-----------------------------------------------------------------------------
  1055. int CXboxSystem::SessionLeaveRemote( XboxHandle_t hSession, uint nUserCount, const XUID *pXuids, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1056. {
  1057. #ifdef _X360
  1058. XOVERLAPPED *pOverlapped = NULL;
  1059. if ( bAsync )
  1060. {
  1061. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1062. pOverlapped = &pResult->overlapped;
  1063. }
  1064. return XSessionLeaveRemote( hSession, nUserCount, pXuids, pOverlapped );
  1065. #else
  1066. return ERROR_SUCCESS;
  1067. #endif
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose: Migrate a session to a new host
  1071. //-----------------------------------------------------------------------------
  1072. int CXboxSystem::SessionMigrate( XboxHandle_t hSession, uint nUserIndex, void *pSessionInfo, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1073. {
  1074. #ifdef _X360
  1075. XOVERLAPPED *pOverlapped = NULL;
  1076. if ( bAsync )
  1077. {
  1078. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1079. pOverlapped = &pResult->overlapped;
  1080. }
  1081. return XSessionMigrateHost( hSession, nUserIndex, (XSESSION_INFO*)pSessionInfo, pOverlapped );
  1082. #else
  1083. return ERROR_SUCCESS; // On PC migration is not necessary because sessions are server-side
  1084. #endif
  1085. }
  1086. //-----------------------------------------------------------------------------
  1087. // Purpose: Register for arbitration
  1088. //-----------------------------------------------------------------------------
  1089. int CXboxSystem::SessionArbitrationRegister( XboxHandle_t hSession, uint nFlags, uint64 nonce, uint *pBytes, void *pBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1090. {
  1091. #ifdef _X360
  1092. XOVERLAPPED *pOverlapped = NULL;
  1093. if ( bAsync )
  1094. {
  1095. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1096. pOverlapped = &pResult->overlapped;
  1097. }
  1098. return XSessionArbitrationRegister( hSession, nFlags, nonce, (DWORD*)pBytes, (XSESSION_REGISTRATION_RESULTS*)pBuffer, pOverlapped );
  1099. #else
  1100. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1101. #endif
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. // Purpose: Get a list of the players friends
  1105. //-----------------------------------------------------------------------------
  1106. int CXboxSystem::EnumerateFriends( uint userIndex, void **ppBuffer, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1107. {
  1108. #ifdef _X360
  1109. HANDLE *phEnumerator = new HANDLE;
  1110. *phEnumerator = INVALID_HANDLE_VALUE;
  1111. DWORD nBufferBytes;
  1112. DWORD ret = XFriendsCreateEnumerator( userIndex, 0, MAX_FRIENDS, &nBufferBytes, phEnumerator );
  1113. // Just looking for the buffer size needed to hold the results
  1114. if ( ret != ERROR_SUCCESS )
  1115. {
  1116. Warning( "EnumerateFriends: XFriendsCreateEnumerator returned the error code: %d\n", ret );
  1117. CloseHandle( *phEnumerator );
  1118. delete phEnumerator;
  1119. return ret;
  1120. }
  1121. *ppBuffer = malloc( nBufferBytes );
  1122. if ( !*ppBuffer )
  1123. {
  1124. Warning( "EnumerateFriends: malloc failed for ppBuffer\n" );
  1125. CloseHandle( *phEnumerator );
  1126. delete phEnumerator;
  1127. return ERROR_NOT_ENOUGH_MEMORY;
  1128. }
  1129. XOVERLAPPED *pOverlapped = NULL;
  1130. int items = 0;
  1131. int *pItems = NULL;
  1132. if ( bAsync )
  1133. {
  1134. AsyncResult_t *pAsyncResult = InitializeAsyncResult( &pAsyncHandle );
  1135. pOverlapped = &pAsyncResult->overlapped;
  1136. // Free any existing input data
  1137. if ( pAsyncResult->pInputData )
  1138. delete pAsyncResult->pInputData;
  1139. pAsyncResult->pInputData = phEnumerator;
  1140. }
  1141. else
  1142. {
  1143. pItems = &items;
  1144. }
  1145. ret = XEnumerate( *phEnumerator, *ppBuffer, nBufferBytes, (DWORD*)pItems, pOverlapped );
  1146. if ( ( ret != ERROR_SUCCESS && !bAsync ) || ( ret != ERROR_IO_PENDING && bAsync ) )
  1147. {
  1148. Warning( "XEnumerate failed in EnumerateFriends.\n" );
  1149. CloseHandle( *phEnumerator );
  1150. delete phEnumerator;
  1151. return -1;
  1152. }
  1153. if ( !bAsync )
  1154. {
  1155. CloseHandle( *phEnumerator );
  1156. delete phEnumerator;
  1157. }
  1158. return items;
  1159. #else
  1160. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1161. #endif
  1162. }
  1163. //-----------------------------------------------------------------------------
  1164. // Purpose: Upload player stats to Xbox Live
  1165. //-----------------------------------------------------------------------------
  1166. int CXboxSystem::WriteStats( XboxHandle_t hSession, XUID xuid, uint nViews, void* pViews, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1167. {
  1168. #ifdef _X360
  1169. XOVERLAPPED *pOverlapped = NULL;
  1170. if ( bAsync )
  1171. {
  1172. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1173. pOverlapped = &pResult->overlapped;
  1174. }
  1175. return XSessionWriteStats( hSession, xuid, nViews, (XSESSION_VIEW_PROPERTIES*)pViews, pOverlapped );
  1176. #else
  1177. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1178. #endif
  1179. }
  1180. //-----------------------------------------------------------------------------
  1181. // Purpose: Upload player stats to Xbox Live
  1182. //-----------------------------------------------------------------------------
  1183. int CXboxSystem::FlushStats( XboxHandle_t hSession, bool bAsync, AsyncHandle_t *pAsyncHandle )
  1184. {
  1185. #ifdef _X360
  1186. XOVERLAPPED *pOverlapped = NULL;
  1187. if ( bAsync )
  1188. {
  1189. AsyncResult_t *pResult = InitializeAsyncResult( &pAsyncHandle );
  1190. pOverlapped = &pResult->overlapped;
  1191. }
  1192. return XSessionFlushStats( hSession, pOverlapped );
  1193. #else
  1194. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1195. #endif
  1196. }
  1197. //-----------------------------------------------------------------------------
  1198. // Purpose: Enumerate player stats for a specific range starting at a particular rank
  1199. //-----------------------------------------------------------------------------
  1200. int CXboxSystem::EnumerateStatsByRank( uint nStartingRank,
  1201. uint nNumRows,
  1202. uint nNumSpecs,
  1203. void *pSpecs,
  1204. void **ppResults,
  1205. bool bAsync,
  1206. AsyncHandle_t *pAsyncHandle
  1207. )
  1208. {
  1209. #ifdef _X360
  1210. HANDLE *phEnumerator = new HANDLE;
  1211. *phEnumerator = INVALID_HANDLE_VALUE;
  1212. DWORD nBufferBytes;
  1213. DWORD ret = XUserCreateStatsEnumeratorByRank( 0, nStartingRank, nNumRows, nNumSpecs, (XUSER_STATS_SPEC*)pSpecs, &nBufferBytes, phEnumerator );
  1214. if ( ret != ERROR_SUCCESS )
  1215. {
  1216. Warning( "EnumerateStatsByRank: XUserCreateStatsEnumeratorByRank failed (ret %d)\n", ret );
  1217. CloseHandle( *phEnumerator );
  1218. delete phEnumerator;
  1219. return ret;
  1220. }
  1221. *ppResults = malloc( nBufferBytes );
  1222. if ( !*ppResults )
  1223. {
  1224. Warning( "EnumerateStatsByRank: malloc failed for ppResults\n" );
  1225. CloseHandle( *phEnumerator );
  1226. delete phEnumerator;
  1227. return ERROR_NOT_ENOUGH_MEMORY;
  1228. }
  1229. XOVERLAPPED *pOverlapped = NULL;
  1230. DWORD items = 0;
  1231. DWORD *pItems = NULL;
  1232. if ( bAsync )
  1233. {
  1234. AsyncResult_t *pAsyncResult = InitializeAsyncResult( &pAsyncHandle );
  1235. pOverlapped = &pAsyncResult->overlapped;
  1236. // Free any existing input data
  1237. if ( pAsyncResult->pInputData )
  1238. delete pAsyncResult->pInputData;
  1239. pAsyncResult->pInputData = phEnumerator;
  1240. }
  1241. else
  1242. {
  1243. pItems = &items;
  1244. }
  1245. ret = XEnumerate( *phEnumerator, *ppResults, nBufferBytes, pItems, pOverlapped );
  1246. if ( ( ret != ERROR_SUCCESS && !bAsync ) || ( ret != ERROR_IO_PENDING && bAsync ) )
  1247. {
  1248. Warning( "EnumerateStatsByRank: XEnumerate failed (ret %d)\n", ret );
  1249. items = (DWORD)-1;
  1250. }
  1251. if ( !bAsync )
  1252. {
  1253. CloseHandle( *phEnumerator );
  1254. delete phEnumerator;
  1255. }
  1256. return ret;
  1257. #else
  1258. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1259. #endif
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Purpose: Enumerate player stats for a specific range starting at a particular rank
  1263. //-----------------------------------------------------------------------------
  1264. int CXboxSystem::EnumerateStatsByXuid( XUID nUserId,
  1265. uint nNumRows,
  1266. uint nNumSpecs,
  1267. void *pSpecs,
  1268. void **ppResults,
  1269. bool bAsync,
  1270. AsyncHandle_t *pAsyncHandle
  1271. )
  1272. {
  1273. #ifdef _X360
  1274. if (nUserId == 0)
  1275. {
  1276. Warning( "EnumerateStatsByXuid: XUserCreateStatsEnumeratorByXuid failed (nUserID is 0)\n" );
  1277. return ERROR_INVALID_PARAMETER;
  1278. }
  1279. DWORD nBufferBytes;
  1280. HANDLE *phEnumerator = new HANDLE;
  1281. *phEnumerator = INVALID_HANDLE_VALUE;
  1282. DWORD ret = XUserCreateStatsEnumeratorByXuid( 0, nUserId, nNumRows, nNumSpecs, (XUSER_STATS_SPEC*)pSpecs, &nBufferBytes, phEnumerator );
  1283. if ( ret != ERROR_SUCCESS )
  1284. {
  1285. Warning( "EnumerateStatsByXuid: XUserCreateStatsEnumeratorByXuid failed (ret %d)\n", ret );
  1286. CloseHandle( *phEnumerator );
  1287. delete phEnumerator;
  1288. return ret;
  1289. }
  1290. *ppResults = malloc( nBufferBytes );
  1291. if ( !*ppResults )
  1292. {
  1293. Warning( "EnumerateStatsByXuid: malloc failed for ppResults\n" );
  1294. CloseHandle( *phEnumerator );
  1295. delete phEnumerator;
  1296. return ERROR_NOT_ENOUGH_MEMORY;
  1297. }
  1298. XOVERLAPPED *pOverlapped = NULL;
  1299. DWORD items = 0;
  1300. DWORD *pItems = NULL;
  1301. if ( bAsync )
  1302. {
  1303. AsyncResult_t *pAsyncResult = InitializeAsyncResult( &pAsyncHandle );
  1304. pOverlapped = &pAsyncResult->overlapped;
  1305. // Free any existing input data
  1306. if ( pAsyncResult->pInputData )
  1307. delete pAsyncResult->pInputData;
  1308. pAsyncResult->pInputData = phEnumerator;
  1309. }
  1310. else
  1311. {
  1312. pItems = &items;
  1313. }
  1314. ret = XEnumerate( *phEnumerator, *ppResults, nBufferBytes, pItems, pOverlapped );
  1315. if ( ( ret != ERROR_SUCCESS && !bAsync ) || ( ret != ERROR_IO_PENDING && bAsync ) )
  1316. {
  1317. Warning( "EnumerateStatsByXuid: XEnumerate failed (ret %d)\n", ret );
  1318. items = (DWORD)-1;
  1319. }
  1320. if ( !bAsync )
  1321. {
  1322. CloseHandle( *phEnumerator );
  1323. delete phEnumerator;
  1324. }
  1325. return ret;
  1326. #else
  1327. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1328. #endif
  1329. }
  1330. //-----------------------------------------------------------------------------
  1331. // Purpose: Enumerate a player's achievements
  1332. //-----------------------------------------------------------------------------
  1333. int CXboxSystem::EnumerateAchievements( uint nUserIdx,
  1334. uint64 xuid,
  1335. uint nStartingIdx,
  1336. uint nCount,
  1337. void *pBuffer,
  1338. uint nBufferBytes,
  1339. bool bAsync,
  1340. AsyncHandle_t *pAsyncHandle
  1341. )
  1342. {
  1343. Error( "This function is obsolete and should not be used!\nReturn code cannot be an error code and number of results at the same time!\n" );
  1344. return ERROR_NO_SUCH_PRIVILEGE;
  1345. }
  1346. //-----------------------------------------------------------------------------
  1347. // Purpose: Award an achievement to the current user
  1348. //-----------------------------------------------------------------------------
  1349. int CXboxSystem::AwardAchievement( uint nUserIdx, uint nAchievementId, AsyncHandle_t *ppOverlappedResult )
  1350. {
  1351. #ifdef _X360
  1352. // Can't award achievements if this is a trial package!
  1353. if ( IsArcadeTitleUnlocked() == false )
  1354. return ERROR_SUCCESS;
  1355. // Create a new result
  1356. AsyncResult_t *pResult = CreateAsyncResult( false );
  1357. XUSER_ACHIEVEMENT ach;
  1358. ach.dwUserIndex = nUserIdx;
  1359. ach.dwAchievementId = nAchievementId;
  1360. pResult->pInputData = malloc( sizeof( ach ) );
  1361. Q_memcpy( pResult->pInputData, &ach, sizeof( ach ) );
  1362. DWORD ret = XUserWriteAchievements( 1, (XUSER_ACHIEVEMENT*)pResult->pInputData, &pResult->overlapped );
  1363. if ( ret != ERROR_IO_PENDING )
  1364. {
  1365. Warning( "XUserWriteAchievments failed.\n" );
  1366. }
  1367. // Return it to the user if they've supplied a pointer
  1368. if ( ppOverlappedResult != NULL )
  1369. {
  1370. *ppOverlappedResult = pResult;
  1371. }
  1372. return ret;
  1373. #else
  1374. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1375. #endif
  1376. }
  1377. //-----------------------------------------------------------------------------
  1378. // Purpose: Grant an avatar asset award to the current user
  1379. //-----------------------------------------------------------------------------
  1380. int CXboxSystem::AwardAvatarAsset( uint nUserIdx, uint nAwardId, AsyncHandle_t *ppOverlappedResult )
  1381. {
  1382. #ifdef _X360
  1383. // Create a new result
  1384. AsyncResult_t *pResult = CreateAsyncResult( false );
  1385. XUSER_AVATARASSET award;
  1386. award.dwUserIndex = nUserIdx;
  1387. award.dwAwardId = nAwardId;
  1388. pResult->pInputData = malloc( sizeof( award ) );
  1389. Q_memcpy( pResult->pInputData, &award, sizeof( award ) );
  1390. DWORD ret = XUserAwardAvatarAssets( 1, (XUSER_AVATARASSET*)pResult->pInputData, &pResult->overlapped );
  1391. if ( ret != ERROR_IO_PENDING )
  1392. {
  1393. Warning( "XUserAwardAvatarAssets failed.\n" );
  1394. }
  1395. if ( ppOverlappedResult != NULL )
  1396. {
  1397. *ppOverlappedResult = pResult;
  1398. }
  1399. return ret;
  1400. #else
  1401. return ERROR_ACCESS_DISABLED_BY_POLICY;
  1402. #endif
  1403. }
  1404. // trial mode
  1405. //-----------------------------------------------------------------------------
  1406. // Purpose: Show the "unlock trial game" blade
  1407. //-----------------------------------------------------------------------------
  1408. void CXboxSystem::ShowUnlockFullGameUI( void )
  1409. {
  1410. #ifdef _X360
  1411. XShowMarketplaceUI( XBX_GetPrimaryUserId(),
  1412. XSHOWMARKETPLACEUI_ENTRYPOINT_CONTENTITEM,
  1413. 0x5841096000000001,
  1414. (DWORD) -1 );
  1415. #endif
  1416. }
  1417. //=============================================================================
  1418. static ConVar xbox_arcade_title_unlocked( "xbox_arcade_title_unlocked", CSTRIKE_TRIAL_MODE ? "0": "1", FCVAR_DEVELOPMENTONLY, "debug unlocking arcade title" );
  1419. static bool g_bTitleUnlocked = false;
  1420. static ConVar xbox_arcade_remaining_trial_time( "xbox_arcade_remaining_trial_time", "2700.0", FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS | FCVAR_DEVELOPMENTONLY, "time remaining in trial mode" );
  1421. //=============================================================================
  1422. float CXboxSystem::GetArcadeRemainingTrialTime( int nSlot )
  1423. {
  1424. SplitScreenConVarRef trialTime( "xbox_arcade_remaining_trial_time" );
  1425. return trialTime.GetFloat( nSlot );
  1426. }
  1427. //-----------------------------------------------------------------------------
  1428. // Purpose: Determine whether this arcade game is unlocked
  1429. //-----------------------------------------------------------------------------
  1430. bool CXboxSystem::UpdateArcadeTitleUnlockStatus( void )
  1431. {
  1432. #ifdef _X360
  1433. // This means it was unlocked at some point during this session, which allows it to stay unlocked for the duration of the session
  1434. if ( g_bTitleUnlocked )
  1435. return false;
  1436. // Synchronously retrieve our own license bits
  1437. DWORD dwLicenseMask;
  1438. if ( XContentGetLicenseMask( &dwLicenseMask, NULL ) == ERROR_SUCCESS )
  1439. {
  1440. if ( ( dwLicenseMask & 0x01 ) == 0x01 )
  1441. {
  1442. g_bTitleUnlocked = true;
  1443. return true;
  1444. }
  1445. }
  1446. return false;
  1447. #else
  1448. return true;
  1449. #endif
  1450. }
  1451. //-----------------------------------------------------------------------------
  1452. // Purpose: Determine whether this arcade game is unlocked
  1453. //-----------------------------------------------------------------------------
  1454. bool CXboxSystem::IsArcadeTitleUnlocked( void )
  1455. {
  1456. #if defined ( _X360 )
  1457. // This allows us to quickly test licenses being on or off
  1458. if ( xbox_arcade_title_unlocked.GetBool() )
  1459. return true;
  1460. // This means it was unlocked at some point during this session, which allows it to stay unlocked for the duration of the session
  1461. return g_bTitleUnlocked;
  1462. #else
  1463. return true;
  1464. #endif
  1465. }
  1466. int CXboxSystem::Io_HasOverlappedIoCompleted( XOVERLAPPED *pOverlapped )
  1467. {
  1468. #ifdef _X360
  1469. return XHasOverlappedIoCompleted( pOverlapped );
  1470. #else
  1471. return 1;
  1472. #endif
  1473. }
  1474. int CXboxSystem::NetRandom( byte *pb, unsigned numBytes )
  1475. {
  1476. #ifdef _X360
  1477. return XNetRandom( pb, numBytes );
  1478. #else
  1479. if ( pb )
  1480. {
  1481. for ( byte * const pbEnd = pb + numBytes; pb < pbEnd; ++ pb )
  1482. *pb = ( byte ) ( unsigned ) RandomInt( 0, 255 );
  1483. }
  1484. return 0;
  1485. #endif
  1486. }
  1487. DWORD CXboxSystem::NetGetTitleXnAddr( XNADDR *pxna )
  1488. {
  1489. #ifdef _X360
  1490. return XNetGetTitleXnAddr( pxna );
  1491. #else
  1492. if ( pxna )
  1493. memset( pxna, 0, sizeof( *pxna ) );
  1494. return XNET_GET_XNADDR_NONE;
  1495. #endif
  1496. }
  1497. int CXboxSystem::NetXnAddrToMachineId( const XNADDR *pxnaddr, uint64 *pqwMachineId )
  1498. {
  1499. #ifdef _X360
  1500. return XNetXnAddrToMachineId( pxnaddr, pqwMachineId );
  1501. #else
  1502. if ( pqwMachineId )
  1503. *pqwMachineId = 0ull;
  1504. return 0;
  1505. #endif
  1506. }
  1507. int CXboxSystem::NetInAddrToXnAddr( const IN_ADDR ina, XNADDR *pxna, XNKID *pxnkid )
  1508. {
  1509. #ifdef _X360
  1510. return XNetInAddrToXnAddr( ina, pxna, pxnkid );
  1511. #else
  1512. if ( pxnkid )
  1513. {
  1514. memset( pxnkid, 0, sizeof( *pxnkid ) );
  1515. }
  1516. if ( pxna )
  1517. {
  1518. memset( pxna, 0, sizeof( *pxna ) );
  1519. pxna->ina = ina;
  1520. }
  1521. return 0;
  1522. #endif
  1523. }
  1524. int CXboxSystem::NetXnAddrToInAddr( const XNADDR *pxna, const XNKID *pxnkid, IN_ADDR *pina )
  1525. {
  1526. #ifdef _X360
  1527. return XNetXnAddrToInAddr( pxna, pxnkid, pina );
  1528. #else
  1529. if ( pina )
  1530. {
  1531. if ( pxna )
  1532. {
  1533. *pina = pxna->ina;
  1534. }
  1535. else
  1536. {
  1537. memset( pina, 0, sizeof( *pina ) );
  1538. }
  1539. }
  1540. return 0;
  1541. #endif
  1542. }
  1543. XUSER_SIGNIN_STATE CXboxSystem::UserGetSigninState( int iCtrlr )
  1544. {
  1545. #ifdef _X360
  1546. return XUserGetSigninState( iCtrlr );
  1547. #else
  1548. return eXUserSigninState_SignedInToLive;
  1549. #endif
  1550. }
  1551. #ifdef _X360
  1552. //
  1553. // Title server address refcounting service
  1554. //
  1555. struct XTitleServerAddr_t
  1556. {
  1557. IN_ADDR m_ina;
  1558. DWORD m_dwServiceID;
  1559. IN_ADDR m_result;
  1560. DWORD m_dwRefCount;
  1561. };
  1562. class XTitleServerAddrRefs
  1563. {
  1564. public:
  1565. INT XNetServerToInAddr(
  1566. const IN_ADDR ina,
  1567. DWORD dwServiceId,
  1568. IN_ADDR *pina
  1569. );
  1570. INT XNetUnregisterInAddr(
  1571. const IN_ADDR ina
  1572. );
  1573. protected:
  1574. CUtlVector< XTitleServerAddr_t > m_arrServerAddrs;
  1575. }
  1576. g_XTitleServerAddrRefs;
  1577. INT XTitleServerAddrRefs::XNetServerToInAddr(
  1578. const IN_ADDR ina,
  1579. DWORD dwServiceId,
  1580. IN_ADDR *pina
  1581. )
  1582. {
  1583. for ( int k = 0; k < m_arrServerAddrs.Count(); ++ k )
  1584. {
  1585. XTitleServerAddr_t &x = m_arrServerAddrs[k];
  1586. if ( x.m_ina.s_addr == ina.s_addr && x.m_dwServiceID == dwServiceId )
  1587. {
  1588. *pina = x.m_result;
  1589. ++ x.m_dwRefCount;
  1590. DevMsg( "XTitleServerAddrRefs::XNetServerToInAddr( %08X -> %08X ), cached connection [state = %d], refcount %d\n",
  1591. x.m_ina.s_addr, x.m_result.s_addr, ::XNetGetConnectStatus( x.m_result ), x.m_dwRefCount );
  1592. INT iConnectCode = ::XNetConnect( x.m_result );
  1593. DevMsg( " XNetConnect code = %d\n", iConnectCode );
  1594. return 0;
  1595. }
  1596. }
  1597. INT nResult = ::XNetServerToInAddr( ina, dwServiceId, pina );
  1598. if ( nResult )
  1599. return nResult;
  1600. XTitleServerAddr_t x = { ina, dwServiceId, *pina, 1 };
  1601. m_arrServerAddrs.AddToTail( x );
  1602. DevMsg( "XTitleServerAddrRefs::XNetServerToInAddr( %08X -> %08X ), new connection, refcount %d\n", x.m_ina.s_addr, x.m_result.s_addr, x.m_dwRefCount );
  1603. return 0;
  1604. }
  1605. INT XTitleServerAddrRefs::XNetUnregisterInAddr(
  1606. const IN_ADDR ina
  1607. )
  1608. {
  1609. for ( int k = 0; k < m_arrServerAddrs.Count(); ++ k )
  1610. {
  1611. XTitleServerAddr_t &x = m_arrServerAddrs[k];
  1612. if ( x.m_result.s_addr == ina.s_addr )
  1613. {
  1614. -- x.m_dwRefCount;
  1615. DevMsg( "XTitleServerAddrRefs::XNetUnregisterInAddr( %08X -> %08X ), cached connection, refcount %d\n", x.m_ina.s_addr, x.m_result.s_addr, x.m_dwRefCount );
  1616. if ( x.m_dwRefCount )
  1617. return 0; // not unregistering netadr since there are more references to it
  1618. m_arrServerAddrs.FastRemove( k );
  1619. break;
  1620. }
  1621. }
  1622. return ::XNetUnregisterInAddr( ina );
  1623. }
  1624. //
  1625. // XSession calls serializer service
  1626. //
  1627. static ConVar sys_xsessioncallstack_delay( "sys_xsessioncallstack_delay", "0" );
  1628. class XSessionCallStack
  1629. {
  1630. public:
  1631. struct OverlappedSessionCall
  1632. {
  1633. HANDLE m_hSession;
  1634. XOVERLAPPED *m_pxOverlapped;
  1635. XOVERLAPPED m_xOverlapped;
  1636. virtual DWORD Run() = NULL;
  1637. virtual char const * Name() = NULL;
  1638. virtual ~OverlappedSessionCall() {}
  1639. OverlappedSessionCall( HANDLE hSession, XOVERLAPPED *pxOverlapped ) :
  1640. m_hSession( hSession ), m_pxOverlapped( pxOverlapped )
  1641. {
  1642. Plat_FastMemset( &m_xOverlapped, 0, sizeof( m_xOverlapped ) );
  1643. if ( m_pxOverlapped )
  1644. {
  1645. Assert( !memcmp( &m_xOverlapped, m_pxOverlapped, sizeof( m_xOverlapped ) ) );
  1646. m_pxOverlapped->InternalLow = ERROR_IO_PENDING;
  1647. }
  1648. }
  1649. };
  1650. struct DebugDelayCall : public OverlappedSessionCall
  1651. {
  1652. DebugDelayCall( HANDLE hSession ) : OverlappedSessionCall( hSession, NULL ), m_flTimeStarted( 0 ) {}
  1653. virtual DWORD Run() { m_flTimeStarted = Plat_FloatTime(); return ERROR_IO_PENDING; }
  1654. virtual char const * Name() { return "DebugDelayCall"; }
  1655. float m_flTimeStarted;
  1656. };
  1657. typedef CUtlVector< OverlappedSessionCall * > CallsArray;
  1658. typedef CUtlVector< CallsArray * > SessionCalls;
  1659. public:
  1660. DWORD ScheduleOverlappedSessionCall( OverlappedSessionCall *pCall );
  1661. bool CancelOverlapped( XOVERLAPPED *pxOverlapped );
  1662. void RunFrame();
  1663. protected:
  1664. void OnDeleteHeadCallAndRunNext( CallsArray &arrCalls, int &idx );
  1665. void OnSessionCallFinished( CallsArray &arrCalls );
  1666. void RunNextCall( CallsArray &arrCalls );
  1667. protected:
  1668. SessionCalls m_SessionCalls;
  1669. }
  1670. g_XSessionCallStack;
  1671. // Macros for DECLARE_OVERLAPPED_SESSION_CALL_N
  1672. #include "xboxsystem.xsessioncallstack.inl"
  1673. void XSessionCallStack::RunFrame()
  1674. {
  1675. // Walk over all currently pending calls and see
  1676. // if they are finished:
  1677. for ( int k = 0; k < m_SessionCalls.Count(); ++ k )
  1678. {
  1679. CallsArray &arrCalls = *m_SessionCalls[k];
  1680. Assert( arrCalls.Count() );
  1681. OverlappedSessionCall &osc = *arrCalls.Head();
  1682. if ( !osc.m_pxOverlapped )
  1683. {
  1684. if ( DebugDelayCall *pDebugDelayCall = dynamic_cast< DebugDelayCall * >( &osc ) )
  1685. {
  1686. if ( Plat_FloatTime() < pDebugDelayCall->m_flTimeStarted + sys_xsessioncallstack_delay.GetFloat() )
  1687. continue;
  1688. }
  1689. }
  1690. if ( !XHasOverlappedIoCompleted( &osc.m_xOverlapped ) )
  1691. continue;
  1692. DevMsg( 2, "XSessionCallStack: finished overlapped call %s for session %p [%d]\n", osc.Name(), osc.m_hSession, arrCalls.Count() );
  1693. OnDeleteHeadCallAndRunNext( arrCalls, k );
  1694. }
  1695. }
  1696. bool XSessionCallStack::CancelOverlapped( XOVERLAPPED *pxOverlapped )
  1697. {
  1698. if ( !pxOverlapped )
  1699. return false;
  1700. // Attempt to find the overlapped operation in the session calls
  1701. for ( int k = 0; k < m_SessionCalls.Count(); ++ k )
  1702. {
  1703. CallsArray &arrCalls = *m_SessionCalls[k];
  1704. Assert( arrCalls.Count() );
  1705. OverlappedSessionCall &osc = *arrCalls.Head();
  1706. if ( osc.m_pxOverlapped == pxOverlapped )
  1707. {
  1708. // Actually cancel the faked overlapped call
  1709. ::XCancelOverlapped( &osc.m_xOverlapped );
  1710. DevMsg( 2, "XSessionCallStack: cancelled overlapped call %s for session %p [%d]\n", osc.Name(), osc.m_hSession, arrCalls.Count() );
  1711. OnDeleteHeadCallAndRunNext( arrCalls, k );
  1712. return true;
  1713. }
  1714. }
  1715. return false;
  1716. }
  1717. DWORD XSessionCallStack::ScheduleOverlappedSessionCall( OverlappedSessionCall *pCall )
  1718. {
  1719. // If the call has a NULL overlapped, then execute it right away
  1720. if ( !pCall->m_pxOverlapped )
  1721. {
  1722. DevWarning( "Executing a non-overlapped call in XSessionCallStack!\n" );
  1723. DWORD ret = pCall->Run();
  1724. delete pCall;
  1725. return ret;
  1726. }
  1727. // Attempt to find the session for this call
  1728. for ( int k = 0; k < m_SessionCalls.Count(); ++ k )
  1729. {
  1730. CallsArray &arrCalls = *m_SessionCalls[k];
  1731. Assert( arrCalls.Count() );
  1732. OverlappedSessionCall &osc = *arrCalls.Head();
  1733. if ( osc.m_hSession == pCall->m_hSession )
  1734. {
  1735. if ( sys_xsessioncallstack_delay.GetFloat() > 0.0f )
  1736. {
  1737. DebugDelayCall *pDbgCall = new DebugDelayCall( pCall->m_hSession );
  1738. arrCalls.AddToTail( pDbgCall );
  1739. DevMsg( 2, "XSessionCallStack: injecting debug delay call %s for session %p [%d]\n", pDbgCall->Name(), pDbgCall->m_hSession, arrCalls.Count() );
  1740. }
  1741. // We have a call stack for this session
  1742. arrCalls.AddToTail( pCall );
  1743. DevMsg( 2, "XSessionCallStack: queued call %s for session %p [%d]\n", pCall->Name(), pCall->m_hSession, arrCalls.Count() );
  1744. return ERROR_IO_PENDING;
  1745. }
  1746. }
  1747. // In case special call stack debugging is enabled, we insert a delay between
  1748. // every scheduled call
  1749. if ( sys_xsessioncallstack_delay.GetFloat() > 0.0f )
  1750. {
  1751. DebugDelayCall *pDbgCall = new DebugDelayCall( pCall->m_hSession );
  1752. DevMsg( 2, "XSessionCallStack: injecting debug delay call %s for session %p [new call stack]\n", pDbgCall->Name(), pDbgCall->m_hSession );
  1753. CallsArray *pCallStack = new CallsArray;
  1754. pCallStack->AddToTail( pDbgCall );
  1755. pCallStack->AddToTail( pCall );
  1756. DevMsg( 2, "XSessionCallStack: queued call %s for session %p [%d]\n", pCall->Name(), pCall->m_hSession, pCallStack->Count() );
  1757. m_SessionCalls.AddToTail( pCallStack );
  1758. return pDbgCall->Run();
  1759. }
  1760. // Otherwise it is a new session, we should queue the call
  1761. // and if it goes PENDING create a new call stack
  1762. DevMsg( 2, "XSessionCallStack: running call %s for session %p [new call stack]\n", pCall->Name(), pCall->m_hSession );
  1763. DWORD ret = pCall->Run();
  1764. if ( ret != ERROR_IO_PENDING )
  1765. {
  1766. DevWarning( 2, "XSessionCallStack: ret=%d for call %s for session %p [call stack not created]\n", ret, pCall->Name(), pCall->m_hSession );
  1767. delete pCall;
  1768. return ret;
  1769. }
  1770. // Call is pending
  1771. CallsArray *pCallStack = new CallsArray;
  1772. pCallStack->AddToTail( pCall );
  1773. m_SessionCalls.AddToTail( pCallStack );
  1774. return ERROR_IO_PENDING;
  1775. }
  1776. void XSessionCallStack::OnDeleteHeadCallAndRunNext( CallsArray &arrCalls, int &idx )
  1777. {
  1778. // Mark call as finished and delete it
  1779. OnSessionCallFinished( arrCalls );
  1780. // Check if the stack has another call to schedule
  1781. RunNextCall( arrCalls );
  1782. // Check if the stack for the current session is now empty
  1783. if ( !arrCalls.Count() )
  1784. {
  1785. delete &arrCalls;
  1786. m_SessionCalls.Remove( idx -- );
  1787. }
  1788. }
  1789. void XSessionCallStack::OnSessionCallFinished( CallsArray &arrCalls )
  1790. {
  1791. OverlappedSessionCall &osc = *arrCalls.Head();
  1792. // Copy data into the caller's overlapped structure
  1793. if ( osc.m_pxOverlapped )
  1794. {
  1795. Plat_FastMemcpy( osc.m_pxOverlapped, &osc.m_xOverlapped, sizeof( osc.m_xOverlapped ) );
  1796. }
  1797. // Delete the call and pop it off the stack
  1798. delete &osc;
  1799. arrCalls.RemoveMultipleFromHead( 1 );
  1800. }
  1801. void XSessionCallStack::RunNextCall( CallsArray &arrCalls )
  1802. {
  1803. while ( arrCalls.Count() )
  1804. {
  1805. OverlappedSessionCall &osc = *arrCalls.Head();
  1806. DevMsg( 2, "XSessionCallStack: running next call %s for session %p [%d]\n", osc.Name(), osc.m_hSession, arrCalls.Count() );
  1807. DWORD ret = osc.Run();
  1808. if ( ret != ERROR_IO_PENDING )
  1809. {
  1810. DevWarning( 2, "XSessionCallStack: ret=%d for call %s for session %p [%d]\n", ret, osc.Name(), osc.m_hSession, arrCalls.Count() );
  1811. OnSessionCallFinished( arrCalls );
  1812. }
  1813. else
  1814. {
  1815. break; // call is pending
  1816. }
  1817. }
  1818. }
  1819. //
  1820. // CXOnline implementation
  1821. //
  1822. static class CXOnline_Impl : public IXOnline
  1823. {
  1824. public:
  1825. virtual void RunFrame()
  1826. {
  1827. g_XSessionCallStack.RunFrame();
  1828. }
  1829. public:
  1830. virtual DWORD XCancelOverlapped( PXOVERLAPPED pOverlapped )
  1831. {
  1832. if ( g_XSessionCallStack.CancelOverlapped( pOverlapped ) )
  1833. return ERROR_SUCCESS;
  1834. return ::XCancelOverlapped( pOverlapped );
  1835. }
  1836. public:
  1837. virtual DWORD XFriendsCreateEnumerator(
  1838. DWORD dwUserIndex,
  1839. DWORD dwStartingIndex,
  1840. DWORD dwFriendsToReturn,
  1841. DWORD *pcbBuffer,
  1842. HANDLE *ph
  1843. )
  1844. {
  1845. return ::XFriendsCreateEnumerator( dwUserIndex, dwStartingIndex, dwFriendsToReturn, pcbBuffer, ph );
  1846. }
  1847. virtual INT XNetQosRelease(
  1848. XNQOS * pxnqos
  1849. )
  1850. {
  1851. return ::XNetQosRelease( pxnqos );
  1852. }
  1853. virtual INT XNetQosServiceLookup(
  1854. DWORD dwFlags,
  1855. WSAEVENT hEvent,
  1856. XNQOS * * ppxnqos
  1857. )
  1858. {
  1859. return ::XNetQosServiceLookup( dwFlags, hEvent, ppxnqos );
  1860. }
  1861. virtual DWORD XInviteGetAcceptedInfo(
  1862. DWORD dwUserIndex,
  1863. XINVITE_INFO *pInfo
  1864. )
  1865. {
  1866. return ::XInviteGetAcceptedInfo( dwUserIndex, pInfo );
  1867. }
  1868. virtual DWORD XInviteSend(
  1869. DWORD dwUserIndex,
  1870. DWORD cInvitees,
  1871. const XUID *pXuidInvitees,
  1872. const WCHAR *pszText,
  1873. XOVERLAPPED *pXOverlapped
  1874. )
  1875. {
  1876. return ::XInviteSend( dwUserIndex, cInvitees, pXuidInvitees, pszText, pXOverlapped );
  1877. }
  1878. virtual DWORD XTitleServerCreateEnumerator(
  1879. LPCSTR pszServerInfo,
  1880. DWORD cItem,
  1881. PDWORD pcbBuffer,
  1882. PHANDLE phEnum
  1883. )
  1884. {
  1885. return ::XTitleServerCreateEnumerator( pszServerInfo, cItem, pcbBuffer, phEnum );
  1886. }
  1887. virtual INT XNetQosLookup(
  1888. UINT cxna,
  1889. const XNADDR * apxna[],
  1890. const XNKID * apxnkid[],
  1891. const XNKEY * apxnkey[],
  1892. UINT cina,
  1893. const IN_ADDR aina[],
  1894. const DWORD adwServiceId[],
  1895. UINT cProbes,
  1896. DWORD dwBitsPerSec,
  1897. DWORD dwFlags,
  1898. WSAEVENT hEvent,
  1899. XNQOS ** ppxnqos
  1900. )
  1901. {
  1902. return ::XNetQosLookup( cxna, apxna, apxnkid, apxnkey, cina, aina, adwServiceId, cProbes, dwBitsPerSec, dwFlags, hEvent, ppxnqos );
  1903. }
  1904. virtual INT XNetUnregisterInAddr(
  1905. const IN_ADDR ina
  1906. )
  1907. {
  1908. return g_XTitleServerAddrRefs.XNetUnregisterInAddr( ina );
  1909. }
  1910. virtual INT XNetServerToInAddr(
  1911. const IN_ADDR ina,
  1912. DWORD dwServiceId,
  1913. IN_ADDR *pina
  1914. )
  1915. {
  1916. return g_XTitleServerAddrRefs.XNetServerToInAddr( ina, dwServiceId, pina );
  1917. }
  1918. virtual DWORD XSessionSearchEx(
  1919. DWORD dwProcedureIndex,
  1920. DWORD dwUserIndex,
  1921. DWORD dwNumResults,
  1922. DWORD dwNumUsers,
  1923. WORD wNumProperties,
  1924. WORD wNumContexts,
  1925. PXUSER_PROPERTY pSearchProperties,
  1926. PXUSER_CONTEXT pSearchContexts,
  1927. DWORD *pcbResultsBuffer,
  1928. PXSESSION_SEARCHRESULT_HEADER pSearchResults,
  1929. PXOVERLAPPED pXOverlapped
  1930. )
  1931. {
  1932. return ::XSessionSearchEx( dwProcedureIndex, dwUserIndex, dwNumResults, dwNumUsers, wNumProperties, wNumContexts, pSearchProperties, pSearchContexts, pcbResultsBuffer, pSearchResults, pXOverlapped );
  1933. }
  1934. IMPLEMENT_OVERLAPPED_SESSION_CALL_2( XSessionGetDetails, DWORD *, pcbResultsBuffer, XSESSION_LOCAL_DETAILS *, pSessionDetails );
  1935. virtual INT XNetQosListen(
  1936. const XNKID * pxnkid,
  1937. const BYTE * pb,
  1938. UINT cb,
  1939. DWORD dwBitsPerSec,
  1940. DWORD dwFlags
  1941. )
  1942. {
  1943. return ::XNetQosListen( pxnkid, pb, cb, dwBitsPerSec, dwFlags );
  1944. }
  1945. IMPLEMENT_OVERLAPPED_SESSION_CALL_3( XSessionModify, DWORD, dwFlags, DWORD, dwMaxPublicSlots, DWORD, dwMaxPrivateSlots );
  1946. virtual DWORD XNetGetTitleXnAddr(
  1947. XNADDR *pxna
  1948. )
  1949. {
  1950. return ::XNetGetTitleXnAddr( pxna );
  1951. }
  1952. virtual INT XNetRegisterKey(
  1953. const XNKID *pxnkid,
  1954. const XNKEY *pxnkey
  1955. )
  1956. {
  1957. return ::XNetRegisterKey( pxnkid, pxnkey );
  1958. }
  1959. virtual INT XNetUnregisterKey(
  1960. const XNKID *pxnkid
  1961. )
  1962. {
  1963. return ::XNetUnregisterKey( pxnkid );
  1964. }
  1965. virtual INT XNetCreateKey(
  1966. XNKID *pxnkid,
  1967. XNKEY *pxnkey
  1968. )
  1969. {
  1970. return ::XNetCreateKey( pxnkid, pxnkey );
  1971. }
  1972. virtual INT XNetReplaceKey(
  1973. const XNKID *pxnkidUnregister,
  1974. const XNKID * pxnkidReplace
  1975. )
  1976. {
  1977. return ::XNetReplaceKey( pxnkidUnregister, pxnkidReplace );
  1978. }
  1979. IMPLEMENT_OVERLAPPED_SESSION_CALL_0( XSessionDelete );
  1980. virtual DWORD XSessionCreate(
  1981. DWORD dwFlags,
  1982. DWORD dwUserIndex,
  1983. DWORD dwMaxPublicSlots,
  1984. DWORD dwMaxPrivateSlots,
  1985. ULONGLONG *pqwSessionNonce,
  1986. PXSESSION_INFO pSessionInfo,
  1987. PXOVERLAPPED pXOverlapped,
  1988. HANDLE *ph
  1989. )
  1990. {
  1991. return ::XSessionCreate( dwFlags, dwUserIndex, dwMaxPublicSlots, dwMaxPrivateSlots, pqwSessionNonce, pSessionInfo, pXOverlapped, ph );
  1992. }
  1993. virtual DWORD XSessionSearchByID(
  1994. XNKID sessionID,
  1995. DWORD dwUserIndex,
  1996. DWORD *pcbResultsBuffer,
  1997. PXSESSION_SEARCHRESULT_HEADER pSearchResults,
  1998. PXOVERLAPPED pXOverlapped
  1999. )
  2000. {
  2001. return ::XSessionSearchByID( sessionID, dwUserIndex, pcbResultsBuffer, pSearchResults, pXOverlapped );
  2002. }
  2003. IMPLEMENT_OVERLAPPED_SESSION_CALL_2( XSessionMigrateHost, DWORD, dwUserIndex, XSESSION_INFO *, pSessionInfo );
  2004. IMPLEMENT_OVERLAPPED_SESSION_CALL_3( XSessionJoinRemote, DWORD, dwXuidCount, const XUID *, pXuids, const BOOL *, pfPrivateSlots );
  2005. IMPLEMENT_OVERLAPPED_SESSION_CALL_3( XSessionJoinLocal, DWORD, dwUserCount, const DWORD *, pdwUserIndexes, const BOOL *, pfPrivateSlots );
  2006. IMPLEMENT_OVERLAPPED_SESSION_CALL_2( XSessionLeaveRemote, DWORD, dwXuidCount, const XUID *, pXuids );
  2007. IMPLEMENT_OVERLAPPED_SESSION_CALL_2( XSessionLeaveLocal, DWORD, dwUserCount, const DWORD *, pdwUserIndexes );
  2008. IMPLEMENT_OVERLAPPED_SESSION_CALL_0( XSessionEnd );
  2009. IMPLEMENT_OVERLAPPED_SESSION_CALL_1( XSessionStart, DWORD, dwFlags );
  2010. virtual DWORD XNetGetConnectStatus(
  2011. const IN_ADDR ina
  2012. )
  2013. {
  2014. return ::XNetGetConnectStatus( ina );
  2015. }
  2016. virtual INT XNetInAddrToXnAddr(
  2017. const IN_ADDR ina,
  2018. XNADDR *pxna,
  2019. XNKID *pxnkid
  2020. )
  2021. {
  2022. return ::XNetInAddrToXnAddr( ina, pxna, pxnkid );
  2023. }
  2024. virtual INT XNetXnAddrToInAddr(
  2025. const XNADDR *pxna,
  2026. const XNKID *pxnkid,
  2027. IN_ADDR *pina
  2028. )
  2029. {
  2030. return ::XNetXnAddrToInAddr( pxna, pxnkid, pina );
  2031. }
  2032. virtual INT XNetConnect(
  2033. const IN_ADDR ina
  2034. )
  2035. {
  2036. return ::XNetConnect( ina );
  2037. }
  2038. virtual DWORD XUserReadProfileSettingsByXuid(
  2039. DWORD dwTitleId,
  2040. DWORD dwUserIndexRequester,
  2041. DWORD dwNumFor,
  2042. const XUID *pxuidFor,
  2043. DWORD dwNumSettingIds,
  2044. const DWORD *pdwSettingIds,
  2045. DWORD *pcbResults,
  2046. PXUSER_READ_PROFILE_SETTING_RESULT pResults,
  2047. PXOVERLAPPED pXOverlapped
  2048. )
  2049. {
  2050. return ::XUserReadProfileSettingsByXuid( dwTitleId, dwUserIndexRequester, dwNumFor, pxuidFor, dwNumSettingIds, pdwSettingIds, pcbResults, pResults, pXOverlapped );
  2051. }
  2052. virtual DWORD XUserReadProfileSettings(
  2053. DWORD dwTitleId,
  2054. DWORD dwUserIndex,
  2055. DWORD dwNumSettingIds,
  2056. const DWORD *pdwSettingIds,
  2057. DWORD *pcbResults,
  2058. PXUSER_READ_PROFILE_SETTING_RESULT pResults,
  2059. PXOVERLAPPED pXOverlapped
  2060. )
  2061. {
  2062. return ::XUserReadProfileSettings( dwTitleId, dwUserIndex, dwNumSettingIds, pdwSettingIds, pcbResults, pResults, pXOverlapped );
  2063. }
  2064. virtual DWORD XUserWriteProfileSettings(
  2065. DWORD dwUserIndex,
  2066. DWORD dwNumSettings,
  2067. const PXUSER_PROFILE_SETTING pSettings,
  2068. PXOVERLAPPED pXOverlapped
  2069. )
  2070. {
  2071. return ::XUserWriteProfileSettings( dwUserIndex, dwNumSettings, pSettings, pXOverlapped );
  2072. }
  2073. virtual DWORD XUserMuteListQuery(
  2074. DWORD dwUserIndex,
  2075. XUID XuidRemoteTalker,
  2076. BOOL *pfOnMuteList
  2077. )
  2078. {
  2079. return ::XUserMuteListQuery( dwUserIndex, XuidRemoteTalker, pfOnMuteList );
  2080. }
  2081. IMPLEMENT_OVERLAPPED_SESSION_CALL_3( XSessionWriteStats, XUID, xuid, DWORD, dwNumViews, const XSESSION_VIEW_PROPERTIES *, pViews );
  2082. IMPLEMENT_OVERLAPPED_SESSION_CALL_0( XSessionFlushStats );
  2083. virtual DWORD XShowMarketplaceDownloadItemsUI(
  2084. DWORD dwUserIndex,
  2085. DWORD dwEntryPoint,
  2086. CONST ULONGLONG *pOfferIDs,
  2087. DWORD dwOfferIdCount,
  2088. HRESULT *phrResult,
  2089. PXOVERLAPPED pOverlapped
  2090. )
  2091. {
  2092. return ::XShowMarketplaceDownloadItemsUI( dwUserIndex, dwEntryPoint, pOfferIDs, dwOfferIdCount, phrResult, pOverlapped );
  2093. }
  2094. virtual DWORD XMarketplaceGetDownloadStatus(
  2095. DWORD dwUserIndex,
  2096. ULONGLONG qwOfferID,
  2097. LPDWORD pdwResult
  2098. )
  2099. {
  2100. return ::XMarketplaceGetDownloadStatus( dwUserIndex, qwOfferID, pdwResult );
  2101. }
  2102. virtual DWORD XShowMarketplaceUI(
  2103. DWORD dwUserIndex,
  2104. DWORD dwEntryPoint,
  2105. ULONGLONG qwOfferID,
  2106. DWORD dwContentCategories
  2107. )
  2108. {
  2109. return ::XShowMarketplaceUI( dwUserIndex, dwEntryPoint, qwOfferID, dwContentCategories );
  2110. }
  2111. virtual DWORD XShowGameInviteUI(
  2112. DWORD dwUserIndex,
  2113. CONST XUID *pXuidRecipients,
  2114. DWORD cRecipients,
  2115. LPCWSTR wszUnused
  2116. )
  2117. {
  2118. return ::XShowGameInviteUI( dwUserIndex, pXuidRecipients, cRecipients, wszUnused );
  2119. }
  2120. virtual HRESULT XShowPartyUI(
  2121. DWORD dwUserIndex
  2122. )
  2123. {
  2124. return ::XShowPartyUI( dwUserIndex );
  2125. }
  2126. virtual DWORD XPartySendGameInvites(
  2127. DWORD dwUserIndex,
  2128. XOVERLAPPED *pOverlapped
  2129. )
  2130. {
  2131. return ::XPartySendGameInvites( dwUserIndex, pOverlapped );
  2132. }
  2133. virtual HRESULT XShowCommunitySessionsUI(
  2134. DWORD dwUserIndex,
  2135. DWORD dwSocialSessionsFlags
  2136. )
  2137. {
  2138. return ::XShowCommunitySessionsUI( dwUserIndex, dwSocialSessionsFlags );
  2139. }
  2140. virtual INT XNetXnAddrToMachineId(
  2141. const XNADDR *pxnaddr,
  2142. ULONGLONG *pqwMachineId
  2143. )
  2144. {
  2145. return ::XNetXnAddrToMachineId( pxnaddr, pqwMachineId );
  2146. }
  2147. virtual DWORD XNetGetEthernetLinkStatus()
  2148. {
  2149. return ::XNetGetEthernetLinkStatus();
  2150. }
  2151. virtual XONLINE_NAT_TYPE XOnlineGetNatType()
  2152. {
  2153. return ::XOnlineGetNatType();
  2154. }
  2155. }
  2156. g_XOnline_Impl;
  2157. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CXOnline_Impl, IXOnline, XONLINE_INTERFACE_VERSION, g_XOnline_Impl );
  2158. #endif