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.

985 lines
28 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A redirection tool that allows the DLLs to reside elsewhere.
  4. //
  5. //=====================================================================================//
  6. #if defined( _WIN32 ) && !defined( _X360 )
  7. #include <windows.h>
  8. #include <stdio.h>
  9. #include <assert.h>
  10. #include <direct.h>
  11. #endif
  12. #if defined( _X360 )
  13. #define _XBOX
  14. #include <xtl.h>
  15. #include <xbdm.h>
  16. #undef _XBOX
  17. #include <stdio.h>
  18. #include <assert.h>
  19. #include "xbox\xbox_core.h"
  20. #include "xbox\xbox_launch.h"
  21. #elif defined( SN_TARGET_PS3 )
  22. #include "../public/ps3_pathinfo.h"
  23. #include <stddef.h>
  24. #include <cell/fios/fios_common.h>
  25. #include <cell/fios/fios_memory.h>
  26. #include <cell/fios/fios_configuration.h>
  27. #include <cell/fios/fios_time.h>
  28. #include <sys/tty.h>
  29. #include <sys/ppu_thread.h>
  30. #include "tier0/vprof_sn.h"
  31. #include "errorrenderloop.h"
  32. //#if defined( VPROF_SN_LEVEL )
  33. #include "sn/libsntuner.h"
  34. #include "libsn.h"
  35. //#endif
  36. #endif
  37. #ifdef POSIX
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #ifndef SN_TARGET_PS3
  41. #include <dlfcn.h>
  42. #endif // SN_TARGET_PS3
  43. #include <limits.h>
  44. #include <string.h>
  45. #define MAX_PATH PATH_MAX
  46. #endif
  47. #include "tier0/platform.h"
  48. #include "tier0/basetypes.h"
  49. #if defined( VPCGAME )
  50. #define _VPCGAME_STRING_HACK2(x) #x
  51. #define _VPCGAME_STRING_HACK1(x) _VPCGAME_STRING_HACK2(x)
  52. #define VPCGAME_STRING _VPCGAME_STRING_HACK1(VPCGAME)
  53. #endif
  54. #ifdef WIN32
  55. typedef int (*LauncherMain_t)( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  56. LPSTR lpCmdLine, int nCmdShow );
  57. #elif POSIX
  58. typedef int (*LauncherMain_t)( int argc, char **argv );
  59. #else
  60. #error
  61. #endif
  62. #ifdef WIN32
  63. // hinting the nvidia driver to use the dedicated graphics card in an optimus configuration
  64. // for more info, see: http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/OptimusRenderingPolicies.pdf
  65. extern "C" { _declspec( dllexport ) DWORD NvOptimusEnablement = 0x00000001; }
  66. // same thing for AMD GPUs using v13.35 or newer drivers
  67. extern "C" { __declspec( dllexport ) int AmdPowerXpressRequestHighPerformance = 1; }
  68. #endif
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Return the directory where this .exe is running from
  71. // Output : char
  72. //-----------------------------------------------------------------------------
  73. #if !defined( _X360 )
  74. #ifdef WIN32
  75. static char *GetBaseDir( const char *pszBuffer )
  76. {
  77. static char basedir[ MAX_PATH ];
  78. char szBuffer[ MAX_PATH ];
  79. size_t j;
  80. char *pBuffer = NULL;
  81. strcpy( szBuffer, pszBuffer );
  82. pBuffer = strrchr( szBuffer,'\\' );
  83. if ( pBuffer )
  84. {
  85. *(pBuffer+1) = '\0';
  86. }
  87. strcpy( basedir, szBuffer );
  88. j = strlen( basedir );
  89. if (j > 0)
  90. {
  91. if ( ( basedir[ j-1 ] == '\\' ) ||
  92. ( basedir[ j-1 ] == '/' ) )
  93. {
  94. basedir[ j-1 ] = 0;
  95. }
  96. }
  97. return basedir;
  98. }
  99. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
  100. {
  101. // Must add 'bin' to the path....
  102. char* pPath = getenv("PATH");
  103. // Use the .EXE name to determine the root directory
  104. char moduleName[ MAX_PATH ];
  105. char szBuffer[4096];
  106. if ( !GetModuleFileName( hInstance, moduleName, MAX_PATH ) )
  107. {
  108. MessageBox( 0, "Failed calling GetModuleFileName", "Launcher Error", MB_OK );
  109. return 0;
  110. }
  111. // Get the root directory the .exe is in
  112. char* pRootDir = GetBaseDir( moduleName );
  113. const char* pBinPath =
  114. #ifdef _WIN64
  115. "\\x64"
  116. #else
  117. ""
  118. #endif
  119. ;
  120. #ifdef _DEBUG
  121. int len =
  122. #endif
  123. _snprintf( szBuffer, sizeof( szBuffer ), "PATH=%s\\bin%s\\;%s", pRootDir, pBinPath, pPath );
  124. szBuffer[sizeof( szBuffer ) - 1] = '\0';
  125. assert( len < sizeof( szBuffer ) );
  126. _putenv( szBuffer );
  127. // Assemble the full path to our "launcher.dll"
  128. _snprintf( szBuffer, sizeof( szBuffer ), "%s\\bin%s\\launcher.dll", pRootDir, pBinPath );
  129. szBuffer[sizeof( szBuffer ) - 1] = '\0';
  130. // STEAM OK ... filesystem not mounted yet
  131. #if defined(_X360)
  132. HINSTANCE launcher = LoadLibrary( szBuffer );
  133. #else
  134. HINSTANCE launcher = LoadLibraryEx( szBuffer, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  135. #endif
  136. if ( !launcher )
  137. {
  138. char *pszError;
  139. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pszError, 0, NULL);
  140. char szBuf[1024];
  141. _snprintf(szBuf, sizeof( szBuf ), "Failed to load the launcher DLL:\n\n%s", pszError);
  142. szBuf[sizeof( szBuf ) - 1] = '\0';
  143. MessageBox( 0, szBuf, "Launcher Error", MB_OK );
  144. LocalFree(pszError);
  145. return 0;
  146. }
  147. LauncherMain_t main = (LauncherMain_t)GetProcAddress( launcher, "LauncherMain" );
  148. return main( hInstance, hPrevInstance, lpCmdLine, nCmdShow );
  149. }
  150. #elif defined( SN_TARGET_PS3 )
  151. #if defined( __GCC__ )
  152. #define COMPILER_GCC
  153. #elif defined( __SNC__ )
  154. #define COMPILER_SNC
  155. #endif
  156. #include "../public/tls_ps3.h"
  157. #include "sys/process.h"
  158. // We need to avoid printf before we
  159. // configure our custom memory allocator
  160. #define printf(...) ((void)0)
  161. #include "../common/ps3/ps3_helpers.h"
  162. #ifdef APPCHANGELISTVERSION
  163. // write the changelist number into the executable so that the GUID changes between builds.
  164. // previously, setting the version number via the SYS_MODULE_INFO was good enough to do
  165. // this, but not after sdk 350.
  166. volatile unsigned int clnumber = APPCHANGELISTVERSION;
  167. __attribute__ ((noinline)) void DummyFuncForUpdatingGUIDs( char *pOut )
  168. {
  169. sprintf( pOut, "%x", clnumber );
  170. }
  171. #else // absent appchangelistversion, invent one
  172. volatile unsigned int clnumber = 0;
  173. #define DUMMY_VER_STRING __DATE__ " " __TIME__
  174. volatile char dummyVersionDateString[] = DUMMY_VER_STRING "\n";
  175. __attribute__ ((noinline)) void DummyFuncForUpdatingGUIDs( char *pOut )
  176. {
  177. sprintf( pOut, DUMMY_VER_STRING );
  178. }
  179. #undef DUMMY_VER_STRING
  180. #endif
  181. // 1 Mb stack is maximum allowed for the main thread
  182. // and we will make good use of it
  183. SYS_PROCESS_PARAM( 1000, 1 * 1024 * 1024 )
  184. /////////////////////////////////////////////////////////////////////////////////////////////////////
  185. // All thread-local storage must reside in the ELF and be exported for PRXes to use it
  186. /////////////////////////////////////////////////////////////////////////////////////////////////////
  187. __thread TLSGlobals gTLSGlobals =
  188. {
  189. // TLS values/flags
  190. /*nThreadLocalStateIndex*/ 0,
  191. /*TLSValues*/ { NULL },
  192. /*TLSFlags*/ { false },
  193. /*bWaitObjectsCreated*/ false,
  194. /*WaitObjectsSemaphore*/ 0,
  195. /*pCurThread*/ NULL,
  196. /*nThreadID*/ 0,
  197. // Engine TLS data (zip/console/splitslot)
  198. /*uiEngineZipLastErrorZ*/ 0,
  199. /*bEngineConsoleIsInSpew*/ false,
  200. /*pEngineSplitSlot*/ NULL,
  201. // Malloc debugging TLS data
  202. /*pMallocDbgInfoStack*/ NULL,
  203. /*nMallocDbgInfoStackDepth*/ 0,
  204. // Filesystem read filename buffer
  205. /*pFileSystemReadFilename*/ NULL,
  206. // Material system render context
  207. /*pMaterialSystemRenderContext*/ NULL,
  208. // Physics virtual mesh frame locks
  209. /*pPhysicsVirtualMeshFrameLocks*/ NULL,
  210. /*bNormalQuitRequested*/ false
  211. };
  212. TLSGlobals *GetTLSGlobals_ELF() { return &gTLSGlobals; }
  213. extern CPs3ContentPathInfo g_Ps3GameDataPathInfo;
  214. template< typename BaseStruct >
  215. struct PS3MainParameters : public BaseStruct
  216. {
  217. PS3MainParameters() { memset( this, 0, sizeof( BaseStruct ) ); BaseStruct::cbSize = sizeof( BaseStruct ); }
  218. };
  219. struct PS3_Launch_t
  220. {
  221. explicit PS3_Launch_t( char const *szPrxName, PS3_PrxLoadParametersBase_t *pParams ) :
  222. m_szPrxName( szPrxName ), m_pPrxParams( pParams )
  223. {
  224. m_iResult = PS3_PrxLoad( m_szPrxName, m_pPrxParams );
  225. if ( m_iResult < CELL_OK )
  226. {
  227. printf( "ERROR: %s PRX load failed: 0x%08x\n", m_szPrxName, m_iResult );
  228. }
  229. else
  230. {
  231. printf( "Loaded: %s (0x%08x)\n", m_szPrxName, m_iResult );
  232. }
  233. }
  234. char const *m_szPrxName;
  235. PS3_PrxLoadParametersBase_t *m_pPrxParams;
  236. int m_iResult;
  237. };
  238. static const char *LauncherMainSPRXPath( const char *modulename, char *buf, int buflen = CELL_GAME_PATH_MAX ) // formats a path to the module. returns a pointer to the buf param for convenience.
  239. {
  240. snprintf( buf, buflen, "%s/%s" DLL_EXT_STRING, g_Ps3GameDataPathInfo.PrxPath(), modulename );
  241. return buf;
  242. }
  243. #if defined( SN_TARGET_PS3 )
  244. void TunerMarkerPush( const char * pName )
  245. {
  246. //#if defined( VPROF_SN_LEVEL )
  247. snPushMarker( pName );
  248. //#endif
  249. }
  250. void TunerMarkerPop()
  251. {
  252. //#if defined( VPROF_SN_LEVEL )
  253. snPopMarker();
  254. //#endif
  255. }
  256. // this is debug-only counter; never use it for anything other than debugging!
  257. uint64_t g_nDebugSwapBufferCount = 0;
  258. void TunerSwapBufferMarker()
  259. {
  260. // this dummy function is only required as a patch-through for Tuner that attaches to the game after the game has been started, as a convenience funciton/
  261. // it must be called at every frame boundary (presumably at/after psglSwap )
  262. g_nDebugSwapBufferCount++;
  263. }
  264. #endif
  265. PS3_PrxModuleEntry_t *g_pPrxModulesList = NULL;
  266. PS3_PrxModuleEntry_t ** PS3_PrxGetModulesList() { return &g_pPrxModulesList; }
  267. void TestThreadProc( uint64_t id )
  268. {
  269. printf( "Hello from PPU thread %lld\n", id );
  270. sys_ppu_thread_exit( id );
  271. }
  272. void TestThreads( int nLevel = 0)
  273. {
  274. printf("testing threads\n");
  275. const int numThreads = 20;
  276. sys_ppu_thread_t id[numThreads];
  277. for( int i = 0;i < numThreads; ++i )
  278. {
  279. if( nLevel > 0 )
  280. TestThreads( nLevel - 1 );
  281. if( CELL_OK != sys_ppu_thread_create( &id[i], TestThreadProc, i, 1001, 64*1024, SYS_PPU_THREAD_CREATE_JOINABLE, "SimpleThread" ) )
  282. {
  283. printf("ERROR: cannot create thread\n");
  284. return;
  285. }
  286. }
  287. for( int i = 0;i < numThreads; ++i )
  288. {
  289. uint64_t res;
  290. sys_ppu_thread_join( id[i], &res );
  291. if( res != i )
  292. {
  293. printf("ERROR: invalid thread return value\n");
  294. return;
  295. }
  296. }
  297. }
  298. int MainImpl( int argc, char *argv[] )
  299. {
  300. // #ifdef _CERT // possibly enable it for ship to disable command line cheating?
  301. #if 0
  302. // Disable command line support for shipping unless -certcmdline specified
  303. if ( ( argc > 1 ) && !strcmp( argv[1], "-certcmdline" ) )
  304. {
  305. argc = 1;
  306. }
  307. #endif
  308. // this is the very first timing message, before tier0 is even initialized and we can use any
  309. // logging or timing facilities; this is the baseline to measure loading times
  310. cell::fios::abstime_t fiosLaunchTime = cell::fios::FIOSGetCurrentTime();
  311. #ifndef _CERT
  312. {
  313. double flTime = cell::fios::FIOSAbstimeToMicroseconds( fiosLaunchTime ) * 1e-6;
  314. char buffer[4096];
  315. int nMessageSize = snprintf(buffer, sizeof(buffer), "--------------------------------------\n 0.0000 / %8.4f : launcher_main(", flTime );
  316. for( int i = 0;i < argc && nMessageSize < sizeof(buffer)-4; ++i )
  317. {
  318. // add delimiters
  319. if( i > 0 )
  320. buffer[nMessageSize++] = ',';
  321. nMessageSize += snprintf( buffer + nMessageSize, sizeof(buffer) - nMessageSize, " \"%s\"", argv[i] );
  322. }
  323. nMessageSize += snprintf(buffer + nMessageSize, sizeof(buffer) - nMessageSize, " )\n" );
  324. unsigned wrote;
  325. sys_tty_write( SYS_TTYP6, buffer, nMessageSize, &wrote );
  326. }
  327. #endif
  328. // this is a dummy operation to force the compiler to not elide the
  329. // changelist GUID. It's really necessary, because otherwise the compiler
  330. // will notice the function isn't called, and elide it, and the GUID string,
  331. // altogether. Because the compiler "can't" know what argc will be, it has
  332. // to compile in the function call here. This is the only way to guarantee
  333. // that different builds will have different GUIDs, because we don't often
  334. // change launcher_main between versions, and the PRXes don't get individual
  335. // GUIDs in the dump.
  336. // Don't pass in more than one million commandline
  337. // parameters or this will corrupt the one millionth.
  338. if ( argc > 100000000 )
  339. {
  340. DummyFuncForUpdatingGUIDs( argv[100000000] );
  341. }
  342. char path[CELL_GAME_PATH_MAX];
  343. bool bDevHddCfgOnly = false;
  344. bool bRunLauncherMain = true;
  345. bool bSupportPathLegacyArgs = true;
  346. bool bEnableMlaa = true;
  347. #ifdef HDD_BOOT
  348. unsigned int uiInitFlags = CPs3ContentPathInfo::INIT_PRX_ON_HDD | CPs3ContentPathInfo::INIT_IMAGE_ON_HDD;
  349. #else
  350. unsigned int uiInitFlags = CPs3ContentPathInfo::INIT_RETAIL_MODE; // assume that if no arguments are specified we are going to run in retail mode
  351. #endif
  352. // uncomment the following in order to allow starting game in /app_home from XMB (shortcutting creating disk image)
  353. // uiInitFlags = CPs3ContentPathInfo::INIT_PRX_APP_HOME | CPs3ContentPathInfo::INIT_IMAGE_APP_HOME;
  354. for ( int k = 0; k < argc; ++ k )
  355. {
  356. if( !strcmp( "-noMlaa", argv[k] ) )
  357. {
  358. bEnableMlaa = false;
  359. }
  360. else if ( !strcmp( "-errorrenderloop", argv[k] ) )
  361. {
  362. return -1;
  363. }
  364. else if ( !strcmp( "-devhddcfgonly", argv[k] ) )
  365. {
  366. bDevHddCfgOnly = true;
  367. }
  368. else if ( !strcmp( "-nolaunchermain", argv[k] ) )
  369. {
  370. bRunLauncherMain = false;
  371. }
  372. else if ( !strcmp( "-syscacheclear", argv[k] ) )
  373. {
  374. uiInitFlags |= CPs3ContentPathInfo::INIT_SYS_CACHE_CLEAR;
  375. }
  376. else if ( !strncmp( "-path_retail", argv[k], 12 ) )
  377. {
  378. bSupportPathLegacyArgs = false;
  379. if ( argv[k][12] )
  380. uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  381. }
  382. else if ( !strncmp( "-path_prx_", argv[k], 10 ) )
  383. {
  384. char chPrxPathMode = argv[k][10];
  385. switch ( chPrxPathMode )
  386. {
  387. case 'h': uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_ON_HDD; break;
  388. case 'b': uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_ON_BDVD; break;
  389. case 'a': uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_APP_HOME; break;
  390. }
  391. }
  392. else if ( !strncmp( "-path_img_", argv[k], 10 ) )
  393. {
  394. char chPrxPathMode = argv[k][10];
  395. switch ( chPrxPathMode )
  396. {
  397. case 'h': uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_ON_HDD; break;
  398. case 'b': uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_ON_BDVD; break;
  399. case 'a': uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_APP_HOME; break;
  400. }
  401. }
  402. // LEGACY PARAMETERS because people are used to running with them (need to clean up some time later)
  403. else if ( bSupportPathLegacyArgs && !strcmp( "-dev", argv[k] ) )
  404. {
  405. uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  406. uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_APP_HOME;
  407. uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_APP_HOME;
  408. }
  409. else if ( bSupportPathLegacyArgs && !strcmp( "-ps3hd", argv[k] ) )
  410. {
  411. uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  412. uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_ON_HDD;
  413. uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_APP_HOME;
  414. }
  415. else if ( bSupportPathLegacyArgs && !strcmp( "-nops3hd", argv[k] ) )
  416. {
  417. uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  418. uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_APP_HOME;
  419. uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_APP_HOME;
  420. }
  421. else if ( bSupportPathLegacyArgs && !strcmp( "-dev_bdvd", argv[k] ) )
  422. {
  423. uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  424. uiInitFlags |= CPs3ContentPathInfo::INIT_IMAGE_ON_BDVD;
  425. uiInitFlags |= CPs3ContentPathInfo::INIT_PRX_APP_HOME;
  426. }
  427. // END LEGACY PARAMETERS
  428. }
  429. // uncomment the following to hard code for Eurogamer (as if running -dev)
  430. #ifdef _PS3
  431. // uiInitFlags &=~CPs3ContentPathInfo::INIT_RETAIL_MODE;
  432. #endif
  433. int iPathInfoInitResult = g_Ps3GameDataPathInfo.Init( uiInitFlags );
  434. if ( iPathInfoInitResult < 0 )
  435. return iPathInfoInitResult;
  436. if ( bDevHddCfgOnly )
  437. return 0;
  438. PS3MainParameters< PS3_LoadTier0_Parameters_t > tier0;
  439. tier0.pfnGetTlsGlobals = GetTLSGlobals_ELF;
  440. tier0.pPS3PathInfo = &g_Ps3GameDataPathInfo;
  441. tier0.fiosLaunchTime = fiosLaunchTime;
  442. tier0.nCLNumber = clnumber;
  443. tier0.pfnPushMarker = TunerMarkerPush;
  444. tier0.pfnPopMarker = TunerMarkerPop;
  445. tier0.pfnSwapBufferMarker = TunerSwapBufferMarker;
  446. tier0.ppPrxModulesList = PS3_PrxGetModulesList();
  447. tier0.m_pGcmSharedData = &g_gcmSharedData;
  448. #ifndef _CERT
  449. tier0.snRawSPULockHandler = snRawSPULockHandler;
  450. tier0.snRawSPUUnlockHandler = snRawSPUUnlockHandler;
  451. tier0.snRawSPUNotifyCreation = snRawSPUNotifyCreation;
  452. tier0.snRawSPUNotifyDestruction = snRawSPUNotifyDestruction;
  453. tier0.snRawSPUNotifyElfLoad = snRawSPUNotifyElfLoad;
  454. tier0.snRawSPUNotifyElfLoadNoWait = snRawSPUNotifyElfLoadNoWait;
  455. tier0.snRawSPUNotifyElfLoadAbs = snRawSPUNotifyElfLoadAbs;
  456. tier0.snRawSPUNotifyElfLoadAbsNoWait = snRawSPUNotifyElfLoadAbsNoWait;
  457. tier0.snRawSPUNotifySPUStopped = snRawSPUNotifySPUStopped;
  458. tier0.snRawSPUNotifySPUStarted = snRawSPUNotifySPUStarted;
  459. #endif
  460. (void)bEnableMlaa; // we'll use it if we need to init GCM and start rendering right away
  461. /*
  462. g_gcmSharedData.m_nIoMemorySize = bEnableMlaa ? 5 * 1024 * 1024 : 1 * 1024 * 1024;
  463. sys_addr_t pIoAddress = NULL;
  464. int nError = sys_memory_allocate( g_gcmSharedData.m_nIoMemorySize, SYS_MEMORY_PAGE_SIZE_1M, &pIoAddress );
  465. if( CELL_OK != nError || !pIoAddress )
  466. {
  467. // cannot allocate IO memory
  468. return -2;
  469. }
  470. int32 result = cellGcmInit( m_nCmdSize, m_nIoSize, m_pIoAddress );
  471. if ( result < CELL_OK )
  472. return result;
  473. g_gcmSharedData.m_pIoMemory = ( void* )pIoAddress;
  474. */
  475. PS3_Launch_t tier0Launch( LauncherMainSPRXPath( "tier0", path ), &tier0 );
  476. if( tier0Launch.m_iResult < CELL_OK )
  477. {
  478. return -1;
  479. }
  480. int iAppRetCode = 0;
  481. PS3MainParameters< PS3_PrxLoadParametersBase_t > vstdlib;
  482. PS3_Launch_t vstdlibLaunch( LauncherMainSPRXPath( "vstdlib", path ), &vstdlib );
  483. if( vstdlibLaunch.m_iResult >= CELL_OK )
  484. {
  485. #ifndef NO_STEAM
  486. PS3MainParameters< PS3_PrxLoadParametersBase_t > steamapi;
  487. PS3_Launch_t steamapiLaunch( LauncherMainSPRXPath( "steam_api", path ), &steamapi );
  488. if ( steamapiLaunch.m_iResult >= CELL_OK )
  489. {
  490. #endif
  491. PS3MainParameters< PS3_LoadLauncher_Parameters_t > launcher;
  492. PS3_Launch_t launcherLaunch( LauncherMainSPRXPath( "launcher", path ), &launcher );
  493. if ( launcher.pfnLauncherMain )
  494. {
  495. printf( "Launching...\n" );
  496. iAppRetCode = bRunLauncherMain ? (*launcher.pfnLauncherMain)( argc, argv ) : 0;
  497. printf( "Shutting down...\n" );
  498. launcher.pfnLauncherShutdown();
  499. }
  500. else
  501. {
  502. printf( "ERROR: failed to obtain LauncherMain entry point!\n" );
  503. }
  504. PS3_PrxUnload( launcher.sysPrxId );
  505. #ifndef NO_STEAM
  506. PS3_PrxUnload( steamapi.sysPrxId );
  507. }
  508. #endif
  509. PS3_PrxUnload( vstdlib.sysPrxId );
  510. }
  511. // Before tier0 unloads make sure that there are no modules remaining loaded
  512. #if !defined( _CERT )
  513. for ( PS3_PrxModuleEntry_t *pEntry = *PS3_PrxGetModulesList(); pEntry; pEntry = pEntry->pNextModule )
  514. {
  515. if ( strstr( pEntry->chName, "/tier0" DLL_EXT_STRING ) )
  516. continue;
  517. unsigned int dummy;
  518. char const *szWarnMsg = "EXITING WITH PRX MODULE: ";
  519. sys_tty_write( SYS_TTYP6, szWarnMsg, strlen( szWarnMsg ), &dummy );
  520. sys_tty_write( SYS_TTYP6, pEntry->chName, strlen( pEntry->chName ), &dummy );
  521. szWarnMsg = "\n";
  522. sys_tty_write( SYS_TTYP6, szWarnMsg, strlen( szWarnMsg ), &dummy );
  523. }
  524. #endif
  525. tier0.pfnTier0Shutdown();
  526. PS3_PrxUnload( tier0.sysPrxId );
  527. return iAppRetCode;
  528. }
  529. int main( int argc, char *argv[] )
  530. {
  531. // Init LibSn
  532. #ifndef _CERT
  533. snInit();
  534. #endif
  535. int nReturn = MainImpl( argc, argv );
  536. #ifndef _PS3
  537. // if( !gTLSGlobals.bNormalQuitRequested )
  538. // {
  539. // printf("no normal quit requested, starting error render loop\n");
  540. // ErrorRenderLoop loop;
  541. // loop.Run();
  542. // printf("Error render loop finished\n");
  543. // }
  544. #endif
  545. #if !defined( _CERT )
  546. if ( 1 )
  547. {
  548. unsigned int dummy;
  549. char const *szWarnMsg =
  550. (*PS3_PrxGetModulesList())
  551. ? "------- WARNING: RETURNING FROM MAIN WITH PRX MODULES RUNNING --------\n"
  552. : "--------------------------------BYE-----------------------------------\n";
  553. sys_tty_write( SYS_TTYP6, szWarnMsg, strlen( szWarnMsg ), &dummy );
  554. }
  555. #endif
  556. return nReturn;
  557. }
  558. #elif defined (POSIX)
  559. int main( int argc, char *argv[] )
  560. {
  561. #ifdef PLATFORM_64BITS
  562. #ifdef OSX
  563. const char *pLauncherPath = "bin/osx64/launcher" DLL_EXT_STRING;
  564. #else
  565. const char *pLauncherPath = "bin/linux64/launcher" DLL_EXT_STRING;
  566. #endif
  567. #else
  568. const char *pLauncherPath = "bin/launcher" DLL_EXT_STRING;
  569. #endif
  570. void *launcher = dlopen( pLauncherPath, RTLD_NOW );
  571. if ( !launcher )
  572. {
  573. printf( "Failed to load the launcher (%s)\n", dlerror() );
  574. while(1);
  575. return 0;
  576. }
  577. LauncherMain_t main = (LauncherMain_t)dlsym( launcher, "LauncherMain" );
  578. if ( !main )
  579. {
  580. printf( "Failed to load the launcher entry proc\n" );
  581. while(1);
  582. return 0;
  583. }
  584. return main( argc, argv );
  585. }
  586. #else
  587. #error
  588. #endif // WIN32 || POSIX
  589. #else // X360
  590. //-----------------------------------------------------------------------------
  591. // 360 Quick and dirty command line parsing. Returns true if key found,
  592. // false otherwise. Caller can optionally get next argument.
  593. //-----------------------------------------------------------------------------
  594. bool ParseCommandLineArg( const char *pCmdLine, const char* pKey, char* pValueBuff = NULL, int valueBuffSize = 0 )
  595. {
  596. int keyLen = (int)strlen( pKey );
  597. const char* pArg = pCmdLine;
  598. for ( ;; )
  599. {
  600. // scan for match
  601. pArg = strstr( (char*)pArg, pKey );
  602. if ( !pArg )
  603. {
  604. return false;
  605. }
  606. // found, but could be a substring
  607. if ( pArg[keyLen] == '\0' || pArg[keyLen] == ' ' )
  608. {
  609. // exact match
  610. break;
  611. }
  612. pArg += keyLen;
  613. }
  614. if ( pValueBuff )
  615. {
  616. // caller wants next token
  617. // skip past key and whitespace
  618. pArg += keyLen;
  619. while ( *pArg == ' ' )
  620. {
  621. pArg++;
  622. }
  623. int i;
  624. for ( i=0; i<valueBuffSize; i++ )
  625. {
  626. pValueBuff[i] = *pArg;
  627. if ( *pArg == '\0' || *pArg == ' ' )
  628. break;
  629. pArg++;
  630. }
  631. pValueBuff[i] = '\0';
  632. }
  633. return true;
  634. }
  635. //-----------------------------------------------------------------------------
  636. // 360 Quick and dirty command line arg stripping.
  637. //-----------------------------------------------------------------------------
  638. void StripCommandLineArg( const char *pCmdLine, char *pNewCmdLine, const char *pStripArg )
  639. {
  640. // cannot operate in place
  641. assert( pCmdLine != pNewCmdLine );
  642. int numTotal = strlen( pCmdLine ) + 1;
  643. const char* pArg = strstr( pCmdLine, pStripArg );
  644. if ( !pArg )
  645. {
  646. strcpy( pNewCmdLine, pCmdLine );
  647. return;
  648. }
  649. int numDiscard = strlen( pStripArg );
  650. while ( pArg[numDiscard] && ( pArg[numDiscard] != '-' && pArg[numDiscard] != '+' ) )
  651. {
  652. // eat whitespace up to the next argument
  653. numDiscard++;
  654. }
  655. memcpy( pNewCmdLine, pCmdLine, pArg - pCmdLine );
  656. memcpy( pNewCmdLine + ( pArg - pCmdLine ), (void*)&pArg[numDiscard], numTotal - ( pArg + numDiscard - pCmdLine ) );
  657. // ensure we don't leave any trailing whitespace, occurs if last arg is stripped
  658. int len = strlen( pNewCmdLine );
  659. while ( len > 0 && pNewCmdLine[len-1] == ' ' )
  660. {
  661. len--;
  662. }
  663. pNewCmdLine[len] = '\0';
  664. }
  665. //-----------------------------------------------------------------------------
  666. // 360 Conditional spew
  667. //-----------------------------------------------------------------------------
  668. void Spew( const char *pFormat, ... )
  669. {
  670. #if defined( _DEBUG )
  671. char msg[2048];
  672. va_list argptr;
  673. va_start( argptr, pFormat );
  674. vsprintf( msg, pFormat, argptr );
  675. va_end( argptr );
  676. OutputDebugString( msg );
  677. #endif
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Get the new entry point and command line
  681. //-----------------------------------------------------------------------------
  682. LauncherMain_t GetLaunchEntryPoint( char *pNewCommandLine )
  683. {
  684. HMODULE hModule;
  685. char *pCmdLine;
  686. // determine source of our invocation, internal or external
  687. // a valid launch payload will have an embedded command line
  688. // command line could be from internal restart in dev or retail mode
  689. CXboxLaunch xboxLaunch;
  690. int payloadSize;
  691. unsigned int launchID;
  692. char *pPayload;
  693. bool bInternalRestart = xboxLaunch.GetLaunchData( &launchID, (void**)&pPayload, &payloadSize );
  694. if ( !bInternalRestart || !payloadSize || launchID != VALVE_LAUNCH_ID )
  695. {
  696. // could be first time, get command line from system
  697. pCmdLine = GetCommandLine();
  698. if ( !stricmp( pCmdLine, "\"default.xex\"" ) )
  699. {
  700. // matches retail xex and no arguments, mut be first time retail launch
  701. pCmdLine = "default.xex";
  702. #if defined( _MEMTEST )
  703. pCmdLine = "default.xex +mat_picmip 2";
  704. #endif
  705. }
  706. }
  707. else
  708. {
  709. // get embedded command line from payload
  710. pCmdLine = pPayload;
  711. }
  712. int launchFlags = 0;
  713. if ( launchID == VALVE_LAUNCH_ID )
  714. {
  715. launchFlags = xboxLaunch.GetLaunchFlags();
  716. }
  717. #if !defined( _CERT )
  718. if ( launchFlags & LF_ISDEBUGGING )
  719. {
  720. while ( !DmIsDebuggerPresent() )
  721. {
  722. }
  723. Sleep( 1000 );
  724. Spew( "Resuming debug session.\n" );
  725. }
  726. #endif
  727. // unforunately, the xbox erases its internal store upon first fetch
  728. // must re-establish it so the payload that contains other data (past command line) can be accessed by the game
  729. // the launch data will be owned by tier0 and supplied to game
  730. if ( launchID == VALVE_LAUNCH_ID )
  731. {
  732. xboxLaunch.SetLaunchData( pPayload, payloadSize, launchFlags );
  733. }
  734. #if defined( _DEMO )
  735. else if ( pPayload && payloadSize )
  736. {
  737. // not our data
  738. // restore the launch data as expected
  739. xboxLaunch.SetLaunchData( pPayload, payloadSize, LF_UNKNOWNDATA );
  740. }
  741. #endif
  742. #if defined( _DEMO )
  743. // the demo version cannot trust launch environment
  744. // Kiosk or Magazines launch in unpredictable ways with unknown paths
  745. // MUST slam the command line!!!
  746. #if !defined( _CERT )
  747. // take the command line as specified by the debugger
  748. if ( !DmIsDebuggerPresent() )
  749. {
  750. pCmdLine = "default.xex";
  751. }
  752. #else
  753. pCmdLine = "default.xex";
  754. #endif
  755. #endif
  756. // The 360 has no paths and therefore the xex must reside in the same location as the dlls.
  757. // Only the xex must reside locally, on the box, but the dlls can be mounted from the remote share.
  758. // Resolve all known implicitly loaded dlls to be explicitly loaded now to allow their remote location.
  759. const char *pImplicitDLLs[] =
  760. {
  761. "tier0_360.dll",
  762. "vstdlib_360.dll",
  763. "vxbdm_360.dll",
  764. "launcher_360.dll",
  765. };
  766. // Corresponds to pImplicitDLLs. A dll load failure is only an error if that dll is tagged as required.
  767. const bool bDllRequired[] =
  768. {
  769. true, // tier0
  770. true, // vstdlib
  771. false, // vxbdm
  772. true, // ???
  773. };
  774. char gameName[32];
  775. if ( !ParseCommandLineArg( pCmdLine, "-game", gameName, sizeof( gameName ) ) )
  776. {
  777. #if defined( VPCGAME_STRING )
  778. strcpy( gameName, VPCGAME_STRING );
  779. #endif
  780. }
  781. else
  782. {
  783. // sanitize a possible absolute game path back to expected game name
  784. char *pSlash = strrchr( gameName, '\\' );
  785. if ( pSlash )
  786. {
  787. memcpy( gameName, pSlash+1, strlen( pSlash+1 )+1 );
  788. }
  789. }
  790. // resolve which application gets launched
  791. // default is to application
  792. pImplicitDLLs[ARRAYSIZE( pImplicitDLLs )-1] = "launcher_360.dll";
  793. // the base path is the where the game is predominantly anchored
  794. // game runs from dvd only
  795. // this can only be the d: by definition on the xbox
  796. const char *pBasePath = "d:";
  797. // load all the dlls specified
  798. char dllPath[MAX_PATH];
  799. for ( int i=0; i<ARRAYSIZE( pImplicitDLLs ); i++ )
  800. {
  801. hModule = NULL;
  802. sprintf( dllPath, "%s\\bin\\%s", pBasePath, pImplicitDLLs[i] );
  803. hModule = LoadLibrary( dllPath );
  804. if ( !hModule && bDllRequired[i] )
  805. {
  806. Spew( "FATAL: Failed to load dll: '%s'\n", dllPath );
  807. return NULL;
  808. }
  809. }
  810. char cleanCommandLine[1024];
  811. char tempCommandLine[1024];
  812. StripCommandLineArg( pCmdLine, tempCommandLine, "-basedir" );
  813. StripCommandLineArg( tempCommandLine, cleanCommandLine, "-game" );
  814. // HACK: For ratings build, unlock everything. Remove this for later testing
  815. const char *pAdditionalArgs = "";
  816. #if defined( RATINGSBUILD )
  817. pAdditionalArgs = "-dev -unlockchapters mp_mark_all_maps_complete";
  818. #endif
  819. // set the alternate command line
  820. sprintf( pNewCommandLine, "%s -basedir %s -game %s\\%s %s", cleanCommandLine, pBasePath, pBasePath, gameName, pAdditionalArgs );
  821. // the 'main' export is guaranteed to be at ordinal 1
  822. // the library is already loaded, this just causes a lookup that will resolve against the shortname
  823. const char *pLaunchDllName = pImplicitDLLs[ARRAYSIZE( pImplicitDLLs )-1];
  824. hModule = LoadLibrary( pLaunchDllName );
  825. LauncherMain_t main = (LauncherMain_t)GetProcAddress( hModule, (LPSTR)1 );
  826. if ( !main )
  827. {
  828. Spew( "FATAL: 'LauncherMain' entry point not found in %s\n", pLaunchDllName );
  829. return NULL;
  830. }
  831. return main;
  832. }
  833. //-----------------------------------------------------------------------------
  834. // 360 Application Entry Point.
  835. //-----------------------------------------------------------------------------
  836. VOID __cdecl main()
  837. {
  838. char newCmdLine[1024];
  839. LauncherMain_t newMain = GetLaunchEntryPoint( newCmdLine );
  840. if ( newMain )
  841. {
  842. // 360 has no concept of instances, spoof one
  843. newMain( (HINSTANCE)1, (HINSTANCE)0, (LPSTR)newCmdLine, 0 );
  844. }
  845. }
  846. #endif