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.

751 lines
22 KiB

  1. //========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "cbase.h"
  7. #include "basemodpanel.h"
  8. #include "UIGameData.h"
  9. #include "EngineInterface.h"
  10. #include "vgui/ILocalize.h"
  11. #include "matchmaking/imatchframework.h"
  12. #include "filesystem.h"
  13. #include "fmtstr.h"
  14. #ifndef _GAMECONSOLE
  15. #include "steam/steam_api.h"
  16. #endif
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. using namespace BaseModUI;
  20. using namespace vgui;
  21. #ifndef ERROR_SUCCESS
  22. #define ERROR_SUCCESS 0
  23. #endif
  24. #ifndef ERROR_IO_INCOMPLETE
  25. #define ERROR_IO_INCOMPLETE 996L
  26. #endif
  27. //
  28. // Storage device selection
  29. //
  30. //-----------------------------------------------------------------------------
  31. // Purpose: A storage device has been connected, update our settings and anything else
  32. //-----------------------------------------------------------------------------
  33. namespace BaseModUI {
  34. class CAsyncCtxUIOnDeviceAttached : public CUIGameData::CAsyncJobContext
  35. {
  36. public:
  37. explicit CAsyncCtxUIOnDeviceAttached( int iController );
  38. ~CAsyncCtxUIOnDeviceAttached();
  39. virtual void ExecuteAsync();
  40. virtual void Completed();
  41. uint GetContainerOpenResult( void ) { return m_ContainerOpenResult; }
  42. int GetController() const { return m_iController; }
  43. private:
  44. uint m_ContainerOpenResult;
  45. int m_iController;
  46. };
  47. CAsyncCtxUIOnDeviceAttached::CAsyncCtxUIOnDeviceAttached( int iController ) :
  48. CUIGameData::CAsyncJobContext( 3.0f ), // Storage device info for at least 3 seconds
  49. m_ContainerOpenResult( ERROR_SUCCESS ),
  50. m_iController( iController )
  51. {
  52. //CUIGameData::Get()->ShowMessageDialog( MD_CHECKING_STORAGE_DEVICE );
  53. }
  54. CAsyncCtxUIOnDeviceAttached::~CAsyncCtxUIOnDeviceAttached()
  55. {
  56. //CUIGameData::Get()->CloseMessageDialog( 0 );
  57. }
  58. void CAsyncCtxUIOnDeviceAttached::ExecuteAsync()
  59. {
  60. // Asynchronously do the tasks that don't interact with the command buffer
  61. g_pFullFileSystem->DiscoverDLC( GetController() );
  62. // Open user settings and save game container here
  63. m_ContainerOpenResult = engine->OnStorageDeviceAttached( GetController() );
  64. if ( m_ContainerOpenResult != ERROR_SUCCESS )
  65. return;
  66. }
  67. ConVar ui_start_dlc_time_pump( "ui_start_dlc_time_pump", "30" );
  68. ConVar ui_start_dlc_time_loaded( "ui_start_dlc_time_loaded", "150" );
  69. ConVar ui_start_dlc_time_corrupt( "ui_start_dlc_time_corrupt", "300" );
  70. CON_COMMAND_F( ui_pump_dlc_mount_corrupt, "", FCVAR_DEVELOPMENTONLY )
  71. {
  72. int nStage = -1;
  73. if ( args.ArgC() > 1 )
  74. {
  75. nStage = Q_atoi( args.Arg( 1 ) );
  76. }
  77. DevMsg( 2, "ui_pump_dlc_mount_corrupt %d\n", nStage );
  78. int nCorruptDLCs = g_pFullFileSystem->IsAnyCorruptDLC();
  79. while ( nStage >= 0 && nStage < nCorruptDLCs )
  80. {
  81. static wchar_t wszDlcInfo[ 3 * MAX_PATH ] = {0};
  82. if ( !g_pFullFileSystem->GetAnyCorruptDLCInfo( nStage, wszDlcInfo, sizeof( wszDlcInfo ) ) )
  83. {
  84. ++ nStage;
  85. continue;
  86. }
  87. // information text
  88. if ( wchar_t *wszExplanation = g_pVGuiLocalize->Find( "#L4D360UI_MsgBx_DlcCorruptTxt" ) )
  89. {
  90. int wlen = Q_wcslen( wszDlcInfo );
  91. Q_wcsncpy( wszDlcInfo + wlen, wszExplanation, sizeof( wszDlcInfo ) - 2 * wlen );
  92. }
  93. #if 0 // TODO: UI: // We've got a corrupt DLC, put it up on the spinner
  94. // We've got a corrupt DLC, put it up on the spinner
  95. CUIGameData::Get()->UpdateWaitPanel( wszDlcInfo, 0.0f );
  96. #endif
  97. engine->ClientCmd( CFmtStr( "echo corruptdlc%d; wait %d; ui_pump_dlc_mount_corrupt %d;",
  98. nStage + 1, ui_start_dlc_time_corrupt.GetInt(), nStage + 1 ) );
  99. return;
  100. }
  101. // end of dlc mounting phases
  102. CUIGameData::Get()->OnCompletedAsyncDeviceAttached( NULL );
  103. }
  104. CON_COMMAND_F( ui_pump_dlc_mount_content, "", FCVAR_DEVELOPMENTONLY )
  105. {
  106. int nStage = -1;
  107. if ( args.ArgC() > 1 )
  108. {
  109. nStage = Q_atoi( args.Arg( 1 ) );
  110. }
  111. DevMsg( 2, "ui_pump_dlc_mount_content %d\n", nStage );
  112. bool bSearchPathMounted = false;
  113. int numDlcsContent = g_pFullFileSystem->IsAnyDLCPresent( &bSearchPathMounted );
  114. while ( nStage >= 0 && nStage < numDlcsContent )
  115. {
  116. static wchar_t wszDlcInfo[ 3 * MAX_PATH ] = {0};
  117. unsigned int ulMask;
  118. if ( !g_pFullFileSystem->GetAnyDLCInfo( nStage, &ulMask, wszDlcInfo, sizeof( wszDlcInfo ) ) )
  119. {
  120. ++ nStage;
  121. continue;
  122. }
  123. // information text
  124. if ( wchar_t *wszExplanation = g_pVGuiLocalize->Find( "#L4D360UI_MsgBx_DlcMountedTxt" ) )
  125. {
  126. int wlen = Q_wcslen( wszDlcInfo );
  127. Q_wcsncpy( wszDlcInfo + wlen, wszExplanation, sizeof( wszDlcInfo ) - 2 * wlen );
  128. }
  129. #if 0 // TODO: UI: // We've got a corrupt DLC, put it up on the spinner
  130. // We've got a corrupt DLC, put it up on the spinner
  131. CUIGameData::Get()->UpdateWaitPanel( wszDlcInfo, 0.0f );
  132. #endif
  133. engine->ClientCmd( CFmtStr( "echo mounteddlc%d (0x%08X); wait %d; ui_pump_dlc_mount_content %d;",
  134. nStage + 1, ulMask, ui_start_dlc_time_loaded.GetInt(), nStage + 1 ) );
  135. return;
  136. }
  137. // Done displaying found content, show corrupt
  138. engine->ClientCmd( "ui_pump_dlc_mount_corrupt 0" );
  139. }
  140. CON_COMMAND_F( ui_pump_dlc_mount_stage, "", FCVAR_DEVELOPMENTONLY )
  141. {
  142. // execute in order
  143. int nStage = -1;
  144. if ( args.ArgC() > 1 )
  145. {
  146. nStage = Q_atoi( args.Arg( 1 ) );
  147. }
  148. DevMsg( 2, "ui_pump_dlc_mount_stage %d\n", nStage );
  149. static char const *s_arrClientCmdsDlcMount[] =
  150. {
  151. "net_reloadgameevents",
  152. "hud_reloadscheme",
  153. "gameinstructor_reload_lessons",
  154. "scenefilecache_reload",
  155. "cc_reload",
  156. "rr_reloadresponsesystems",
  157. "cl_soundemitter_reload",
  158. "sv_soundemitter_reload",
  159. };
  160. if ( nStage >= 0 && nStage < ARRAYSIZE( s_arrClientCmdsDlcMount ) )
  161. {
  162. // execute in phases, each command deferred occurs on main thread as required
  163. // adding a wait <frames> to let spinner clock a little
  164. // no way to solve any one phase that blocks for too long...this is good enough
  165. engine->ClientCmd( CFmtStr( "wait %d; %s; ui_pump_dlc_mount_stage %d;",
  166. ui_start_dlc_time_pump.GetInt(),
  167. s_arrClientCmdsDlcMount[ nStage ],
  168. nStage + 1 ) );
  169. return;
  170. }
  171. // Done mounting
  172. engine->ClientCmd( "ui_pump_dlc_mount_content 0" );
  173. }
  174. void CAsyncCtxUIOnDeviceAttached::Completed()
  175. {
  176. bool bDLCSearchPathMounted = false;
  177. if ( GetContainerOpenResult() == ERROR_SUCCESS &&
  178. g_pFullFileSystem->IsAnyDLCPresent( &bDLCSearchPathMounted ) )
  179. {
  180. if ( !bDLCSearchPathMounted )
  181. {
  182. // add the DLC search paths if they exist
  183. // this must be done on the main thread
  184. // the DLC search path mount will incur a quick synchronous hit due to zip mounting
  185. g_pFullFileSystem->AddDLCSearchPaths();
  186. // new DLC data may trump prior data, so need to signal isolated system reloads
  187. engine->ClientCmd( "ui_pump_dlc_mount_stage 0" );
  188. return;
  189. }
  190. }
  191. // No valid DLC was discovered, check if we discovered some corrupt DLC
  192. if ( g_pFullFileSystem->IsAnyCorruptDLC() )
  193. {
  194. // need to show just corrupt DLC information
  195. engine->ClientCmd( CFmtStr( "ui_pump_dlc_mount_corrupt %d", 0 ) );
  196. return;
  197. }
  198. // Otherwise we are done attaching storage right now
  199. CUIGameData::Get()->OnCompletedAsyncDeviceAttached( this );
  200. }
  201. }
  202. //
  203. // CChangeStorageDevice
  204. //
  205. // Should be used when user wants to change storage device
  206. //
  207. static CChangeStorageDevice *s_pChangeStorageDeviceCallback = NULL;
  208. static void CChangeStorageDevice_Continue()
  209. {
  210. s_pChangeStorageDeviceCallback->DeviceChangeCompleted( true );
  211. delete s_pChangeStorageDeviceCallback;
  212. s_pChangeStorageDeviceCallback = NULL;
  213. }
  214. static void CChangeStorageDevice_SelectAgain()
  215. {
  216. CUIGameData::Get()->SelectStorageDevice( s_pChangeStorageDeviceCallback );
  217. s_pChangeStorageDeviceCallback = NULL;
  218. }
  219. CChangeStorageDevice::CChangeStorageDevice( int iCtrlr ) :
  220. m_iCtrlr( iCtrlr ),
  221. m_bAllowDeclined( true ),
  222. m_bForce( true ),
  223. m_nConfirmationData( 0 )
  224. {
  225. // Just in case clean up (if dialogs were cancelled due to user sign out or such)
  226. delete s_pChangeStorageDeviceCallback;
  227. s_pChangeStorageDeviceCallback = NULL;
  228. }
  229. void CChangeStorageDevice::OnDeviceFail( FailReason_t eReason )
  230. {
  231. // Depending if the user had storage device by this moment
  232. // or not we will take different actions:
  233. DWORD dwDevice = XBX_GetStorageDeviceId( GetCtrlrIndex() );
  234. switch ( eReason )
  235. {
  236. case FAIL_ERROR:
  237. case FAIL_NOT_SELECTED:
  238. if ( XBX_DescribeStorageDevice( dwDevice ) )
  239. {
  240. // That's fine user has a valid storage device, didn't want to change
  241. DeviceChangeCompleted( false );
  242. delete this;
  243. return;
  244. }
  245. // otherwise, proceed with the ui msg
  246. }
  247. XBX_SetStorageDeviceId( GetCtrlrIndex(), XBX_STORAGE_DECLINED );
  248. // We don't want to fire notification because there might be unsaved
  249. // preferences changes that were done without a storage device
  250. // no: g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnProfileStorageAvailable", "iController", GetCtrlrIndex() ) );
  251. m_bAllowDeclined = false;
  252. #if 0 // TODO: UI: CChangeStorageDevice::OnDeviceFail
  253. GenericConfirmation* confirmation =
  254. static_cast<GenericConfirmation*>( CBaseModPanel::GetSingleton().
  255. OpenWindow( WT_GENERICCONFIRMATION, CUIGameData::Get()->GetParentWindowForSystemMessageBox(), false ) );
  256. GenericConfirmation::Data_t data;
  257. switch ( eReason )
  258. {
  259. case FAIL_ERROR:
  260. case FAIL_NOT_SELECTED:
  261. data.pWindowTitle = "#L4D360UI_MsgBx_AttractDeviceNoneC";
  262. data.pMessageText = "#L4D360UI_MsgBx_AttractDeviceNoneTxt";
  263. break;
  264. case FAIL_FULL:
  265. data.pWindowTitle = "#L4D360UI_MsgBx_AttractDeviceFullC";
  266. data.pMessageText = "#L4D360UI_MsgBx_AttractDeviceFullTxt";
  267. break;
  268. case FAIL_CORRUPT:
  269. default:
  270. data.pWindowTitle = "#L4D360UI_MsgBx_AttractDeviceCorruptC";
  271. data.pMessageText = "#L4D360UI_MsgBx_AttractDeviceCorruptTxt";
  272. break;
  273. }
  274. data.bOkButtonEnabled = true;
  275. data.bCancelButtonEnabled = true;
  276. s_pChangeStorageDeviceCallback = this;
  277. data.pfnOkCallback = CChangeStorageDevice_Continue;
  278. data.pfnCancelCallback = CChangeStorageDevice_SelectAgain;
  279. // WARNING! WARNING! WARNING!
  280. // The nature of Generic Confirmation is that it will be silently replaced
  281. // with another Generic Confirmation if a system event occurs
  282. // e.g. user unplugs controller, user changes storage device, etc.
  283. // If that happens neither OK nor CANCEL callbacks WILL NOT BE CALLED
  284. // The state machine cannot depend on either callback advancing the
  285. // state because in some situations neither callback can fire and the
  286. // confirmation dismissed/closed/replaced.
  287. // State machine must implement OnThink and check if the required
  288. // confirmation box is still present!
  289. // This code implements some sort of fallback - it deletes the static
  290. // confirmation data when a new storage device change is requested.
  291. // Vitaliy -- 9/26/2009
  292. //
  293. m_nConfirmationData = confirmation->SetUsageData(data);
  294. #endif
  295. }
  296. void CChangeStorageDevice::OnDeviceSelected()
  297. {
  298. DevMsg( "[GAMEUI] CChangeStorageDevice::OnDeviceSelected( 0x%08X )\n",
  299. XBX_GetStorageDeviceId( GetCtrlrIndex() ) );
  300. #if 0 // TODO: UI: CChangeStorageDevice::OnDeviceSelected
  301. CUIGameData::Get()->UpdateWaitPanel( "#L4D360UI_WaitScreen_SignOnSucceded" );
  302. #endif
  303. }
  304. void CChangeStorageDevice::AfterDeviceMounted()
  305. {
  306. DeviceChangeCompleted( true );
  307. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnProfileStorageAvailable", "iController", GetCtrlrIndex() ) );
  308. delete this;
  309. }
  310. void CChangeStorageDevice::DeviceChangeCompleted( bool bChanged )
  311. {
  312. if ( bChanged )
  313. {
  314. Msg( "CChangeStorageDevice::DeviceChangeCompleted for ctrlr%d device 0x%08X\n",
  315. GetCtrlrIndex(), XBX_GetStorageDeviceId( GetCtrlrIndex() ) );
  316. }
  317. else
  318. {
  319. Msg( "CChangeStorageDevice::DeviceChangeCompleted - ctrlr%d is keeping device 0x%08X\n",
  320. GetCtrlrIndex(), XBX_GetStorageDeviceId( GetCtrlrIndex() ) );
  321. }
  322. }
  323. //=============================================================================
  324. //
  325. //=============================================================================
  326. class CChangeStorageDeviceChained : public CChangeStorageDevice
  327. {
  328. public:
  329. typedef CChangeStorageDevice BaseClass;
  330. explicit CChangeStorageDeviceChained( int iCtrlrs[2] ) :
  331. BaseClass( iCtrlrs[0] ), m_nChainCtrlr( iCtrlrs[1] ) {}
  332. virtual void DeviceChangeCompleted( bool bChanged )
  333. {
  334. // Defer to the base class
  335. BaseClass::DeviceChangeCompleted( bChanged );
  336. // If we have a chain target, then call this off again
  337. if ( m_nChainCtrlr >= 0 )
  338. {
  339. CUIGameData::Get()->SelectStorageDevice( new CChangeStorageDevice( m_nChainCtrlr ) );
  340. }
  341. }
  342. private:
  343. int m_nChainCtrlr;
  344. };
  345. void OnStorageDevicesChangedSelectNewDevice()
  346. {
  347. #ifdef _GAMECONSOLE
  348. int numChangedCtrlrs = 0;
  349. int nChangedCtrlrs[2] = { -1, -1 }; // We can only have two users (split-screen)
  350. for ( DWORD i = 0; i < XBX_GetNumGameUsers(); ++ i )
  351. {
  352. int iController = XBX_GetUserId( i );
  353. // Guests can't choose a storage device!
  354. if ( XBX_GetUserIsGuest( iController ) )
  355. continue;
  356. int nStorageID = XBX_GetStorageDeviceId( iController );
  357. if ( nStorageID == XBX_INVALID_STORAGE_ID )
  358. {
  359. // A controller's device has changed, and we'll need to prompt them to replace it
  360. nChangedCtrlrs[numChangedCtrlrs] = iController;
  361. numChangedCtrlrs++;
  362. }
  363. }
  364. // If a controller changed, then start off our device change dialogs
  365. if ( numChangedCtrlrs )
  366. {
  367. CUIGameData::Get()->SelectStorageDevice( new CChangeStorageDeviceChained( nChangedCtrlrs ) );
  368. }
  369. #endif // _GAMECONSOLE
  370. }
  371. void CUIGameData::RunFrame_Storage()
  372. {
  373. // Check to see if a pending async task has already finished
  374. if ( m_pAsyncJob && !m_pAsyncJob->m_hThreadHandle )
  375. {
  376. m_pAsyncJob->Completed();
  377. delete m_pAsyncJob;
  378. m_pAsyncJob = NULL;
  379. }
  380. if( m_bWaitingForStorageDeviceHandle )
  381. {
  382. //the select device blade just closed, get the selected device
  383. DWORD ret = xboxsystem->GetOverlappedResult( m_hStorageDeviceChangeHandle, NULL, true );
  384. if ( ret != ERROR_IO_INCOMPLETE )
  385. {
  386. // Done waiting
  387. xboxsystem->ReleaseAsyncHandle( m_hStorageDeviceChangeHandle );
  388. m_bWaitingForStorageDeviceHandle = false;
  389. // If we selected something, validate it
  390. if ( m_iStorageID != XBX_INVALID_STORAGE_ID )
  391. {
  392. OnSetStorageDeviceId( m_iStorageController, m_iStorageID );
  393. }
  394. else
  395. {
  396. #if 0 // TODO: UI: CloseWaitScreen( NULL, "ReportNoDeviceSelected" );
  397. CloseWaitScreen( NULL, "ReportNoDeviceSelected" );
  398. #endif
  399. if ( m_pSelectStorageClient )
  400. {
  401. m_pSelectStorageClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_NOT_SELECTED );
  402. m_pSelectStorageClient = NULL;
  403. }
  404. }
  405. }
  406. }
  407. }
  408. void StorageDevice_SelectAllNow()
  409. {
  410. #ifdef _GAMECONSOLE
  411. int numChangedCtrlrs = 0;
  412. int nChangedCtrlrs[2] = { -1, -1 }; // We can only have two users (split-screen)
  413. for ( DWORD i = 0; i < XBX_GetNumGameUsers(); ++ i )
  414. {
  415. int iController = XBX_GetUserId( i );
  416. // Guests can't choose a storage device!
  417. if ( XBX_GetUserIsGuest( iController ) )
  418. continue;
  419. int nStorageID = XBX_GetStorageDeviceId( iController );
  420. if ( nStorageID == XBX_INVALID_STORAGE_ID )
  421. {
  422. // A controller's device has changed, and we'll need to prompt them to replace it
  423. nChangedCtrlrs[numChangedCtrlrs] = iController;
  424. numChangedCtrlrs++;
  425. }
  426. }
  427. // If a controller changed, then start off our device change dialogs
  428. if ( numChangedCtrlrs )
  429. {
  430. CUIGameData::Get()->SelectStorageDevice( new CChangeStorageDeviceChained( nChangedCtrlrs ) );
  431. }
  432. #endif // _GAMECONSOLE
  433. }
  434. //=============================================================================
  435. //This is where we open the XUI pannel to let the user select the current storage device.
  436. bool CUIGameData::SelectStorageDevice( ISelectStorageDeviceClient *pSelectClient )
  437. {
  438. #ifdef _GAMECONSOLE
  439. if ( !pSelectClient )
  440. return false;
  441. int iController = pSelectClient->GetCtrlrIndex();
  442. bool bAllowDeclined = pSelectClient->AllowDeclined();
  443. bool bForceDisplay = pSelectClient->ForceSelector();
  444. bool bCheckCtrlr = !pSelectClient->AllowAnyController();
  445. DevMsg( 2, "[GAMEUI] SelectStorageDevice( ctrlr=%d; %d, %d ), waiting=%d\n",
  446. iController, bAllowDeclined, bForceDisplay, m_bWaitingForStorageDeviceHandle );
  447. if ( bCheckCtrlr )
  448. {
  449. // Check if the game is in guest mode
  450. if ( XBX_GetPrimaryUserIsGuest() )
  451. {
  452. Warning( "[GAMEUI] SelectStorageDevice for guest!\n" );
  453. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  454. return false; // go away, no storage for guests
  455. }
  456. int nSlot = -1;
  457. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  458. {
  459. int iCtrlr = XBX_GetUserId( k );
  460. if ( iCtrlr != iController )
  461. continue;
  462. else if ( XBX_GetUserIsGuest( k ) )
  463. {
  464. Warning( "[GAMEUI] SelectStorageDevice for guest!\n" );
  465. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  466. return false; // go away, game thinks you are a guest
  467. }
  468. else
  469. nSlot = k;
  470. }
  471. if ( nSlot < 0 )
  472. {
  473. Warning( "[GAMEUI] SelectStorageDevice for not active ctrlr!\n" );
  474. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  475. return false; // this controller is not involved in the game, go away
  476. }
  477. }
  478. // Is the controller signed in?
  479. if( XUserGetSigninState( iController ) == eXUserSigninState_NotSignedIn )
  480. {
  481. Warning( "[GAMEUI] SelectStorageDevice for not signed in user!\n" );
  482. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  483. return false; // not signed in, no device selector
  484. }
  485. // Maybe a guest buddy?
  486. XUSER_SIGNIN_INFO xsi;
  487. if ( ERROR_SUCCESS == XUserGetSigninInfo( iController, XUSER_GET_SIGNIN_INFO_ONLINE_XUID_ONLY, &xsi ) &&
  488. (xsi.dwInfoFlags & XUSER_INFO_FLAG_GUEST) != 0 )
  489. {
  490. Warning( "[GAMEUI] SelectStorageDevice for LIVE-guest!\n" );
  491. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  492. return false; // guests don't have device selectors, go away
  493. }
  494. if ( ERROR_SUCCESS != XUserGetSigninInfo( iController, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &xsi ) )
  495. {
  496. Warning( "[GAMEUI] SelectStorageDevice failed to obtain XUID!\n" );
  497. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  498. return false; // failed to obtain XUID?
  499. }
  500. //
  501. // Prevent reentry
  502. //
  503. if( m_bWaitingForStorageDeviceHandle )
  504. {
  505. Warning( "[GAMEUI] SelectStorageDevice is already busy selecting storage device! Cannot re-enter!\n" );
  506. pSelectClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_ERROR );
  507. return false; // Somebody already selecting a device
  508. }
  509. #if defined( _DEMO ) && defined( _GAMECONSOLE )
  510. // Demo mode cannot have access to storage devices anyway
  511. if ( IsGameConsole() )
  512. {
  513. m_iStorageID = XBX_STORAGE_DECLINED;
  514. m_iStorageController = iController;
  515. m_pSelectStorageClient = pSelectClient;
  516. m_pSelectStorageClient->OnDeviceSelected();
  517. OnCompletedAsyncDeviceAttached( NULL );
  518. return true;
  519. }
  520. #endif
  521. // Check if we already have a valid storage device
  522. if ( XBX_GetStorageDeviceId( iController ) != XBX_INVALID_STORAGE_ID &&
  523. ( bAllowDeclined || XBX_GetStorageDeviceId( iController ) != XBX_STORAGE_DECLINED ) &&
  524. ! bForceDisplay )
  525. {
  526. DevMsg( 2, "[GAMEUI] SelectStorageDevice - storage id = 0x%08X\n",
  527. XBX_GetStorageDeviceId( iController ) );
  528. // Put up a progress that we are loading profile...
  529. // TODO: UI: OpenWaitScreen( "#L4D360UI_WaitScreen_SigningOn" );
  530. // - OpenWaitScreen( "#L4D360UI_WaitScreen_SigningOn" );
  531. m_iStorageID = XBX_GetStorageDeviceId( iController );
  532. m_iStorageController = iController;
  533. m_pSelectStorageClient = pSelectClient;
  534. OnSetStorageDeviceId( iController, XBX_GetStorageDeviceId( iController ) );
  535. // Already have a storage device
  536. return true;
  537. }
  538. // Put up a progress that we are loading profile...
  539. // TODO: UI: OpenWaitScreen( "#L4D360UI_WaitScreen_SigningOn", 0.0f );
  540. // - OpenWaitScreen( "#L4D360UI_WaitScreen_SigningOn", 0.0f );
  541. // NOTE: this shouldn't have a 3 sec time-out as a new wait message is taking over
  542. // the progress when container starts mounting
  543. //open the dialog
  544. m_bWaitingForStorageDeviceHandle = true;
  545. m_hStorageDeviceChangeHandle = xboxsystem->CreateAsyncHandle();
  546. m_iStorageID = XBX_INVALID_STORAGE_ID;
  547. m_iStorageController = iController;
  548. m_pSelectStorageClient = pSelectClient;
  549. xboxsystem->ShowDeviceSelector( iController, bForceDisplay, &m_iStorageID, &m_hStorageDeviceChangeHandle );
  550. #endif
  551. return false;
  552. }
  553. //=============================================================================
  554. void CUIGameData::OnDeviceAttached()
  555. {
  556. //This is straight from CBasePanel
  557. ExecuteAsync( new CAsyncCtxUIOnDeviceAttached( m_iStorageController ) );
  558. }
  559. //=============================================================================
  560. void CUIGameData::OnCompletedAsyncDeviceAttached( CAsyncCtxUIOnDeviceAttached * job )
  561. {
  562. ISelectStorageDeviceClient *pStorageDeviceClient = m_pSelectStorageClient;
  563. m_pSelectStorageClient = NULL;
  564. static ConVarRef mm_dlcs_mask_extras( "mm_dlcs_mask_extras" );
  565. if ( mm_dlcs_mask_extras.IsValid() )
  566. {
  567. #ifdef _GAMECONSOLE
  568. int iDLCmask = mm_dlcs_mask_extras.GetInt();
  569. if ( engine->IsLowViolence() && XGetGameRegion() == XC_GAME_REGION_EUROPE_REST )
  570. {
  571. // iDLCmask |= ( 1 << ? );
  572. }
  573. mm_dlcs_mask_extras.SetValue( iDLCmask );
  574. #endif
  575. }
  576. uint nRet = job ? job->GetContainerOpenResult() : ERROR_SUCCESS;
  577. if ( nRet != ERROR_SUCCESS )
  578. {
  579. #if 0 // TODO: UI: CloseWaitScreen( NULL, "ReportDeviceCorrupt" );
  580. CloseWaitScreen( NULL, "ReportDeviceCorrupt" );
  581. #endif
  582. pStorageDeviceClient->OnDeviceFail( ISelectStorageDeviceClient::FAIL_CORRUPT );
  583. }
  584. else
  585. {
  586. // Notify that data has loaded
  587. pStorageDeviceClient->AfterDeviceMounted();
  588. // Check for opening a new storage device immediately
  589. if ( m_pSelectStorageClient == NULL )
  590. {
  591. // Close down the waiting screen
  592. #if 0 // TODO: UI: CloseWaitScreen( NULL, "OnCompletedAsyncDeviceAttached" );
  593. CloseWaitScreen( NULL, "OnCompletedAsyncDeviceAttached" );
  594. #endif
  595. }
  596. }
  597. }
  598. #ifdef _WIN32
  599. //-------------------------
  600. // Purpose: Job wrapper
  601. //-------------------------
  602. static unsigned UIGameDataJobWrapperFn( void *pvContext )
  603. {
  604. CUIGameData::CAsyncJobContext *pAsync = reinterpret_cast< CUIGameData::CAsyncJobContext * >( pvContext );
  605. float const flTimeStart = Plat_FloatTime();
  606. pAsync->ExecuteAsync();
  607. float const flElapsedTime = Plat_FloatTime() - flTimeStart;
  608. if ( flElapsedTime < pAsync->m_flLeastExecuteTime )
  609. {
  610. ThreadSleep( ( pAsync->m_flLeastExecuteTime - flElapsedTime ) * 1000 );
  611. }
  612. ReleaseThreadHandle( ( ThreadHandle_t ) pAsync->m_hThreadHandle );
  613. pAsync->m_hThreadHandle = NULL;
  614. return 0;
  615. }
  616. #endif
  617. //-----------------------------------------------------------------------------
  618. // Purpose: Enqueues a job function to be called on a separate thread
  619. //-----------------------------------------------------------------------------
  620. void CUIGameData::ExecuteAsync( CAsyncJobContext *pAsync )
  621. {
  622. Assert( !m_pAsyncJob );
  623. Assert( pAsync && !pAsync->m_hThreadHandle );
  624. m_pAsyncJob = pAsync;
  625. #ifdef _WIN32
  626. ThreadHandle_t hHandle = CreateSimpleThread( UIGameDataJobWrapperFn, reinterpret_cast< void * >( pAsync ) );
  627. pAsync->m_hThreadHandle = hHandle;
  628. #ifdef _GAMECONSOLE
  629. ThreadSetAffinity( hHandle, XBOX_PROCESSOR_3 );
  630. #endif
  631. #else
  632. pAsync->ExecuteAsync();
  633. #endif
  634. }