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.

1169 lines
33 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Xbox
  4. //
  5. //=====================================================================================//
  6. #include "../pch_tier0.h"
  7. #ifdef PLATFORM_PS3
  8. #include "ps3/ps3_core.h"
  9. #include "ps3/ps3_win32stubs.h"
  10. #include "ps3/ps3_console.h"
  11. #include "tls_ps3.h"
  12. #include <sysutil/sysutil_common.h>
  13. #include <sys/process.h>
  14. #include <sysutil/sysutil_sysparam.h>
  15. #else
  16. #include "xbox/xbox_console.h"
  17. #include "xbox/xbox_win32stubs.h"
  18. #include "xbox/xbox_launch.h"
  19. #endif
  20. #include "tier0/threadtools.h"
  21. #include "tier0/icommandline.h"
  22. #include "tier0/memdbgon.h"
  23. class CXbxEventQueue
  24. {
  25. public:
  26. CXbxEventQueue() : m_pQueue( NULL ), m_dwCount( 0 ), m_dwAllocated( 0 ), m_bDispatching( false ) {}
  27. public:
  28. void AppendEvent( xevent_t const &xevt );
  29. void Dispatch();
  30. bool IsDispatching() const;
  31. protected:
  32. CThreadFastMutex m_mtx;
  33. xevent_t *m_pQueue;
  34. DWORD m_dwCount;
  35. DWORD m_dwAllocated;
  36. bool m_bDispatching;
  37. static const int s_nQueueNormalSize = 32;
  38. static const int s_nQueueAbnormalSize = 128;
  39. };
  40. static CXbxEventQueue g_xbx_EventQueue;
  41. DWORD g_iStorageDeviceId[ XUSER_MAX_COUNT ] =
  42. {
  43. XBX_INVALID_STORAGE_ID, XBX_INVALID_STORAGE_ID, XBX_INVALID_STORAGE_ID, XBX_INVALID_STORAGE_ID
  44. #ifdef PLATFORM_PS3
  45. , XBX_INVALID_STORAGE_ID, XBX_INVALID_STORAGE_ID, XBX_INVALID_STORAGE_ID
  46. #endif
  47. };
  48. DWORD g_iPrimaryUserId = XBX_INVALID_USER_ID;
  49. DWORD g_bPrimaryUserIsGuest = 0;
  50. DWORD g_numGameUsers = 0;
  51. DWORD g_InvitedUserId = XBX_INVALID_USER_ID;
  52. XUID g_InvitedUserXuid = 0ull;
  53. XNKID g_InviteSessionId;
  54. #ifdef _X360
  55. HANDLE g_hListenHandle = INVALID_HANDLE_VALUE;
  56. ULONG64 g_ListenCategories = 0;
  57. #elif defined( _PS3 )
  58. ps3syscbckeventhdlr_t g_ps3SysCbckEvHdlr;
  59. #endif
  60. //-----------------------------------------------------------------------------
  61. // Convert an Xbox notification to a custom windows message
  62. //-----------------------------------------------------------------------------
  63. static int NotificationToWindowsMessage( DWORD id )
  64. {
  65. #ifdef _X360
  66. switch( id )
  67. {
  68. case XN_SYS_UI: return WM_SYS_UI;
  69. case XN_SYS_SIGNINCHANGED: return WM_SYS_SIGNINCHANGED;
  70. case XN_SYS_STORAGEDEVICESCHANGED: return WM_SYS_STORAGEDEVICESCHANGED;
  71. case XN_SYS_PROFILESETTINGCHANGED: return WM_SYS_PROFILESETTINGCHANGED;
  72. case XN_SYS_MUTELISTCHANGED: return WM_SYS_MUTELISTCHANGED;
  73. case XN_SYS_INPUTDEVICESCHANGED: return WM_SYS_INPUTDEVICESCHANGED;
  74. case XN_SYS_INPUTDEVICECONFIGCHANGED: return WM_SYS_INPUTDEVICECONFIGCHANGED;
  75. case XN_LIVE_CONNECTIONCHANGED: return WM_LIVE_CONNECTIONCHANGED;
  76. case XN_LIVE_INVITE_ACCEPTED: return WM_LIVE_INVITE_ACCEPTED;
  77. case XN_LIVE_LINK_STATE_CHANGED: return WM_LIVE_LINK_STATE_CHANGED;
  78. case XN_LIVE_CONTENT_INSTALLED: return WM_LIVE_CONTENT_INSTALLED;
  79. case XN_LIVE_MEMBERSHIP_PURCHASED: return WM_LIVE_MEMBERSHIP_PURCHASED;
  80. case XN_LIVE_VOICECHAT_AWAY: return WM_LIVE_VOICECHAT_AWAY;
  81. case XN_LIVE_PRESENCE_CHANGED: return WM_LIVE_PRESENCE_CHANGED;
  82. case XN_FRIENDS_PRESENCE_CHANGED: return WM_FRIENDS_PRESENCE_CHANGED;
  83. case XN_FRIENDS_FRIEND_ADDED: return WM_FRIENDS_FRIEND_ADDED;
  84. case XN_FRIENDS_FRIEND_REMOVED: return WM_FRIENDS_FRIEND_REMOVED;
  85. // deprecated in Jun08 XDK: case XN_CUSTOM_GAMEBANNERPRESSED: return WM_CUSTOM_GAMEBANNERPRESSED;
  86. case XN_CUSTOM_ACTIONPRESSED: return WM_CUSTOM_ACTIONPRESSED;
  87. case XN_XMP_STATECHANGED: return WM_XMP_STATECHANGED;
  88. case XN_XMP_PLAYBACKBEHAVIORCHANGED: return WM_XMP_PLAYBACKBEHAVIORCHANGED;
  89. case XN_XMP_PLAYBACKCONTROLLERCHANGED: return WM_XMP_PLAYBACKCONTROLLERCHANGED;
  90. default:
  91. Warning( "Unrecognized notification id %d\n", id );
  92. return 0;
  93. }
  94. #endif
  95. Assert( 0 );
  96. return 0;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // XBX_Error
  100. //
  101. //-----------------------------------------------------------------------------
  102. void XBX_Error( const char* format, ... )
  103. {
  104. va_list args;
  105. char message[XBX_MAX_MESSAGE];
  106. va_start( args, format );
  107. _vsnprintf( message, sizeof( message ), format, args );
  108. va_end( args );
  109. message[sizeof( message )-1] = '\0';
  110. #if defined( _X360 )
  111. XBX_DebugString( XMAKECOLOR(255,0,0), message );
  112. XBX_FlushDebugOutput();
  113. DebugBreak();
  114. static volatile int doReturn;
  115. while ( !doReturn );
  116. #elif defined( _PS3 )
  117. XBX_DebugString( 0xFFFFFFFF, message );
  118. // primitive crash technique for now
  119. DebuggerBreak();
  120. return;
  121. #endif
  122. }
  123. //-----------------------------------------------------------------------------
  124. // XBX_OutputDebugStringA
  125. //
  126. // Replaces 'OutputDebugString' to send through debugging channel
  127. //-----------------------------------------------------------------------------
  128. void XBX_OutputDebugStringA( LPCSTR lpOutputString )
  129. {
  130. #ifdef _X360
  131. XBX_DebugString( XMAKECOLOR(0,0,0), lpOutputString );
  132. #endif
  133. }
  134. //-----------------------------------------------------------------------------
  135. // XBX_ProcessXCommand
  136. //
  137. //-----------------------------------------------------------------------------
  138. static void XBX_ProcessXCommand( xevent_t const &xe )
  139. {
  140. const char *pCommand = (char*)xe.arg1;
  141. #if defined( _X360 )
  142. // remote command
  143. // pass it game via windows message
  144. HWND hWnd = GetFocus();
  145. WNDPROC windowProc = ( WNDPROC)GetWindowLong( hWnd, GWL_WNDPROC );
  146. if ( windowProc )
  147. {
  148. windowProc( hWnd, WM_XREMOTECOMMAND, 0, (LPARAM)pCommand );
  149. }
  150. #elif defined ( _PS3 )
  151. if ( g_ps3SysCbckEvHdlr.pfnHandler )
  152. {
  153. // recreate the event and send it to the handler (wtf?)
  154. xevent_t ev = { XEV_REMOTECMD, WM_XREMOTECOMMAND, reinterpret_cast<int>(pCommand), 0 };
  155. g_ps3SysCbckEvHdlr.pfnHandler( ev );
  156. }
  157. #endif
  158. //
  159. // VXBDM gives us a command as a pointer to the global buffer
  160. // and then monitors this global buffer on a separate thread.
  161. // As soon as the first byte in the buffer is set to NULL this
  162. // serves as a signal to VXBDM that the command has been received
  163. // and processed and that it can enqueue another command.
  164. // Signal to VXBDM here:
  165. ( const_cast< char * >( pCommand ) )[0] = 0;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // XBX_ProcessListenerNotification
  169. //
  170. //-----------------------------------------------------------------------------
  171. static void XBX_ProcessListenerNotification( xevent_t const &xe )
  172. {
  173. #ifdef _X360
  174. // pass it game via windows message
  175. HWND hWnd = GetFocus();
  176. WNDPROC windowProc = ( WNDPROC)GetWindowLong( hWnd, GWL_WNDPROC );
  177. if ( windowProc )
  178. {
  179. windowProc( hWnd, xe.arg1, 0, (LPARAM)xe.arg2 );
  180. }
  181. #elif defined( _PS3 )
  182. if ( g_ps3SysCbckEvHdlr.pfnHandler )
  183. {
  184. g_ps3SysCbckEvHdlr.pfnHandler( xe );
  185. }
  186. #else
  187. Assert( 0 );
  188. #endif
  189. switch ( xe.arg1 )
  190. {
  191. case WM_SYS_SIGNINCHANGED:
  192. delete reinterpret_cast< xevent_SYS_SIGNINCHANGED_t * >( xe.arg2 );
  193. break;
  194. }
  195. }
  196. //-----------------------------------------------------------------------------
  197. // XBX_QueueEvent
  198. //
  199. //-----------------------------------------------------------------------------
  200. void XBX_QueueEvent(xevent_e event, int arg1, int arg2, int arg3)
  201. {
  202. xevent_t xEvt;
  203. memset( &xEvt, 0, sizeof( xEvt ) );
  204. xEvt.event = event;
  205. xEvt.arg1 = arg1;
  206. xEvt.arg2 = arg2;
  207. xEvt.arg3 = arg3;
  208. g_xbx_EventQueue.AppendEvent( xEvt );
  209. }
  210. #ifdef _PS3
  211. static void XBX_QueueRemoteCommandEvent( const char *pBuf )
  212. {
  213. XBX_QueueEvent( XEV_REMOTECMD, ( int )pBuf, 0, 0 );
  214. }
  215. void PS3_CellSysutilCallback_Function(
  216. uint64_t status,
  217. uint64_t param,
  218. void *userdata
  219. );
  220. #endif
  221. //-----------------------------------------------------------------------------
  222. // XBX_ProcessEvents
  223. //
  224. // Assumed one per frame only!
  225. //-----------------------------------------------------------------------------
  226. void XBX_ProcessEvents(void)
  227. {
  228. Assert( ThreadInMainThread() );
  229. if ( g_xbx_EventQueue.IsDispatching() )
  230. {
  231. DevWarning( "XBX_ProcessEvents is ignored while the queue is dispatching!\n" );
  232. return;
  233. }
  234. #ifdef _X360
  235. DWORD id;
  236. ULONG parameter;
  237. while ( XNotifyGetNext( g_hListenHandle, 0, &id, &parameter ) )
  238. {
  239. // Special handling
  240. switch( id )
  241. {
  242. case XN_SYS_STORAGEDEVICESCHANGED:
  243. {
  244. bool bWarnOfDeviceChange = false;
  245. #if defined ( CSTRIKE15 )
  246. // cstrike15 saves info to profile; so we always want to check for profile
  247. // backing store whenever a storage device is changed
  248. bWarnOfDeviceChange = true;
  249. #endif
  250. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  251. {
  252. // Has anybody selected a storage device?
  253. DWORD storageID = XBX_GetStorageDeviceId( k );
  254. if ( XBX_DescribeStorageDevice( storageID ) == false )
  255. continue;
  256. // Validate the selected storage device
  257. XDEVICE_DATA deviceData;
  258. DWORD ret = XContentGetDeviceData( storageID, &deviceData );
  259. if ( ret != ERROR_SUCCESS )
  260. {
  261. // Device was removed
  262. Warning( "XN_SYS_STORAGEDEVICESCHANGED: device 0x%08X removed for ctrlr%d!\n",
  263. storageID, k );
  264. XBX_SetStorageDeviceId( k, XBX_INVALID_STORAGE_ID );
  265. int iSplitscreenSlot = XBX_GetSlotByUserId( k );
  266. if ( iSplitscreenSlot >= 0 )
  267. {
  268. bWarnOfDeviceChange = true;
  269. }
  270. }
  271. }
  272. // Notify the user if something important has changed
  273. if ( bWarnOfDeviceChange )
  274. {
  275. XBX_QueueEvent( XEV_LISTENER_NOTIFICATION, NotificationToWindowsMessage( id ), 0, 0 );
  276. }
  277. }
  278. break;
  279. case XN_SYS_SIGNINCHANGED:
  280. {
  281. xevent_SYS_SIGNINCHANGED_t *pSysEvent = new xevent_SYS_SIGNINCHANGED_t; // deleted during dispatch
  282. pSysEvent->dwParam = parameter;
  283. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  284. {
  285. pSysEvent->state[k] = XUserGetSigninState( k );
  286. pSysEvent->xuid[k] = 0ull;
  287. if ( pSysEvent->state[k] != eXUserSigninState_NotSignedIn )
  288. {
  289. XUSER_SIGNIN_INFO xsi = {0};
  290. if ( ERROR_SUCCESS != XUserGetSigninInfo( k, XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY, &xsi ) ||
  291. !xsi.xuid )
  292. {
  293. if ( ERROR_SUCCESS == XUserGetXUID( k, &xsi.xuid ) )
  294. pSysEvent->xuid[k] = xsi.xuid;
  295. }
  296. else
  297. {
  298. pSysEvent->xuid[k] = xsi.xuid;
  299. }
  300. }
  301. }
  302. XBX_QueueEvent( XEV_LISTENER_NOTIFICATION, NotificationToWindowsMessage( id ), reinterpret_cast< int >( pSysEvent ), parameter );
  303. }
  304. break;
  305. default:
  306. XBX_QueueEvent( XEV_LISTENER_NOTIFICATION, NotificationToWindowsMessage( id ), parameter, 0 );
  307. break;
  308. }
  309. }
  310. #elif defined( _PS3 )
  311. if ( g_pValvePS3Console )
  312. {
  313. g_pValvePS3Console->PumpMessage( XBX_QueueRemoteCommandEvent );
  314. }
  315. int retval = cellSysutilCheckCallback();
  316. if ( retval < 0 )
  317. {
  318. DevWarning( "cellSysutilCheckCallback failed! error 0x%08X!\n", retval );
  319. }
  320. #ifndef _CERT
  321. static float s_flQuitAfter = CommandLine()->ParmValue( "-quitafter", 0.0f );
  322. if( s_flQuitAfter > 0 && Plat_FloatTime() > s_flQuitAfter )
  323. {
  324. PS3_CellSysutilCallback_Function( CELL_SYSUTIL_REQUEST_EXITGAME, 0, 0 );
  325. }
  326. #endif
  327. #endif
  328. }
  329. void XBX_DispatchEventsQueue()
  330. {
  331. g_xbx_EventQueue.Dispatch();
  332. }
  333. #ifdef _PS3
  334. void PS3_CellSysutilCallback_Function(
  335. uint64_t status,
  336. uint64_t param,
  337. void *userdata
  338. )
  339. {
  340. Assert( g_ps3SysCbckEvHdlr.pfnHandler );
  341. // Prepare to queue the event
  342. xevent_t xe;
  343. memset( &xe, 0, sizeof( xe ) );
  344. xe.event = XEV_LISTENER_NOTIFICATION;
  345. switch ( status )
  346. {
  347. case CELL_SYSUTIL_REQUEST_EXITGAME:
  348. xe.arg1 = WM_SYS_SHUTDOWNREQUEST;
  349. GetTLSGlobals()->bNormalQuitRequested = true; // special flag to prevent the error screen from appearing
  350. Warning( "[PS3 SYSTEM] REQUEST EXITGAME RECEIVED @ %.3f\n", Plat_FloatTime() );
  351. break;
  352. case CELL_SYSUTIL_DRAWING_BEGIN:
  353. case CELL_SYSUTIL_DRAWING_END:
  354. // not interesting notifications
  355. return;
  356. case CELL_SYSUTIL_SYSTEM_MENU_OPEN:
  357. case CELL_SYSUTIL_SYSTEM_MENU_CLOSE:
  358. xe.arg1 = WM_SYS_UI;
  359. xe.arg2 = !!( status == CELL_SYSUTIL_SYSTEM_MENU_OPEN );
  360. break;
  361. case CELL_SYSUTIL_BGMPLAYBACK_PLAY:
  362. case CELL_SYSUTIL_BGMPLAYBACK_STOP:
  363. xe.arg1 = WM_XMP_PLAYBACKCONTROLLERCHANGED;
  364. xe.arg2 = !!( status == CELL_SYSUTIL_BGMPLAYBACK_STOP );
  365. break;
  366. case CELL_SYSUTIL_NP_INVITATION_SELECTED:
  367. xe.arg1 = WM_LIVE_INVITE_ACCEPTED;
  368. xe.arg2 = XBX_GetPrimaryUserId(); // accept on primary controller
  369. break;
  370. }
  371. // Queue the event
  372. xe.arg3 = 1; // means that event has sysutil payload
  373. xe.sysutil_status = status;
  374. xe.sysutil_param = param;
  375. g_xbx_EventQueue.AppendEvent( xe );
  376. }
  377. #endif
  378. //-----------------------------------------------------------------------------
  379. // XBX_NotifyCreateListener
  380. //
  381. // Add notification categories to the listener object
  382. //-----------------------------------------------------------------------------
  383. bool XBX_NotifyCreateListener( uint64 categories )
  384. {
  385. #ifdef _X360
  386. if ( categories != 0 )
  387. {
  388. categories |= g_ListenCategories;
  389. }
  390. g_hListenHandle = XNotifyCreateListener( categories );
  391. if ( g_hListenHandle == NULL || g_hListenHandle == INVALID_HANDLE_VALUE )
  392. {
  393. return false;
  394. }
  395. g_ListenCategories = categories;
  396. #elif defined( _PS3 )
  397. Assert( categories == (uint64)( (size_t) categories ) );
  398. if ( ps3syscbckeventhdlr_t const *pHdlr = reinterpret_cast< ps3syscbckeventhdlr_t const * >( (size_t) categories ) )
  399. {
  400. Assert( !g_ps3SysCbckEvHdlr.pfnHandler );
  401. g_ps3SysCbckEvHdlr = *pHdlr;
  402. int retval = cellSysutilRegisterCallback( 0, PS3_CellSysutilCallback_Function, NULL );
  403. if ( retval < 0 )
  404. {
  405. DevWarning( "cellSysutilRegisterCallback failed with error 0x%08X!\n", retval );
  406. }
  407. }
  408. else
  409. {
  410. int retval = cellSysutilUnregisterCallback( 0 );
  411. if ( retval < 0 )
  412. {
  413. DevWarning( "cellSysutilUnregisterCallback failed with error 0x%08X!\n", retval );
  414. }
  415. memset( &g_ps3SysCbckEvHdlr, 0, sizeof( g_ps3SysCbckEvHdlr ) );
  416. }
  417. #endif
  418. return true;
  419. }
  420. struct Language_t
  421. {
  422. const char *pString;
  423. int id;
  424. bool bLocalizedAudio;
  425. };
  426. Language_t s_ValidLanguages[] =
  427. {
  428. #ifdef _GAMECONSOLE
  429. #ifdef _PS3
  430. #define XC_LANGUAGE_JAPANESE CELL_SYSUTIL_LANG_JAPANESE
  431. #if CELL_SDK_VERSION >= 0x400000
  432. #define XC_LANGUAGE_ENGLISH CELL_SYSUTIL_LANG_ENGLISH_US
  433. #else
  434. #define XC_LANGUAGE_ENGLISH CELL_SYSUTIL_LANG_ENGLISH
  435. #endif
  436. #define XC_LANGUAGE_FRENCH CELL_SYSUTIL_LANG_FRENCH
  437. #define XC_LANGUAGE_SPANISH CELL_SYSUTIL_LANG_SPANISH
  438. #define XC_LANGUAGE_GERMAN CELL_SYSUTIL_LANG_GERMAN
  439. #define XC_LANGUAGE_ITALIAN CELL_SYSUTIL_LANG_ITALIAN
  440. #define XC_LANGUAGE_DUTCH CELL_SYSUTIL_LANG_DUTCH
  441. #if CELL_SDK_VERSION >= 0x400000
  442. #define XC_LANGUAGE_PORTUGUESE CELL_SYSUTIL_LANG_PORTUGUESE_PT
  443. #else
  444. #define XC_LANGUAGE_PORTUGUESE CELL_SYSUTIL_LANG_PORTUGUESE
  445. #endif
  446. #define XC_LANGUAGE_RUSSIAN CELL_SYSUTIL_LANG_RUSSIAN
  447. #define XC_LANGUAGE_KOREAN CELL_SYSUTIL_LANG_KOREAN
  448. #define XC_LANGUAGE_TCHINESE CELL_SYSUTIL_LANG_CHINESE_T
  449. #define XC_LANGUAGE_SCHINESE CELL_SYSUTIL_LANG_CHINESE_S
  450. #define XC_LANGUAGE_FINNISH CELL_SYSUTIL_LANG_FINNISH
  451. #define XC_LANGUAGE_SWEDISH CELL_SYSUTIL_LANG_SWEDISH
  452. #define XC_LANGUAGE_DANISH CELL_SYSUTIL_LANG_DANISH
  453. #define XC_LANGUAGE_NORWEGIAN CELL_SYSUTIL_LANG_NORWEGIAN
  454. #define XC_LANGUAGE_POLISH CELL_SYSUTIL_LANG_POLISH
  455. #endif
  456. #ifdef _X360
  457. // Xbox 360 doesn't support these languages in OS, but people can still test
  458. // with them by running with appropriate command line
  459. #define XC_LANGUAGE_DUTCH 0x7F1A4EF1
  460. #define XC_LANGUAGE_FINNISH 0x7F1A4EF2
  461. #define XC_LANGUAGE_SWEDISH 0x7F1A4EF3
  462. #define XC_LANGUAGE_DANISH 0x7F1A4EF4
  463. #define XC_LANGUAGE_NORWEGIAN 0x7F1A4EF5
  464. #endif
  465. #if 0 // to turn off all localization change it to #if 1
  466. {"english", XC_LANGUAGE_ENGLISH, true},
  467. #else
  468. // known supported 360 languages
  469. {"japanese", XC_LANGUAGE_JAPANESE, false},
  470. {"german", XC_LANGUAGE_GERMAN, true},
  471. {"french", XC_LANGUAGE_FRENCH, true},
  472. {"spanish", XC_LANGUAGE_SPANISH, true},
  473. {"italian", XC_LANGUAGE_ITALIAN, false},
  474. {"dutch", XC_LANGUAGE_DUTCH, false},
  475. {"korean", XC_LANGUAGE_KOREAN, false},
  476. {"tchinese", XC_LANGUAGE_TCHINESE, false},
  477. {"portuguese", XC_LANGUAGE_PORTUGUESE, false},
  478. {"schinese", XC_LANGUAGE_SCHINESE, false},
  479. {"finnish", XC_LANGUAGE_FINNISH, false},
  480. {"swedish", XC_LANGUAGE_SWEDISH, false},
  481. {"danish", XC_LANGUAGE_DANISH, false},
  482. {"norwegian", XC_LANGUAGE_NORWEGIAN, false},
  483. {"polish", XC_LANGUAGE_POLISH, false},
  484. #if defined( _X360 )
  485. {"russian", XC_LANGUAGE_RUSSIAN, false},
  486. #else
  487. {"russian", XC_LANGUAGE_RUSSIAN, true},
  488. #endif
  489. #endif
  490. #else
  491. #define XC_LANGUAGE_ENGLISH 0
  492. {"english", XC_LANGUAGE_ENGLISH, true},
  493. #endif
  494. };
  495. static const char *SupportedLanguageIDToString( int id )
  496. {
  497. // find it or force to english
  498. for ( int i = 0; i < ARRAYSIZE( s_ValidLanguages ); i++ )
  499. {
  500. if ( id == s_ValidLanguages[i].id )
  501. {
  502. return s_ValidLanguages[i].pString;
  503. }
  504. }
  505. return "english";
  506. }
  507. static int SupportedLanguageStringToID( const char *pName )
  508. {
  509. // find it or force to english
  510. for ( int i = 0; i < ARRAYSIZE( s_ValidLanguages ); i++ )
  511. {
  512. // caller's argument could be substring from command line, i.e. "french -another arg"
  513. if ( !strncmp( pName, s_ValidLanguages[i].pString, strlen( s_ValidLanguages[i].pString ) ) )
  514. {
  515. return s_ValidLanguages[i].id;
  516. }
  517. }
  518. return XC_LANGUAGE_ENGLISH;
  519. }
  520. //-----------------------------------------------------------------------------
  521. // Returns the true xbox language id, possibly an id that is not supported.
  522. //-----------------------------------------------------------------------------
  523. static int GetLanguage( void )
  524. {
  525. static int languageId = -1;
  526. if ( languageId == -1 )
  527. {
  528. #ifdef _X360
  529. languageId = XGetLanguage();
  530. #elif defined( _PS3 )
  531. if ( cellSysutilGetSystemParamInt( CELL_SYSUTIL_SYSTEMPARAM_ID_LANG, &languageId ) < 0 )
  532. languageId = XC_LANGUAGE_ENGLISH;
  533. #else
  534. languageId = XC_LANGUAGE_ENGLISH;
  535. #endif
  536. // allow language to be overriden via command line for easier development
  537. // otherwise must set via dashboard
  538. const char *pLanguage = CommandLine()->ParmValue( "-language", (const char *)NULL );
  539. if ( pLanguage && pLanguage[0] )
  540. {
  541. languageId = SupportedLanguageStringToID( pLanguage );
  542. }
  543. }
  544. return languageId;
  545. }
  546. const char *XBX_GetNextSupportedLanguage( const char *pLanguage, bool *pbHasAudio )
  547. {
  548. int i = 0;
  549. if ( pLanguage && pLanguage[0] )
  550. {
  551. for ( i = 0; i < ARRAYSIZE( s_ValidLanguages ); i++ )
  552. {
  553. if ( !V_tier0_stricmp( pLanguage, s_ValidLanguages[i].pString ) )
  554. {
  555. i++;
  556. break;
  557. }
  558. }
  559. }
  560. if ( i >= ARRAYSIZE( s_ValidLanguages ) )
  561. {
  562. // end of list
  563. return NULL;
  564. }
  565. if ( pbHasAudio )
  566. {
  567. *pbHasAudio = s_ValidLanguages[i].bLocalizedAudio;
  568. }
  569. return s_ValidLanguages[i].pString;
  570. }
  571. //-----------------------------------------------------------------------------
  572. // XBX_GetLanguageString
  573. //
  574. // Returns the supported xbox language setting as a string, otherwise "english".
  575. //-----------------------------------------------------------------------------
  576. const char* XBX_GetLanguageString( void )
  577. {
  578. return ( SupportedLanguageIDToString( GetLanguage() ) );
  579. }
  580. //-----------------------------------------------------------------------------
  581. // XBX_IsLocalized
  582. //
  583. // Returns true if configured for a supported non-english localization.
  584. //-----------------------------------------------------------------------------
  585. bool XBX_IsLocalized( void )
  586. {
  587. return ( V_tier0_stricmp( XBX_GetLanguageString(), "english" ) != 0 );
  588. }
  589. //-----------------------------------------------------------------------------
  590. // XBX_IsRestrictiveLanguage
  591. //
  592. // Returns true if we are localized into one of the languages that needs
  593. // specialized handling
  594. //-----------------------------------------------------------------------------
  595. bool XBX_IsRestrictiveLanguage( void )
  596. {
  597. #ifdef _GAMECONSOLE
  598. // these languages have to use the xarial font mounted in memory
  599. // cannot determine this from the font system at the times we need it, encoded it here
  600. int languageId = GetLanguage();
  601. switch ( languageId )
  602. {
  603. case XC_LANGUAGE_KOREAN:
  604. case XC_LANGUAGE_JAPANESE:
  605. case XC_LANGUAGE_SCHINESE:
  606. case XC_LANGUAGE_TCHINESE:
  607. return true;
  608. }
  609. #endif
  610. // all other languages can be handled normally
  611. return false;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // XBX_IsAudioLocalized
  615. //
  616. // Returns true if audio is localized.
  617. //-----------------------------------------------------------------------------
  618. bool XBX_IsAudioLocalized( void )
  619. {
  620. // english is not a localized audio
  621. if ( XBX_IsLocalized() )
  622. {
  623. int languageId = GetLanguage();
  624. for ( int i = 0; i < ARRAYSIZE( s_ValidLanguages ); i++ )
  625. {
  626. if ( languageId == s_ValidLanguages[i].id )
  627. {
  628. return s_ValidLanguages[i].bLocalizedAudio;
  629. }
  630. }
  631. }
  632. return false;
  633. }
  634. //-----------------------------------------------------------------------------
  635. // XBX_ResetStorageDeviceInfo
  636. //
  637. // Returns the xbox storage device ID
  638. //-----------------------------------------------------------------------------
  639. void XBX_ResetStorageDeviceInfo()
  640. {
  641. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  642. g_iStorageDeviceId[ k ] = XBX_INVALID_STORAGE_ID;
  643. }
  644. //-----------------------------------------------------------------------------
  645. // XBX_DescribeStorageDevice
  646. //
  647. // Returns whether the storage device denotes a usable device or is
  648. // denoting a state of unavailable device.
  649. //-----------------------------------------------------------------------------
  650. DWORD XBX_DescribeStorageDevice( DWORD nStorageID )
  651. {
  652. if ( nStorageID == XBX_INVALID_STORAGE_ID ||
  653. nStorageID == XBX_STORAGE_DECLINED )
  654. return 0;
  655. return 1;
  656. }
  657. //-----------------------------------------------------------------------------
  658. // XBX_MakeStorageContainerRoot
  659. //
  660. // Returns whether the storage device denotes a usable device or is
  661. // denoting a state of unavailable device.
  662. //-----------------------------------------------------------------------------
  663. char const* XBX_MakeStorageContainerRoot( int iController, char const *szRootName, char *pBuffer, int numBufferBytes )
  664. {
  665. if ( iController < 0 || iController >= XUSER_MAX_COUNT )
  666. {
  667. pBuffer[0] = '\0';
  668. }
  669. else
  670. {
  671. _snprintf( pBuffer, numBufferBytes, "X%d%s", iController, szRootName );
  672. }
  673. return pBuffer;
  674. }
  675. //-----------------------------------------------------------------------------
  676. // XBX_GetStorageDeviceId
  677. //
  678. // Returns the xbox storage device ID for the given controller
  679. //-----------------------------------------------------------------------------
  680. DWORD XBX_GetStorageDeviceId( int iController )
  681. {
  682. #if defined( _DEMO ) && defined( _X360 )
  683. // Demos are not allowed to access storage devices
  684. return XBX_STORAGE_DECLINED;
  685. #endif
  686. if ( iController >= 0 && iController < XUSER_MAX_COUNT )
  687. return g_iStorageDeviceId[ iController ];
  688. else
  689. return XBX_INVALID_STORAGE_ID;
  690. }
  691. //-----------------------------------------------------------------------------
  692. // XBX_SetStorageDeviceId
  693. //
  694. // Sets the xbox storage device ID for the given controller
  695. //-----------------------------------------------------------------------------
  696. void XBX_SetStorageDeviceId( int iController, DWORD id )
  697. {
  698. Msg( "XBX_SetStorageDeviceId: device 0x%08X set for ctrlr%d!\n",
  699. id, iController );
  700. if ( iController >= 0 && iController < XUSER_MAX_COUNT )
  701. {
  702. g_iStorageDeviceId[ iController ] = id;
  703. }
  704. else
  705. {
  706. Assert( iController >= 0 && iController < XUSER_MAX_COUNT );
  707. }
  708. }
  709. //-----------------------------------------------------------------------------
  710. // XBX_GetPrimaryUserId
  711. //
  712. // Returns the active user ID
  713. //-----------------------------------------------------------------------------
  714. DWORD XBX_GetPrimaryUserId( void )
  715. {
  716. #ifdef _PS3
  717. return ( g_iPrimaryUserId != XBX_INVALID_USER_ID ) ? g_iPrimaryUserId : 0;
  718. #else
  719. return g_iPrimaryUserId;
  720. #endif
  721. }
  722. //-----------------------------------------------------------------------------
  723. // XBX_SetPrimaryUserId
  724. //
  725. // Sets the active user ID
  726. //-----------------------------------------------------------------------------
  727. void XBX_SetPrimaryUserId( DWORD idx )
  728. {
  729. g_iPrimaryUserId = idx;
  730. }
  731. //-----------------------------------------------------------------------------
  732. // XBX_GetPrimaryUserIsGuest
  733. //
  734. // Returns zero (FALSE) if primary user is a real account
  735. // Returns non-zero (TRUE) if primary user is a guest account
  736. //-----------------------------------------------------------------------------
  737. DWORD XBX_GetPrimaryUserIsGuest( void )
  738. {
  739. return g_bPrimaryUserIsGuest;
  740. }
  741. //-----------------------------------------------------------------------------
  742. // XBX_SetPrimaryUserIsGuest
  743. //
  744. // Sets if primary user is a guest account
  745. //-----------------------------------------------------------------------------
  746. void XBX_SetPrimaryUserIsGuest( DWORD bPrimaryUserIsGuest )
  747. {
  748. g_bPrimaryUserIsGuest = bPrimaryUserIsGuest;
  749. }
  750. //-----------------------------------------------------------------------------
  751. // XBX_GetNumGameUsers
  752. //
  753. // Returns number of users for the game mode
  754. //-----------------------------------------------------------------------------
  755. DWORD XBX_GetNumGameUsers( void )
  756. {
  757. return g_numGameUsers;
  758. }
  759. //-----------------------------------------------------------------------------
  760. // XBX_SetNumGameUsers
  761. //
  762. // Sets number of users for the game mode
  763. //-----------------------------------------------------------------------------
  764. void XBX_SetNumGameUsers( DWORD numGameUsers )
  765. {
  766. g_numGameUsers = numGameUsers;
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Purpose: Returns the stored session ID for a cross-game invite
  770. //-----------------------------------------------------------------------------
  771. XNKID XBX_GetInviteSessionId( void )
  772. {
  773. return g_InviteSessionId;
  774. }
  775. //-----------------------------------------------------------------------------
  776. // Purpose: Store a session ID for an invitation
  777. //-----------------------------------------------------------------------------
  778. void XBX_SetInviteSessionId( XNKID nSessionId )
  779. {
  780. g_InviteSessionId = nSessionId;
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Purpose: Get the Id of the user who received an invite
  784. //-----------------------------------------------------------------------------
  785. DWORD XBX_GetInvitedUserId( void )
  786. {
  787. #ifdef _PS3
  788. return ( g_InvitedUserId != XBX_INVALID_USER_ID ) ? 0 : XBX_INVALID_USER_ID; // invited user will be the primary user = 0
  789. #else
  790. return g_InvitedUserId;
  791. #endif
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Purpose: Set the Id of the user who received an invite
  795. //-----------------------------------------------------------------------------
  796. void XBX_SetInvitedUserId( DWORD nUserId )
  797. {
  798. g_InvitedUserId = nUserId;
  799. }
  800. //-----------------------------------------------------------------------------
  801. // Purpose: Get the Id of the user who received an invite
  802. //-----------------------------------------------------------------------------
  803. XUID XBX_GetInvitedUserXuid( void )
  804. {
  805. return g_InvitedUserXuid;
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Purpose: Set the Id of the user who received an invite
  809. //-----------------------------------------------------------------------------
  810. void XBX_SetInvitedUserXuid( XUID xuid )
  811. {
  812. g_InvitedUserXuid = xuid;
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose: Maps the physical controllers to splitscreen slots
  816. //-----------------------------------------------------------------------------
  817. static int XBX_UserIndexToSlot[XUSER_MAX_COUNT] =
  818. {
  819. 0,
  820. 1,
  821. 2,
  822. 3
  823. };
  824. //-----------------------------------------------------------------------------
  825. // Purpose: Maps the splitscreen slots to physical controllers
  826. //-----------------------------------------------------------------------------
  827. static int XBX_SlotToUserIndex[XUSER_MAX_COUNT] =
  828. {
  829. 0,
  830. 1,
  831. 2,
  832. 3
  833. };
  834. //-----------------------------------------------------------------------------
  835. // Purpose: Maps slots to guest status
  836. //-----------------------------------------------------------------------------
  837. static DWORD XBX_SlotToUserIsGuest[XUSER_MAX_COUNT] =
  838. {
  839. 0,
  840. 0,
  841. 0,
  842. 0
  843. };
  844. //-----------------------------------------------------------------------------
  845. void XBX_ResetUserIdSlots()
  846. {
  847. Msg( "XBX_ResetUserIdSlots\n" );
  848. for ( int i = 0; i < XUSER_MAX_COUNT; ++i )
  849. {
  850. XBX_UserIndexToSlot[i] = i;
  851. XBX_SlotToUserIndex[i] = i;
  852. XBX_SlotToUserIsGuest[i] = 0;
  853. }
  854. }
  855. //-----------------------------------------------------------------------------
  856. void XBX_ClearUserIdSlots()
  857. {
  858. Msg( "XBX_ClearUserIdSlots\n" );
  859. for ( int i = 0; i < XUSER_MAX_COUNT; ++i )
  860. {
  861. XBX_UserIndexToSlot[i] = (int)XBX_INVALID_USER_ID;
  862. XBX_SlotToUserIndex[i] = (int)XBX_INVALID_USER_ID;
  863. XBX_SlotToUserIsGuest[i] = 0;
  864. }
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Return the split screen slot based on a controller index
  868. // May return -1 if no slot has been asssigned to that controller
  869. int XBX_GetSlotByUserId( int idx )
  870. {
  871. if ( idx >= 0 && idx <= XUSER_MAX_COUNT )
  872. {
  873. return XBX_UserIndexToSlot[ idx ];
  874. }
  875. else
  876. {
  877. Assert( idx >= 0 && idx <= XUSER_MAX_COUNT );
  878. return -1;
  879. }
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Return the controller assigned to a splitscreen slot
  883. // May return -1 if no controller has been asssigned to that slot
  884. int XBX_GetUserId( int nSlot )
  885. {
  886. if ( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS )
  887. {
  888. return XBX_SlotToUserIndex[nSlot];
  889. }
  890. else
  891. {
  892. Assert( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS );
  893. return -1;
  894. }
  895. }
  896. //-----------------------------------------------------------------------------
  897. void XBX_SetUserId( int nSlot, int idx )
  898. {
  899. if ( ( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS ) &&
  900. ( idx >= 0 && idx <= XUSER_MAX_COUNT ) )
  901. {
  902. XBX_SlotToUserIndex[nSlot] = idx;
  903. XBX_UserIndexToSlot[idx] = nSlot;
  904. }
  905. else
  906. {
  907. Assert( "XBX_SetUserId" );
  908. }
  909. }
  910. //-----------------------------------------------------------------------------
  911. void XBX_ClearSlot( int nSlot )
  912. {
  913. if ( !( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS ) )
  914. {
  915. Assert( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS );
  916. return;
  917. }
  918. int iCtrlr = XBX_SlotToUserIndex[nSlot];
  919. if ( iCtrlr >= 0 && iCtrlr < XUSER_MAX_COUNT )
  920. {
  921. XBX_UserIndexToSlot[ iCtrlr ] = (int)XBX_INVALID_USER_ID;
  922. }
  923. XBX_SlotToUserIndex[nSlot] = (int)XBX_INVALID_USER_ID;
  924. XBX_SlotToUserIsGuest[nSlot] = 0;
  925. }
  926. //-----------------------------------------------------------------------------
  927. void XBX_ClearUserId( int idx )
  928. {
  929. if ( !( idx >= 0 && idx <= XUSER_MAX_COUNT ) )
  930. {
  931. Assert( idx >= 0 && idx <= XUSER_MAX_COUNT );
  932. return;
  933. }
  934. int iSlot = XBX_UserIndexToSlot[idx];
  935. if ( iSlot >= 0 && iSlot <= MAX_SPLITSCREEN_CLIENTS )
  936. {
  937. XBX_SlotToUserIndex[iSlot] = (int)XBX_INVALID_USER_ID;
  938. XBX_SlotToUserIsGuest[iSlot] = 0;
  939. }
  940. XBX_UserIndexToSlot[idx] = (int)XBX_INVALID_USER_ID;
  941. }
  942. //-----------------------------------------------------------------------------
  943. DWORD XBX_GetUserIsGuest( int nSlot )
  944. {
  945. if ( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS )
  946. {
  947. return XBX_SlotToUserIsGuest[nSlot];
  948. }
  949. else
  950. {
  951. Assert( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS );
  952. return 0;
  953. }
  954. }
  955. //-----------------------------------------------------------------------------
  956. void XBX_SetUserIsGuest( int nSlot, DWORD dwUserIsGuest )
  957. {
  958. if ( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS )
  959. {
  960. XBX_SlotToUserIsGuest[nSlot] = dwUserIsGuest;
  961. }
  962. else
  963. {
  964. Assert( nSlot >= 0 && nSlot <= MAX_SPLITSCREEN_CLIENTS );
  965. }
  966. }
  967. //-----------------------------------------------------------------------------
  968. #ifdef _X360
  969. static CXboxLaunch g_XBoxLaunch;
  970. CXboxLaunch *XboxLaunch()
  971. {
  972. return &g_XBoxLaunch;
  973. }
  974. #endif
  975. //
  976. // Xbx dynamic event queue implementation
  977. //
  978. void CXbxEventQueue::AppendEvent( xevent_t const &xevt )
  979. {
  980. AUTO_LOCK( m_mtx );
  981. if ( m_bDispatching )
  982. {
  983. Assert( !m_bDispatching );
  984. Error( "CXbxEventQueue::AppendEvent during Dispatch is not allowed!\n" );
  985. return;
  986. }
  987. // Check if we need more capacity
  988. if ( m_dwCount == m_dwAllocated )
  989. {
  990. m_dwAllocated = MAX( m_dwAllocated * 2, s_nQueueNormalSize ); // New size is at least double old size or at least for 32 items
  991. xevent_t *pNewQueue = new xevent_t[ m_dwAllocated ]; // Allocate the new size
  992. if ( m_pQueue )
  993. {
  994. memcpy( pNewQueue, m_pQueue, m_dwCount * sizeof( xevent_t ) ); // Copy events queued so far
  995. delete [] m_pQueue; // Free old event queue memory
  996. }
  997. m_pQueue = pNewQueue; // Now we are pointing a larger chunk of memory, preserved data and size
  998. }
  999. m_pQueue[ m_dwCount ++ ] = xevt;
  1000. }
  1001. void CXbxEventQueue::Dispatch()
  1002. {
  1003. AUTO_LOCK( m_mtx );
  1004. if ( !ThreadInMainThread() )
  1005. {
  1006. Assert( !"ThreadInMainThread()" );
  1007. Error( "CXbxEventQueue::Dispatch not on main thread!\n" );
  1008. return;
  1009. }
  1010. if ( m_bDispatching )
  1011. {
  1012. Assert( !m_bDispatching );
  1013. Error( "CXbxEventQueue::Dispatch is no reentry!\n" );
  1014. return;
  1015. }
  1016. m_bDispatching = true;
  1017. // pump event queue
  1018. for ( DWORD k = 0; k < m_dwCount; ++ k )
  1019. {
  1020. xevent_t *pEvent = &m_pQueue[ k ];
  1021. switch ( pEvent->event )
  1022. {
  1023. case XEV_REMOTECMD:
  1024. XBX_ProcessXCommand( *pEvent );
  1025. break;
  1026. case XEV_LISTENER_NOTIFICATION:
  1027. XBX_ProcessListenerNotification( *pEvent );
  1028. break;
  1029. }
  1030. }
  1031. m_dwCount = 0;
  1032. if ( m_dwAllocated >= s_nQueueAbnormalSize )
  1033. {
  1034. m_dwAllocated = 0;
  1035. delete [] m_pQueue;
  1036. m_pQueue = NULL;
  1037. }
  1038. m_bDispatching = false;
  1039. }
  1040. bool CXbxEventQueue::IsDispatching() const
  1041. {
  1042. // No mutex lock in this case because if the thread
  1043. // is currently dispatching the queue, then it is currently
  1044. // owning the queue mutex and can check the bool directly.
  1045. // If the thread currently doesn't own the mutex, then the
  1046. // operation on the queue will attempt to acquire the mutex
  1047. // and it should be safe for the thread to stall anyway,
  1048. // so the out-of-date information about whether the queue is
  1049. // dispatching is not a concern.
  1050. return m_bDispatching;
  1051. }