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.

1978 lines
53 KiB

  1. //===== Copyright Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // Defines the entry point for the application.
  6. //
  7. //==================================================================//
  8. #if defined( _WIN32 )
  9. #if !defined( _X360 )
  10. #include <windows.h>
  11. #include "shlwapi.h" // registry stuff
  12. #include <direct.h>
  13. #endif
  14. #elif defined ( OSX )
  15. #include <Carbon/Carbon.h>
  16. #elif defined ( LINUX )
  17. #define O_EXLOCK 0
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <fcntl.h>
  21. #include <locale.h>
  22. #elif defined ( _PS3 )
  23. // nothing here for now...
  24. #else
  25. #error
  26. #endif
  27. #include "appframework/ilaunchermgr.h"
  28. #include <stdio.h>
  29. #include "tier0/icommandline.h"
  30. #include "engine_launcher_api.h"
  31. #include "ifilesystem.h"
  32. #include "tier1/interface.h"
  33. #include "tier0/dbg.h"
  34. #include "iregistry.h"
  35. #include "appframework/iappsystem.h"
  36. #include "appframework/AppFramework.h"
  37. #include <vgui/vgui.h>
  38. #include <vgui/ISurface.h>
  39. #include "tier0/platform.h"
  40. #include "tier0/memalloc.h"
  41. #include "datacache/iresourceaccesscontrol.h"
  42. #include "filesystem.h"
  43. #include "tier1/utlrbtree.h"
  44. #include "materialsystem/imaterialsystem.h"
  45. #include "istudiorender.h"
  46. #include "vgui/IVGui.h"
  47. #include "IHammer.h"
  48. #include "datacache/idatacache.h"
  49. #include "datacache/imdlcache.h"
  50. #include "vphysics_interface.h"
  51. #include "filesystem_init.h"
  52. #include "vstdlib/iprocessutils.h"
  53. #include "avi/iavi.h"
  54. #include "avi/ibik.h"
  55. #include "avi/iquicktime.h"
  56. #include "tier1/tier1.h"
  57. #include "tier2/tier2.h"
  58. #include "tier3/tier3.h"
  59. #include "p4lib/ip4.h"
  60. #include "inputsystem/iinputsystem.h"
  61. #include "filesystem/IQueuedLoader.h"
  62. #include "filesystem/IXboxInstaller.h"
  63. #include "reslistgenerator.h"
  64. #include "tier1/fmtstr.h"
  65. #include "steam/steam_api.h"
  66. #include "vscript/ivscript.h"
  67. #include "tier0/miniprofiler.h"
  68. #include "networksystem/inetworksystem.h"
  69. #include "tier1/fmtstr.h"
  70. #include "vjobs_interface.h"
  71. #include "vstdlib/jobthread.h"
  72. #if defined( _PS3 )
  73. #include "sys/ppu_thread.h"
  74. #include "ps3/ps3_win32stubs.h"
  75. #include "ps3/ps3_core.h"
  76. #include "ps3/ps3_helpers.h"
  77. #include "ps3/ps3_console.h"
  78. #include "../public/ps3_pathinfo.h"
  79. #include "../public/tls_ps3.h"
  80. #elif defined( _X360 )
  81. #include "xbox/xbox_win32stubs.h"
  82. #include "xbox/xbox_console.h"
  83. #include "xbox/xbox_launch.h"
  84. #endif
  85. #ifdef LINUX
  86. #include "SDL.h"
  87. #define MB_OK 0x00000001
  88. #define MB_SYSTEMMODAL 0x00000002
  89. #define MB_ICONERROR 0x00000004
  90. int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType );
  91. #endif
  92. #ifdef OSX
  93. #define RELAUNCH_FILE "/tmp/hl2_relaunch"
  94. #endif
  95. #if defined( DEVELOPMENT_ONLY ) || defined( ALLOW_TEXT_MODE )
  96. #define ALLOW_MULTI_CLIENTS_PER_MACHINE 1
  97. #endif
  98. // memdbgon must be the last include file in a .cpp file!!!
  99. #include "tier0/memdbgon.h"
  100. #if defined ( CSTRIKE15 )
  101. #define DEFAULT_HL2_GAMEDIR "csgo"
  102. #else
  103. #define DEFAULT_HL2_GAMEDIR "hl2"
  104. #endif // CSTRIKE15
  105. // A logging channel used during engine initialization
  106. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_EngineInitialization, "EngineInitialization" );
  107. #if defined( USE_SDL )
  108. extern void* CreateSDLMgr();
  109. #elif defined( OSX )
  110. extern void* CreateCCocoaMgr();
  111. #endif
  112. #define SIXENSE
  113. #ifdef SIXENSE
  114. extern bool DoesFileExistIn( const char *pDirectoryName, const char *pFilename );
  115. #endif
  116. //-----------------------------------------------------------------------------
  117. // Modules...
  118. //-----------------------------------------------------------------------------
  119. static IEngineAPI *g_pEngineAPI;
  120. static IHammer *g_pHammer;
  121. bool g_bTextMode = false;
  122. #ifndef _PS3
  123. static char g_szBasedir[MAX_PATH];
  124. static char g_szGamedir[MAX_PATH];
  125. #else
  126. #endif
  127. // copied from sys.h
  128. struct FileAssociationInfo
  129. {
  130. char const *extension;
  131. char const *command_to_issue;
  132. };
  133. static FileAssociationInfo g_FileAssociations[] =
  134. {
  135. { ".dem", "playdemo" },
  136. { ".sav", "load" },
  137. { ".bsp", "map" },
  138. };
  139. #ifdef _WIN32
  140. #pragma warning(disable:4073)
  141. #pragma init_seg(lib)
  142. #endif
  143. class CLeakDump
  144. {
  145. public:
  146. CLeakDump()
  147. : m_bCheckLeaks( false )
  148. {
  149. }
  150. ~CLeakDump()
  151. {
  152. if ( m_bCheckLeaks )
  153. {
  154. g_pMemAlloc->DumpStats();
  155. }
  156. }
  157. bool m_bCheckLeaks;
  158. } g_LeakDump;
  159. class CLauncherLoggingListener : public ILoggingListener
  160. {
  161. public:
  162. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage )
  163. {
  164. #if !defined( _CERT ) && !defined( _PS3 )
  165. #if defined ( WIN32 ) || defined( LINUX )
  166. if ( pContext->m_Severity == LS_WARNING && pContext->m_ChannelID == LOG_EngineInitialization )
  167. {
  168. ::MessageBox( NULL, pMessage, "Warning!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR );
  169. }
  170. else if ( pContext->m_Severity == LS_ASSERT && !ShouldUseNewAssertDialog() )
  171. {
  172. ::MessageBox( NULL, pMessage, "Assert!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR );
  173. }
  174. else if ( pContext->m_Severity == LS_ERROR )
  175. {
  176. ::MessageBox( NULL, pMessage, "Error!", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR );
  177. }
  178. #elif defined(OSX)
  179. CFOptionFlags responseFlags;
  180. CFStringRef message;
  181. message = CFStringCreateWithCString(NULL, pMessage, CFStringGetSystemEncoding() ) ;
  182. if ( pContext->m_Severity == LS_WARNING && pContext->m_ChannelID == LOG_EngineInitialization )
  183. {
  184. CFUserNotificationDisplayAlert(0, kCFUserNotificationCautionAlertLevel, 0, 0, 0, CFSTR( "Warning" ), message, NULL, NULL, NULL, &responseFlags);
  185. }
  186. else if ( pContext->m_Severity == LS_ASSERT && !ShouldUseNewAssertDialog() )
  187. {
  188. CFUserNotificationDisplayAlert(0, kCFUserNotificationNoteAlertLevel, 0, 0, 0, CFSTR( "Assert" ), message, NULL, NULL, NULL, &responseFlags);
  189. }
  190. else if ( pContext->m_Severity == LS_ERROR )
  191. {
  192. CFUserNotificationDisplayAlert(0, kCFUserNotificationStopAlertLevel, 0, 0, 0, CFSTR( "Error" ), message, NULL, NULL, NULL, &responseFlags);
  193. }
  194. CFRelease(message);
  195. #else
  196. #warning "Popup a dialog here"
  197. #endif
  198. #endif // CERT
  199. }
  200. };
  201. #if defined( _PS3 )
  202. const char *GetGameDirectory( void )
  203. {
  204. return g_pPS3PathInfo->GameImagePath();
  205. }
  206. #else
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Return the game directory
  209. // Output : char
  210. //-----------------------------------------------------------------------------
  211. char *GetGameDirectory( void )
  212. {
  213. return g_szGamedir;
  214. }
  215. void SetGameDirectory( const char *game )
  216. {
  217. Q_strncpy( g_szGamedir, game, sizeof(g_szGamedir) );
  218. }
  219. #endif
  220. //-----------------------------------------------------------------------------
  221. // Gets the executable name
  222. //-----------------------------------------------------------------------------
  223. bool GetExecutableName( char *out, int outSize )
  224. {
  225. #ifdef WIN32
  226. if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, outSize ) )
  227. {
  228. return false;
  229. }
  230. return true;
  231. #else
  232. return false;
  233. #endif
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Return the executable name
  237. // Output : char
  238. //-----------------------------------------------------------------------------
  239. const char * GetExecutableFilename()
  240. {
  241. #ifdef _PS3
  242. return "csgo";
  243. #else // !_PS3
  244. char exepath[MAX_PATH];
  245. static char filename[MAX_PATH];
  246. #ifdef WIN32
  247. filename[0] = 0;
  248. if ( GetExecutableName( exepath, sizeof( exepath ) ) )
  249. {
  250. _splitpath
  251. (
  252. exepath, // Input
  253. NULL, // drive
  254. NULL, // dir
  255. filename, // filename
  256. NULL // extension
  257. );
  258. }
  259. Q_strlower( filename );
  260. #else
  261. filename[0] = 0;
  262. #endif
  263. return filename;
  264. #endif // _PS3
  265. }
  266. #if !defined(_PS3)
  267. //-----------------------------------------------------------------------------
  268. // Purpose: Return the base directory
  269. // Output : char
  270. //-----------------------------------------------------------------------------
  271. char *GetBaseDirectory( void )
  272. {
  273. return g_szBasedir;
  274. }
  275. #else
  276. const char *GetBaseDirectory( void )
  277. {
  278. return g_pPS3PathInfo->GameImagePath();
  279. }
  280. #endif
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Determine the directory where this .exe is running from
  283. //-----------------------------------------------------------------------------
  284. void UTIL_ComputeBaseDir()
  285. {
  286. #ifndef _PS3
  287. g_szBasedir[0] = 0;
  288. if ( IsX360() )
  289. {
  290. char const *pBaseDir = CommandLine()->ParmValue( "-basedir" );
  291. if ( pBaseDir )
  292. {
  293. strcpy( g_szBasedir, pBaseDir );
  294. }
  295. }
  296. if ( !g_szBasedir[0] && GetExecutableName( g_szBasedir, sizeof( g_szBasedir ) ) )
  297. {
  298. char *pBuffer = strrchr( g_szBasedir, '\\' );
  299. if ( *pBuffer )
  300. {
  301. *(pBuffer+1) = '\0';
  302. }
  303. int j = strlen( g_szBasedir );
  304. if (j > 0)
  305. {
  306. if ( ( g_szBasedir[j-1] == '\\' ) ||
  307. ( g_szBasedir[j-1] == '/' ) )
  308. {
  309. g_szBasedir[j-1] = 0;
  310. }
  311. }
  312. }
  313. if ( IsPC() )
  314. {
  315. char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" );
  316. if ( pOverrideDir )
  317. {
  318. strcpy( g_szBasedir, pOverrideDir );
  319. }
  320. }
  321. #ifdef WIN32
  322. Q_strlower( g_szBasedir );
  323. #endif
  324. Q_FixSlashes( g_szBasedir );
  325. #else
  326. #endif
  327. }
  328. #ifdef WIN32
  329. BOOL WINAPI MyHandlerRoutine( DWORD dwCtrlType )
  330. {
  331. #if !defined( _X360 )
  332. TerminateProcess( GetCurrentProcess(), 2 );
  333. #endif
  334. return TRUE;
  335. }
  336. #endif
  337. void InitTextMode()
  338. {
  339. #ifdef WIN32
  340. #if !defined( _X360 )
  341. AllocConsole();
  342. SetConsoleCtrlHandler( MyHandlerRoutine, TRUE );
  343. freopen( "CONIN$", "rb", stdin ); // reopen stdin handle as console window input
  344. freopen( "CONOUT$", "wb", stdout ); // reopen stout handle as console window output
  345. freopen( "CONOUT$", "wb", stderr ); // reopen stderr handle as console window output
  346. #else
  347. XBX_Error( "%s %s: Not Supported", __FILE__, __LINE__ );
  348. #endif
  349. #endif
  350. }
  351. void SortResList( char const *pchFileName, char const *pchSearchPath );
  352. #define ALL_RESLIST_FILE "all.lst"
  353. #define ENGINE_RESLIST_FILE "engine.lst"
  354. #ifdef _PS3
  355. void TryToLoadSteamOverlayDLL()
  356. {
  357. }
  358. #else // !_PS3
  359. // create file to dump out to
  360. class CLogAllFiles
  361. {
  362. public:
  363. CLogAllFiles();
  364. void Init();
  365. void Shutdown();
  366. void LogFile( const char *fullPathFileName, const char *options );
  367. private:
  368. static void LogAllFilesFunc( const char *fullPathFileName, const char *options );
  369. void LogToAllReslist( char const *line );
  370. bool m_bActive;
  371. char m_szCurrentDir[_MAX_PATH];
  372. // persistent across restarts
  373. CUtlRBTree< CUtlString, int > m_Logged;
  374. CUtlString m_sResListDir;
  375. CUtlString m_sFullGamePath;
  376. };
  377. static CLogAllFiles g_LogFiles;
  378. static bool AllLogLessFunc( CUtlString const &pLHS, CUtlString const &pRHS )
  379. {
  380. return CaselessStringLessThan( pLHS.Get(), pRHS.Get() );
  381. }
  382. CLogAllFiles::CLogAllFiles() :
  383. m_bActive( false ),
  384. m_Logged( 0, 0, AllLogLessFunc )
  385. {
  386. MEM_ALLOC_CREDIT();
  387. m_sResListDir = "reslists";
  388. }
  389. void CLogAllFiles::Init()
  390. {
  391. if ( IsX360() )
  392. {
  393. return;
  394. }
  395. // Can't do this in edit mode
  396. if ( CommandLine()->CheckParm( "-edit" ) )
  397. {
  398. return;
  399. }
  400. if ( !CommandLine()->CheckParm( "-makereslists" ) )
  401. {
  402. return;
  403. }
  404. m_bActive = true;
  405. char const *pszDir = NULL;
  406. if ( CommandLine()->CheckParm( "-reslistdir", &pszDir ) && pszDir )
  407. {
  408. char szDir[ MAX_PATH ];
  409. Q_strncpy( szDir, pszDir, sizeof( szDir ) );
  410. Q_StripTrailingSlash( szDir );
  411. #ifdef WIN32
  412. Q_strlower( szDir );
  413. #endif
  414. Q_FixSlashes( szDir );
  415. if ( Q_strlen( szDir ) > 0 )
  416. {
  417. m_sResListDir = szDir;
  418. }
  419. }
  420. // game directory has not been established yet, must derive ourselves
  421. char path[MAX_PATH];
  422. Q_snprintf( path, sizeof(path), "%s/%s", GetBaseDirectory(), CommandLine()->ParmValue( "-game", "hl2" ) );
  423. Q_FixSlashes( path );
  424. #ifdef WIN32
  425. Q_strlower( path );
  426. #endif
  427. m_sFullGamePath = path;
  428. // create file to dump out to
  429. char szDir[ MAX_PATH ];
  430. V_snprintf( szDir, sizeof( szDir ), "%s\\%s", m_sFullGamePath.String(), m_sResListDir.String() );
  431. g_pFullFileSystem->CreateDirHierarchy( szDir, "GAME" );
  432. g_pFullFileSystem->AddLoggingFunc( &LogAllFilesFunc );
  433. if ( !CommandLine()->FindParm( "-startmap" ) && !CommandLine()->FindParm( "-startstage" ) )
  434. {
  435. m_Logged.RemoveAll();
  436. g_pFullFileSystem->RemoveFile( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "GAME" );
  437. }
  438. #ifdef WIN32
  439. ::GetCurrentDirectory( sizeof(m_szCurrentDir), m_szCurrentDir );
  440. Q_strncat( m_szCurrentDir, "\\", sizeof(m_szCurrentDir), 1 );
  441. _strlwr( m_szCurrentDir );
  442. #else
  443. getcwd( m_szCurrentDir, sizeof(m_szCurrentDir) );
  444. Q_strncat( m_szCurrentDir, "/", sizeof(m_szCurrentDir), 1 );
  445. #endif
  446. }
  447. void CLogAllFiles::Shutdown()
  448. {
  449. if ( !m_bActive )
  450. return;
  451. m_bActive = false;
  452. if ( CommandLine()->CheckParm( "-makereslists" ) )
  453. {
  454. g_pFullFileSystem->RemoveLoggingFunc( &LogAllFilesFunc );
  455. }
  456. // Now load and sort all.lst
  457. SortResList( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "GAME" );
  458. // Now load and sort engine.lst
  459. SortResList( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ENGINE_RESLIST_FILE ), "GAME" );
  460. m_Logged.Purge();
  461. }
  462. void CLogAllFiles::LogToAllReslist( char const *line )
  463. {
  464. // Open for append, write data, close.
  465. FileHandle_t fh = g_pFullFileSystem->Open( CFmtStr( "%s\\%s\\%s", m_sFullGamePath.String(), m_sResListDir.String(), ALL_RESLIST_FILE ), "at", "GAME" );
  466. if ( fh != FILESYSTEM_INVALID_HANDLE )
  467. {
  468. g_pFullFileSystem->Write("\"", 1, fh);
  469. g_pFullFileSystem->Write( line, Q_strlen(line), fh );
  470. g_pFullFileSystem->Write("\"\n", 2, fh);
  471. g_pFullFileSystem->Close( fh );
  472. }
  473. }
  474. void CLogAllFiles::LogFile(const char *fullPathFileName, const char *options)
  475. {
  476. if ( !m_bActive )
  477. {
  478. Assert( 0 );
  479. return;
  480. }
  481. // write out to log file
  482. Assert( fullPathFileName[1] == ':' );
  483. int idx = m_Logged.Find( fullPathFileName );
  484. if ( idx != m_Logged.InvalidIndex() )
  485. {
  486. return;
  487. }
  488. m_Logged.Insert( fullPathFileName );
  489. // make it relative to our root directory
  490. const char *relative = Q_stristr( fullPathFileName, GetBaseDirectory() );
  491. if ( relative )
  492. {
  493. relative += ( Q_strlen( GetBaseDirectory() ) + 1 );
  494. char rel[ MAX_PATH ];
  495. Q_strncpy( rel, relative, sizeof( rel ) );
  496. #ifdef WIN32
  497. Q_strlower( rel );
  498. #endif
  499. Q_FixSlashes( rel );
  500. LogToAllReslist( rel );
  501. }
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Purpose: callback function from filesystem
  505. //-----------------------------------------------------------------------------
  506. void CLogAllFiles::LogAllFilesFunc(const char *fullPathFileName, const char *options)
  507. {
  508. g_LogFiles.LogFile( fullPathFileName, options );
  509. }
  510. //-----------------------------------------------------------------------------
  511. // Purpose: This is a bit of a hack because it appears
  512. // Output : Returns true on success, false on failure.
  513. //-----------------------------------------------------------------------------
  514. static bool IsWin98OrOlder()
  515. {
  516. bool retval = false;
  517. #if defined( WIN32 ) && !defined( _X360 )
  518. OSVERSIONINFOEX osvi;
  519. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  520. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  521. BOOL bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);
  522. if( !bOsVersionInfoEx )
  523. {
  524. // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
  525. osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  526. if ( !GetVersionEx ( (OSVERSIONINFO *) &osvi) )
  527. {
  528. Error( "IsWin98OrOlder: Unable to get OS version information" );
  529. }
  530. }
  531. switch (osvi.dwPlatformId)
  532. {
  533. case VER_PLATFORM_WIN32_NT:
  534. // NT, XP, Win2K, etc. all OK for SSE
  535. break;
  536. case VER_PLATFORM_WIN32_WINDOWS:
  537. // Win95, 98, Me can't do SSE
  538. retval = true;
  539. break;
  540. case VER_PLATFORM_WIN32s:
  541. // Can't really run this way I don't think...
  542. retval = true;
  543. break;
  544. default:
  545. break;
  546. }
  547. #endif
  548. return retval;
  549. }
  550. //-----------------------------------------------------------------------------
  551. // Purpose: Figure out if Steam is running, then load the GameOverlayRenderer.dll
  552. //-----------------------------------------------------------------------------
  553. void TryToLoadSteamOverlayDLL()
  554. {
  555. #if defined( WIN32 ) && !defined( _X360 )
  556. // First, check if the module is already loaded, perhaps because we were run from Steam directly
  557. HMODULE hMod = GetModuleHandle( "GameOverlayRenderer.dll" );
  558. if ( hMod )
  559. {
  560. return;
  561. }
  562. const char *pchSteamInstallPath = SteamAPI_GetSteamInstallPath();
  563. if ( pchSteamInstallPath )
  564. {
  565. char rgchSteamPath[MAX_PATH];
  566. V_ComposeFileName( pchSteamInstallPath, "GameOverlayRenderer.dll", rgchSteamPath, Q_ARRAYSIZE(rgchSteamPath) );
  567. // This could fail, but we can't fix it if it does so just ignore failures
  568. LoadLibrary( rgchSteamPath );
  569. }
  570. #endif
  571. }
  572. #endif // _PS3
  573. //-----------------------------------------------------------------------------
  574. // Inner loop: initialize, shutdown main systems, load steam to
  575. //-----------------------------------------------------------------------------
  576. class CSourceAppSystemGroup : public CSteamAppSystemGroup
  577. {
  578. public:
  579. // Methods of IApplication
  580. virtual bool Create();
  581. virtual bool PreInit();
  582. virtual int Main();
  583. virtual void PostShutdown();
  584. virtual void Destroy();
  585. private:
  586. const char *DetermineDefaultMod();
  587. const char *DetermineDefaultGame();
  588. bool m_bEditMode;
  589. };
  590. //-----------------------------------------------------------------------------
  591. // The dirty disk error report function
  592. //-----------------------------------------------------------------------------
  593. void ReportDirtyDiskNoMaterialSystem()
  594. {
  595. #ifdef _X360
  596. for ( int i = 0; i < 4; ++i )
  597. {
  598. if ( XUserGetSigninState( i ) != eXUserSigninState_NotSignedIn )
  599. {
  600. XShowDirtyDiscErrorUI( i );
  601. return;
  602. }
  603. }
  604. XShowDirtyDiscErrorUI( 0 );
  605. #endif
  606. }
  607. IVJobs * g_pVJobs = NULL;
  608. //-----------------------------------------------------------------------------
  609. // Instantiate all main libraries
  610. //-----------------------------------------------------------------------------
  611. bool CSourceAppSystemGroup::Create()
  612. {
  613. COM_TimestampedLog( "CSourceAppSystemGroup::Create()" );
  614. double start, elapsed;
  615. start = Plat_FloatTime();
  616. IFileSystem *pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION );
  617. pFileSystem->InstallDirtyDiskReportFunc( ReportDirtyDiskNoMaterialSystem );
  618. #ifdef WIN32
  619. CoInitialize( NULL );
  620. #endif
  621. // Are we running in edit mode?
  622. m_bEditMode = CommandLine()->CheckParm( "-edit" ) ? true : false;
  623. AppSystemInfo_t appSystems[] =
  624. {
  625. #define LAUNCHER_APPSYSTEM( name ) name DLL_EXT_STRING
  626. #ifdef _PS3
  627. { LAUNCHER_APPSYSTEM( "vjobs" ), VJOBS_INTERFACE_VERSION }, // Vjobs must shut down after engine and materialsystem
  628. #endif
  629. { LAUNCHER_APPSYSTEM( "engine" ), CVAR_QUERY_INTERFACE_VERSION }, // NOTE: This one must be first!!
  630. { LAUNCHER_APPSYSTEM( "filesystem_stdio" ), QUEUEDLOADER_INTERFACE_VERSION },
  631. #if defined( _X360 )
  632. { LAUNCHER_APPSYSTEM( "filesystem_stdio" ), XBOXINSTALLER_INTERFACE_VERSION },
  633. #endif
  634. { LAUNCHER_APPSYSTEM( "inputsystem" ), INPUTSYSTEM_INTERFACE_VERSION },
  635. { LAUNCHER_APPSYSTEM( "vphysics" ), VPHYSICS_INTERFACE_VERSION },
  636. { LAUNCHER_APPSYSTEM( "materialsystem" ), MATERIAL_SYSTEM_INTERFACE_VERSION },
  637. { LAUNCHER_APPSYSTEM( "datacache" ), DATACACHE_INTERFACE_VERSION },
  638. { LAUNCHER_APPSYSTEM( "datacache" ), MDLCACHE_INTERFACE_VERSION },
  639. { LAUNCHER_APPSYSTEM( "datacache" ), STUDIO_DATA_CACHE_INTERFACE_VERSION },
  640. { LAUNCHER_APPSYSTEM( "studiorender" ), STUDIO_RENDER_INTERFACE_VERSION },
  641. { LAUNCHER_APPSYSTEM( "soundemittersystem" ), SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
  642. { LAUNCHER_APPSYSTEM( "vscript" ), VSCRIPT_INTERFACE_VERSION },
  643. #ifdef WIN32
  644. { LAUNCHER_APPSYSTEM("soundsystem"), SOUNDSYSTEM_INTERFACE_VERSION },
  645. #endif
  646. #if !defined( _GAMECONSOLE )
  647. #if defined ( AVI_VIDEO )
  648. { LAUNCHER_APPSYSTEM( "valve_avi" ), AVI_INTERFACE_VERSION },
  649. #endif
  650. #if defined ( BINK_VIDEO )
  651. { LAUNCHER_APPSYSTEM( "valve_avi" ), BIK_INTERFACE_VERSION },
  652. #endif
  653. #if defined( QUICKTIME_VIDEO )
  654. { LAUNCHER_APPSYSTEM( "valve_avi" ), QUICKTIME_INTERFACE_VERSION },
  655. #endif
  656. #elif defined( BINK_ENABLED_FOR_CONSOLE )
  657. { LAUNCHER_APPSYSTEM( "engine" ), BIK_INTERFACE_VERSION },
  658. #endif
  659. // NOTE: This has to occur before vgui2.dll so it replaces vgui2's surface implementation
  660. { LAUNCHER_APPSYSTEM( "vguimatsurface" ), VGUI_SURFACE_INTERFACE_VERSION },
  661. { LAUNCHER_APPSYSTEM( "vgui2" ), VGUI_IVGUI_INTERFACE_VERSION },
  662. { LAUNCHER_APPSYSTEM( "engine" ), VENGINE_LAUNCHER_API_VERSION },
  663. { "", "" } // Required to terminate the list
  664. };
  665. #if defined( USE_SDL )
  666. AddSystem( (IAppSystem *)CreateSDLMgr(), SDLMGR_INTERFACE_VERSION );
  667. #elif defined( OSX )
  668. AddSystem( (IAppSystem *)CreateCCocoaMgr(), COCOAMGR_INTERFACE_VERSION );
  669. #endif
  670. if ( !AddSystems( appSystems ) )
  671. return false;
  672. // SF4 TODO
  673. // Windows - See if we need to launch SF4 instead of SF3
  674. // When we move entirely to SF4 this can go back in appsystems[] where it used to be
  675. #if defined( INCLUDE_SCALEFORM )
  676. if ( CommandLine()->FindParm( "-sf3" ) )
  677. {
  678. AppSystemInfo_t scaleformInfo[] =
  679. {
  680. { LAUNCHER_APPSYSTEM( "scaleformui_3" ), SCALEFORMUI_INTERFACE_VERSION },
  681. { "", "" }
  682. };
  683. if ( !AddSystems( scaleformInfo ) )
  684. {
  685. return false;
  686. }
  687. }
  688. else
  689. {
  690. AppSystemInfo_t scaleformInfo[] =
  691. {
  692. { LAUNCHER_APPSYSTEM( "scaleformui" ), SCALEFORMUI_INTERFACE_VERSION },
  693. { "", "" }
  694. };
  695. if ( !AddSystems( scaleformInfo ) )
  696. return false;
  697. }
  698. #endif // INCLUDE_SCALEFORM
  699. // Hook in datamodel and p4 control if we're running with -tools
  700. if ( IsPC() && ( ( CommandLine()->FindParm( "-tools" ) && !CommandLine()->FindParm( "-nop4" ) ) || CommandLine()->FindParm( "-p4" ) ) )
  701. {
  702. AppModule_t p4libModule = LoadModule( "p4lib.dll" );
  703. IP4 *p4 = (IP4*)AddSystem( p4libModule, P4_INTERFACE_VERSION );
  704. // If we are running with -steam then that means the tools are being used by an SDK user. Don't exit in this case!
  705. if ( !p4 && !CommandLine()->FindParm( "-steam" ) )
  706. {
  707. return false;
  708. }
  709. }
  710. if ( IsPC() && IsPlatformWindows() )
  711. {
  712. AppModule_t vstdlibModule = LoadModule( LAUNCHER_APPSYSTEM( "vstdlib" ) );
  713. IProcessUtils *processUtils = ( IProcessUtils* )AddSystem( vstdlibModule, PROCESS_UTILS_INTERFACE_VERSION );
  714. if ( !processUtils )
  715. return false;
  716. }
  717. if ( CommandLine()->FindParm( "-dev" ) )
  718. {
  719. // Used to guarantee precache consistency
  720. AppModule_t datacacheModule = LoadModule( LAUNCHER_APPSYSTEM( "datacache" ) );
  721. IResourceAccessControl *pResourceAccess = (IResourceAccessControl*)AddSystem( datacacheModule, RESOURCE_ACCESS_CONTROL_INTERFACE_VERSION );
  722. if ( !pResourceAccess )
  723. return false;
  724. }
  725. // Connect to iterfaces loaded in AddSystems that we need locally
  726. IMaterialSystem *pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
  727. if ( !pMaterialSystem )
  728. return false;
  729. g_pEngineAPI = (IEngineAPI*)FindSystem( VENGINE_LAUNCHER_API_VERSION );
  730. // Load the hammer DLL if we're in editor mode
  731. if ( m_bEditMode )
  732. {
  733. AppModule_t hammerModule = LoadModule( LAUNCHER_APPSYSTEM( "hammer_dll" ) );
  734. g_pHammer = (IHammer*)AddSystem( hammerModule, INTERFACEVERSION_HAMMER );
  735. if ( !g_pHammer )
  736. {
  737. return false;
  738. }
  739. }
  740. // Load up the appropriate shader DLL
  741. // This has to be done before connection.
  742. char const *pDLLName = "shaderapidx9" DLL_EXT_STRING;
  743. const char* pArg = NULL;
  744. if ( CommandLine()->FindParm( "-noshaderapi" ) )
  745. {
  746. pDLLName = "shaderapiempty" DLL_EXT_STRING;
  747. }
  748. if ( CommandLine()->CheckParm( "-shaderapi", &pArg ))
  749. {
  750. pDLLName = pArg;
  751. }
  752. pMaterialSystem->SetShaderAPI( pDLLName );
  753. elapsed = Plat_FloatTime() - start;
  754. COM_TimestampedLog( "CSourceAppSystemGroup::Create() - Took %.4f secs to load libraries and get factories.", (float)elapsed );
  755. return true;
  756. }
  757. bool CSourceAppSystemGroup::PreInit()
  758. {
  759. CreateInterfaceFn factory = GetFactory();
  760. ConnectTier1Libraries( &factory, 1 );
  761. ConVar_Register( );
  762. ConnectTier2Libraries( &factory, 1 );
  763. ConnectTier3Libraries( &factory, 1 );
  764. if ( !g_pFullFileSystem || !g_pMaterialSystem )
  765. return false;
  766. #ifdef _PS3
  767. g_pVJobs = ( IVJobs* )factory( VJOBS_INTERFACE_VERSION, NULL ); // this is done only once; g_pVJobs doesn't change even after multiple reloads of VJobs.prx
  768. FileSystem_AddSearchPath_Platform( g_pFullFileSystem, GetGameDirectory() );
  769. #else // _PS3
  770. CFSSteamSetupInfo steamInfo;
  771. steamInfo.m_bToolsMode = false;
  772. steamInfo.m_bSetSteamDLLPath = false;
  773. steamInfo.m_bSteam = g_pFullFileSystem->IsSteam();
  774. steamInfo.m_bOnlyUseDirectoryName = true;
  775. steamInfo.m_pDirectoryName = DetermineDefaultMod();
  776. if ( !steamInfo.m_pDirectoryName )
  777. {
  778. steamInfo.m_pDirectoryName = DetermineDefaultGame();
  779. if ( !steamInfo.m_pDirectoryName )
  780. {
  781. Error( "FileSystem_LoadFileSystemModule: no -defaultgamedir or -game specified." );
  782. }
  783. }
  784. if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
  785. return false;
  786. CFSMountContentInfo fsInfo;
  787. fsInfo.m_pFileSystem = g_pFullFileSystem;
  788. fsInfo.m_bToolsMode = m_bEditMode;
  789. fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
  790. if ( FileSystem_MountContent( fsInfo ) != FS_OK )
  791. return false;
  792. #if defined( SUPPORT_VPK )
  793. Msg( "start timing %f\n", Plat_FloatTime() );
  794. char const *pVPKName = CommandLine()->ParmValue( "-vpk" );
  795. if ( pVPKName )
  796. {
  797. fsInfo.m_pFileSystem->AddVPKFile( pVPKName );
  798. }
  799. #endif
  800. if ( IsPC() || !IsX360() )
  801. {
  802. fsInfo.m_pFileSystem->AddSearchPath( "platform", "PLATFORM" );
  803. }
  804. else
  805. {
  806. // 360 needs absolute paths
  807. FileSystem_AddSearchPath_Platform( g_pFullFileSystem, steamInfo.m_GameInfoPath );
  808. }
  809. if ( IsPC() )
  810. {
  811. // This will get called multiple times due to being here, but only the first one will do anything
  812. reslistgenerator->Init( GetBaseDirectory(), CommandLine()->ParmValue( "-game", "hl2" ) );
  813. // This MUST get called each time, but will actually fix up the command line as needed
  814. reslistgenerator->TickAndFixupCommandLine();
  815. }
  816. // FIXME: Logfiles is mod-specific, needs to move into the engine.
  817. g_LogFiles.Init();
  818. // Required to run through the editor
  819. if ( m_bEditMode )
  820. {
  821. g_pMaterialSystem->EnableEditorMaterials();
  822. }
  823. #endif // !_PS3
  824. StartupInfo_t info;
  825. info.m_pInstance = GetAppInstance();
  826. info.m_pBaseDirectory = GetBaseDirectory();
  827. info.m_pInitialMod = DetermineDefaultMod();
  828. info.m_pInitialGame = DetermineDefaultGame();
  829. info.m_pParentAppSystemGroup = this;
  830. info.m_bTextMode = g_bTextMode;
  831. return g_pEngineAPI->SetStartupInfo( info );
  832. }
  833. int CSourceAppSystemGroup::Main()
  834. {
  835. return g_pEngineAPI->Run();
  836. }
  837. void CSourceAppSystemGroup::PostShutdown()
  838. {
  839. #ifndef _PS3
  840. // FIXME: Logfiles is mod-specific, needs to move into the engine.
  841. g_LogFiles.Shutdown();
  842. #endif // _PS3
  843. reslistgenerator->Shutdown();
  844. DisconnectTier3Libraries();
  845. DisconnectTier2Libraries();
  846. ConVar_Unregister( );
  847. DisconnectTier1Libraries();
  848. }
  849. void CSourceAppSystemGroup::Destroy()
  850. {
  851. g_pEngineAPI = NULL;
  852. g_pMaterialSystem = NULL;
  853. g_pHammer = NULL;
  854. g_pVJobs = NULL;
  855. #ifdef WIN32
  856. CoUninitialize();
  857. #endif
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Determines the initial mod to use at load time.
  861. // We eventually (hopefully) will be able to switch mods at runtime
  862. // because the engine/hammer integration really wants this feature.
  863. //-----------------------------------------------------------------------------
  864. const char *CSourceAppSystemGroup::DetermineDefaultMod()
  865. {
  866. if ( !m_bEditMode )
  867. {
  868. return CommandLine()->ParmValue( "-game", DEFAULT_HL2_GAMEDIR );
  869. }
  870. return g_pHammer->GetDefaultMod();
  871. }
  872. const char *CSourceAppSystemGroup::DetermineDefaultGame()
  873. {
  874. if ( !m_bEditMode )
  875. {
  876. return CommandLine()->ParmValue( "-defaultgamedir", DEFAULT_HL2_GAMEDIR );
  877. }
  878. return g_pHammer->GetDefaultGame();
  879. }
  880. //-----------------------------------------------------------------------------
  881. // MessageBox for OSX
  882. //-----------------------------------------------------------------------------
  883. #if defined(OSX)
  884. #include "CoreFoundation/CoreFoundation.h"
  885. int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType )
  886. {
  887. //convert the strings from char* to CFStringRef
  888. CFStringRef header_ref = CFStringCreateWithCString( NULL, header, strlen(header) );
  889. CFStringRef message_ref = CFStringCreateWithCString( NULL, message, strlen(message) );
  890. CFOptionFlags result; //result code from the message box
  891. //launch the message box
  892. CFUserNotificationDisplayAlert( 0, // no timeout
  893. kCFUserNotificationNoteAlertLevel, //change it depending message_type flags ( MB_ICONASTERISK.... etc.)
  894. NULL, //icon url, use default, you can change it depending message_type flags
  895. NULL, //not used
  896. NULL, //localization of strings
  897. header_ref, //header text
  898. message_ref, //message text
  899. NULL, //default "ok" text in button
  900. NULL,
  901. NULL, //other button title, null--> no other button
  902. &result //response flags
  903. );
  904. //Clean up the strings
  905. CFRelease( header_ref );
  906. CFRelease( message_ref );
  907. //Convert the result
  908. if( result == kCFUserNotificationDefaultResponse )
  909. return 0;
  910. else
  911. return 1;
  912. }
  913. #elif defined( LINUX )
  914. int MessageBox( HWND hWnd, const char *message, const char *header, unsigned uType )
  915. {
  916. SDL_ShowSimpleMessageBox( 0, header, message, GetAssertDialogParent() );
  917. return 0;
  918. }
  919. #endif
  920. //-----------------------------------------------------------------------------
  921. // Allow only one windowed source app to run at a time
  922. //-----------------------------------------------------------------------------
  923. #ifdef WIN32
  924. HANDLE g_hMutex = NULL;
  925. #elif defined( POSIX )
  926. int g_lockfd = -1;
  927. char g_lockFilename[MAX_PATH];
  928. #endif
  929. bool GrabSourceMutex()
  930. {
  931. #ifdef WIN32
  932. if ( IsPC() )
  933. {
  934. // don't allow more than one instance to run
  935. g_hMutex = ::CreateMutex(NULL, FALSE, TEXT("hl2_singleton_mutex"));
  936. unsigned int waitResult = ::WaitForSingleObject(g_hMutex, 0);
  937. // Here, we have the mutex
  938. if (waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED)
  939. return true;
  940. // couldn't get the mutex, we must be running another instance
  941. ::CloseHandle(g_hMutex);
  942. // If there is a VPROJECT defined, we assume you are a developer and know the risks
  943. // of running multiple copies of the engine
  944. if ( getenv( "VPROJECT" ) && CommandLine()->FindParm( "-allowmultiple" ) )
  945. {
  946. return true;
  947. }
  948. return false;
  949. }
  950. #elif defined( POSIX )
  951. // Under OSX use flock in /tmp/source_engine_<game>.lock, create the file if it doesn't exist
  952. const char *pchGameParam = CommandLine()->ParmValue( "-game", DEFAULT_HL2_GAMEDIR );
  953. CRC32_t gameCRC;
  954. CRC32_Init(&gameCRC);
  955. CRC32_ProcessBuffer( &gameCRC, (void *)pchGameParam, Q_strlen( pchGameParam ) );
  956. CRC32_Final( &gameCRC );
  957. #ifdef LINUX
  958. /*
  959. * Linux
  960. */
  961. // Check TMPDIR environment variable for temp directory.
  962. char *tmpdir = getenv( "TMPDIR" );
  963. // If it's NULL, or it doesn't exist, or it isn't a directory, fallback to /tmp.
  964. struct stat buf;
  965. if( !tmpdir || stat( tmpdir, &buf ) || !S_ISDIR ( buf.st_mode ) )
  966. tmpdir = "/tmp";
  967. V_snprintf( g_lockFilename, sizeof(g_lockFilename), "%s/source_engine_%lu.lock", tmpdir, gameCRC );
  968. g_lockfd = open( g_lockFilename, O_WRONLY | O_CREAT, 0666 );
  969. if ( g_lockfd == -1 )
  970. {
  971. printf( "open(%s) failed\n", g_lockFilename );
  972. return false;
  973. }
  974. // In case we have a umask setting creation to something other than 0666,
  975. // force it to 0666 so we don't lock other users out of the game if
  976. // the game dies etc.
  977. fchmod(g_lockfd, 0666);
  978. struct flock fl;
  979. fl.l_type = F_WRLCK;
  980. fl.l_whence = SEEK_SET;
  981. fl.l_start = 0;
  982. fl.l_len = 1;
  983. if ( fcntl ( g_lockfd, F_SETLK, &fl ) == -1 )
  984. {
  985. printf( "fcntl(%d) for %s failed\n", g_lockfd, g_lockFilename );
  986. return false;
  987. }
  988. return true;
  989. #else
  990. /*
  991. * OSX
  992. */
  993. V_snprintf( g_lockFilename, sizeof(g_lockFilename), "/tmp/source_engine_%lu.lock", gameCRC );
  994. g_lockfd = open( g_lockFilename, O_CREAT | O_WRONLY | O_EXLOCK | O_NONBLOCK | O_TRUNC, 0777 );
  995. if (g_lockfd >= 0)
  996. {
  997. // make sure we give full perms to the file, we only one instance per machine
  998. fchmod( g_lockfd, 0777 );
  999. // we leave the file open, under unix rules when we die we'll automatically close and remove the locks
  1000. return true;
  1001. }
  1002. // We were unable to open the file, it should be because we are unable to retain a lock
  1003. if ( errno != EWOULDBLOCK)
  1004. {
  1005. fprintf( stderr, "unexpected error %d trying to exclusively lock %s\n", errno, g_lockFilename );
  1006. // Let them launch because we don't know what's going on and wouldn't want
  1007. // to stop them launching.
  1008. return true;
  1009. }
  1010. return false;
  1011. #endif // LINUX
  1012. #endif // POSIX
  1013. return true;
  1014. }
  1015. void ReleaseSourceMutex()
  1016. {
  1017. #ifdef WIN32
  1018. if ( IsPC() && g_hMutex )
  1019. {
  1020. ::ReleaseMutex( g_hMutex );
  1021. ::CloseHandle( g_hMutex );
  1022. g_hMutex = NULL;
  1023. }
  1024. #elif defined( POSIX )
  1025. if ( g_lockfd != -1 )
  1026. {
  1027. close( g_lockfd );
  1028. g_lockfd = -1;
  1029. unlink( g_lockFilename );
  1030. }
  1031. #endif
  1032. }
  1033. // Remove all but the last -game parameter.
  1034. // This is for mods based off something other than Half-Life 2 (like HL2MP mods).
  1035. // The Steam UI does 'steam -applaunch 320 -game c:\steam\steamapps\sourcemods\modname', but applaunch inserts
  1036. // its own -game parameter, which would supercede the one we really want if we didn't intercede here.
  1037. void RemoveSpuriousGameParameters()
  1038. {
  1039. // Find the last -game parameter.
  1040. int nGameArgs = 0;
  1041. char lastGameArg[MAX_PATH];
  1042. for ( int i=0; i < CommandLine()->ParmCount()-1; i++ )
  1043. {
  1044. if ( Q_stricmp( CommandLine()->GetParm( i ), "-game" ) == 0 )
  1045. {
  1046. Q_snprintf( lastGameArg, sizeof( lastGameArg ), "\"%s\"", CommandLine()->GetParm( i+1 ) );
  1047. ++nGameArgs;
  1048. ++i;
  1049. }
  1050. }
  1051. // We only care if > 1 was specified.
  1052. if ( nGameArgs > 1 )
  1053. {
  1054. CommandLine()->RemoveParm( "-game" );
  1055. CommandLine()->AppendParm( "-game", lastGameArg );
  1056. }
  1057. }
  1058. //-----------------------------------------------------------------------------
  1059. // Purpose:
  1060. // Input : *param -
  1061. // Output : static char const
  1062. //-----------------------------------------------------------------------------
  1063. static char const *Cmd_TranslateFileAssociation(char const *param )
  1064. {
  1065. static char sz[ 512 ];
  1066. char *retval = NULL;
  1067. char temp[ 512 ];
  1068. Q_strncpy( temp, param, sizeof( temp ) );
  1069. Q_FixSlashes( temp );
  1070. #ifdef WIN32
  1071. Q_strlower( temp );
  1072. #endif
  1073. const char *extension = V_GetFileExtension(temp);
  1074. // must have an extension to map
  1075. if (!extension)
  1076. return retval;
  1077. extension--; // back up so we have the . in the extension
  1078. int c = ARRAYSIZE( g_FileAssociations );
  1079. for ( int i = 0; i < c; i++ )
  1080. {
  1081. FileAssociationInfo& info = g_FileAssociations[ i ];
  1082. if ( ! Q_strcmp( extension, info.extension ) &&
  1083. ! CommandLine()->FindParm(CFmtStr( "+%s", info.command_to_issue ) ) )
  1084. {
  1085. // Translate if haven't already got one of these commands
  1086. Q_strncpy( sz, temp, sizeof( sz ) );
  1087. Q_FileBase( sz, temp, sizeof( sz ) );
  1088. Q_snprintf( sz, sizeof( sz ), "%s %s", info.command_to_issue, temp );
  1089. retval = sz;
  1090. break;
  1091. }
  1092. }
  1093. // return null if no translation, otherwise return commands
  1094. return retval;
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Purpose: Converts all the convar args into a convar command
  1098. // Input : none
  1099. // Output : const char * series of convars
  1100. //-----------------------------------------------------------------------------
  1101. static const char *BuildCommand()
  1102. {
  1103. static CUtlBuffer build( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1104. build.Clear();
  1105. // arg[0] is the executable name
  1106. for ( int i=1; i < CommandLine()->ParmCount(); i++ )
  1107. {
  1108. const char *szParm = CommandLine()->GetParm(i);
  1109. if (!szParm) continue;
  1110. if (szParm[0] == '-')
  1111. {
  1112. // skip -XXX options and eat their args
  1113. const char *szValue = CommandLine()->ParmValue(szParm);
  1114. if ( szValue ) i++;
  1115. continue;
  1116. }
  1117. if (szParm[0] == '+')
  1118. {
  1119. // convert +XXX options and stuff them into the build buffer
  1120. const char *szValue = CommandLine()->ParmValue(szParm);
  1121. if (szValue)
  1122. {
  1123. build.PutString(CFmtStr("%s %s;", szParm+1, szValue));
  1124. i++;
  1125. }
  1126. else
  1127. {
  1128. build.PutString(szParm+1);
  1129. build.PutChar(';');
  1130. }
  1131. }
  1132. else
  1133. {
  1134. // singleton values, convert to command
  1135. char const *translated = Cmd_TranslateFileAssociation( CommandLine()->GetParm( i ) );
  1136. if (translated)
  1137. {
  1138. build.PutString(translated);
  1139. build.PutChar(';');
  1140. }
  1141. }
  1142. }
  1143. build.PutChar( '\0' );
  1144. return (const char *)build.Base();
  1145. }
  1146. DLL_IMPORT CLinkedMiniProfiler *g_pPhysicsMiniProfilers;
  1147. DLL_IMPORT CLinkedMiniProfiler *g_pOtherMiniProfilers;
  1148. CLauncherLoggingListener g_LauncherLoggingListener;
  1149. // #define LOADING_MEMORY_WATCHDOG 100
  1150. // This block enables a thread that dumps memory stats at regular
  1151. // intervals from the moment the thread pool is initialized until the
  1152. // game halts. LOADING_MEMORY_WATCHDOG, if defined, specifies the
  1153. // interval in milliseconds
  1154. #if LOADING_MEMORY_WATCHDOG
  1155. namespace
  1156. {
  1157. /// a thread that's meant to run intermittently at regular intervals
  1158. class CThreadWatchdog : public CThread
  1159. {
  1160. public:
  1161. CThreadWatchdog( unsigned nIntervalInMilliseconds, const char *pszName, int nAffinity );
  1162. // You will need to call Start() and Stop() on this class externally.
  1163. // for debugging purposes -- record how long it took the payload to execute.
  1164. // (circular buffer of four samples)
  1165. CCycleCount m_nPayloadTimers[4];
  1166. unsigned int m_nPayloadTimersNextIdx; //< next timer to write into.
  1167. protected:
  1168. virtual bool Init();
  1169. // the "run" function for this thread, gets called once every nIntervalInMilliseconds.
  1170. // return true to keep running, false to stop.
  1171. virtual bool Payload() = 0;
  1172. unsigned m_nIntervalMsec; /// the watchdog will run once every this many msec
  1173. int m_nAffinityMask;
  1174. private:
  1175. // from CThread. !!DO NOT!! override this in inheritors -- your work should be done in Payload().
  1176. virtual int Run();
  1177. };
  1178. CThreadWatchdog::CThreadWatchdog( unsigned nIntervalInMilliseconds, const char *pszName, int nAffinity ) :
  1179. m_nIntervalMsec(nIntervalInMilliseconds),
  1180. m_nAffinityMask(nAffinity),
  1181. m_nPayloadTimersNextIdx(0)
  1182. {
  1183. SetName( pszName ); // the thread name must be set before calling Start(), or subsequent thread management calls will crash. I don't know why. That's just what happens.
  1184. }
  1185. bool CThreadWatchdog::Init()
  1186. {
  1187. if (!CThread::Init())
  1188. return false;
  1189. ThreadSetAffinity( GetThreadHandle(), m_nAffinityMask );
  1190. return true;
  1191. }
  1192. int CThreadWatchdog::Run()
  1193. {
  1194. bool bContinue;
  1195. do
  1196. {
  1197. CFastTimer payloadtime;
  1198. payloadtime.Start();
  1199. bContinue = Payload();
  1200. payloadtime.End();
  1201. m_nPayloadTimers[ m_nPayloadTimersNextIdx++ & 3 ] = payloadtime.GetDuration();
  1202. Sleep( m_nIntervalMsec );
  1203. } while ( bContinue );
  1204. return 0;
  1205. }
  1206. class CLoadMemoryWatchdog : public CThreadWatchdog
  1207. {
  1208. public:
  1209. CLoadMemoryWatchdog( unsigned nIntervalInMilliseconds, const char *pszFilename ); // filename is assumed to be into a static COMDAT (don't make it in a temp buffer)
  1210. private:
  1211. bool Payload();
  1212. const char *m_pszFilename;
  1213. };
  1214. CLoadMemoryWatchdog::CLoadMemoryWatchdog( unsigned nIntervalInMilliseconds, const char *pszFilename ) :
  1215. CThreadWatchdog( nIntervalInMilliseconds, "LoadMemWatchdog", IsX360() ? XBOX_CORE_0_HWTHREAD_1 : 0 ),
  1216. m_pszFilename(pszFilename)
  1217. {
  1218. }
  1219. bool CLoadMemoryWatchdog::Payload()
  1220. {
  1221. g_pMemAlloc->DumpStatsFileBase( m_pszFilename );
  1222. return true;
  1223. }
  1224. CLoadMemoryWatchdog g_MemWatchdog( LOADING_MEMORY_WATCHDOG, "loadingmemory" );
  1225. }
  1226. #endif
  1227. // this class automatically handles the initialization and uninitialization
  1228. // of the vpbdm library. It's RAII because we absolutely positively have
  1229. // to guarantee that the library cleans up after itself on shutdown,
  1230. // even if we early out of LauncherMain.
  1231. #ifdef _PS3
  1232. class ValvePS3ConsoleInitializerRAII
  1233. {
  1234. public:
  1235. ValvePS3ConsoleInitializerRAII( bool bDvdDev, bool bSpewDllInfo, bool bWaitForConsole )
  1236. {
  1237. #pragma message("TODO: bdvddev / spewdllinfo / wait for console")
  1238. ValvePS3ConsoleInit( );
  1239. if ( g_pValvePS3Console )
  1240. {
  1241. g_pValvePS3Console->InitConsoleMonitor( bWaitForConsole );
  1242. }
  1243. }
  1244. ~ValvePS3ConsoleInitializerRAII()
  1245. {
  1246. ValvePS3ConsoleShutdown();
  1247. }
  1248. };
  1249. #endif
  1250. //-----------------------------------------------------------------------------
  1251. // Purpose: The real entry point for the application
  1252. // Input : hInstance -
  1253. // hPrevInstance -
  1254. // lpCmdLine -
  1255. // nCmdShow -
  1256. // Output : int APIENTRY
  1257. //-----------------------------------------------------------------------------
  1258. #ifdef WIN32
  1259. extern "C" __declspec(dllexport) int LauncherMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
  1260. #elif defined( _PS3 )
  1261. int LauncherMain( int argc, char **argv )
  1262. #else
  1263. extern "C" DLL_EXPORT int LauncherMain( int argc, char **argv )
  1264. #endif
  1265. {
  1266. #ifdef WIN32
  1267. SetAppInstance( hInstance );
  1268. #endif
  1269. #ifdef LINUX
  1270. // fix to stop us from crashing in printf/sscanf functions that don't expect
  1271. // localization to mess with your "." and "," float seperators. Mac OSX also sets LANG
  1272. // to en_US.UTF-8 before starting up (in info.plist I believe).
  1273. // We need to double check that localization for libcef is handled correctly
  1274. // when we slam things to en_US.UTF-8.
  1275. // Also check if C.UTF-8 exists and use it? This file: /usr/lib/locale/C.UTF-8.
  1276. // It looks like it's only installed on Debian distros right now though.
  1277. const char en_US[] = "en_US.UTF-8";
  1278. setenv( "LC_ALL", en_US, 1 );
  1279. setlocale( LC_ALL, en_US );
  1280. const char *CurrentLocale = setlocale( LC_ALL, NULL );
  1281. if ( Q_stricmp( CurrentLocale, en_US ) )
  1282. {
  1283. Warning( "WARNING: setlocale('%s') failed, using locale:'%s'. International characters may not work.\n", en_US, CurrentLocale );
  1284. }
  1285. #endif // LINUX
  1286. // Hook the debug output stuff.
  1287. LoggingSystem_RegisterLoggingListener( &g_LauncherLoggingListener );
  1288. #ifndef _PS3
  1289. // Quickly check the hardware key, essentially a warning shot.
  1290. if ( !Plat_VerifyHardwareKeyPrompt() )
  1291. {
  1292. return -1;
  1293. }
  1294. #endif // !_PS3
  1295. #ifdef WIN32
  1296. CommandLine()->CreateCmdLine( IsPC() ? GetCommandLine() : lpCmdLine );
  1297. #else
  1298. CommandLine()->CreateCmdLine( argc, argv );
  1299. #endif
  1300. #if defined (PLATFORM_OSX) || defined (WIN32)
  1301. // No -dxlevel or +mat_hdr_level allowed in CSGO
  1302. CommandLine()->RemoveParm( "-dxlevel" );
  1303. CommandLine()->RemoveParm( "+mat_hdr_level" );
  1304. CommandLine()->RemoveParm( "+mat_dxlevel" );
  1305. #endif
  1306. #ifndef _PS3
  1307. // Figure out the directory the executable is running from
  1308. UTIL_ComputeBaseDir();
  1309. #endif // _PS3
  1310. #if defined (CSTRIKE15)
  1311. // GS - If we didn't specify a game name then default to CSGO
  1312. // This is required for running from a HDD Boot Game package
  1313. if ( CommandLine()->CheckParm( "-game") == NULL )
  1314. {
  1315. CommandLine()->AppendParm( "-game", "csgo" );
  1316. }
  1317. #if defined _PS3
  1318. if ( g_pPS3PathInfo->BootType() == CELL_GAME_GAMETYPE_HDD )
  1319. {
  1320. CommandLine()->AppendParm( "+sv_search_key", "testlab" );
  1321. CommandLine()->AppendParm( "-steamBeta", "");
  1322. }
  1323. #endif
  1324. #endif
  1325. bool bDvdDev, bSpewDllInfo, bWaitForConsole;
  1326. bDvdDev = CommandLine()->CheckParm( "-dvddev" ) != NULL;
  1327. bSpewDllInfo = CommandLine()->CheckParm( "-dllinfo" ) != NULL;
  1328. bWaitForConsole = CommandLine()->CheckParm( "-vxconsole" ) != NULL;
  1329. #if defined( _X360 )
  1330. XboxConsoleInit();
  1331. // sync block until vxconsole responds
  1332. XBX_InitConsoleMonitor( bWaitForConsole || bSpewDllInfo || bDvdDev );
  1333. if ( bDvdDev )
  1334. {
  1335. // just launched, signal vxconsole to sync the dvddev cache before any files get accessed
  1336. XBX_rSyncDvdDevCache();
  1337. }
  1338. #elif defined( _PS3 )
  1339. ValvePS3ConsoleInitializerRAII VXBDM( bDvdDev, bSpewDllInfo, bWaitForConsole );
  1340. #endif
  1341. #if LOADING_MEMORY_WATCHDOG
  1342. g_MemWatchdog.Start();
  1343. #endif
  1344. #if defined( _X360 )
  1345. if ( bWaitForConsole )
  1346. {
  1347. COM_TimestampedLog( "LauncherMain: Application Start - %s", CommandLine()->GetCmdLine() );
  1348. }
  1349. if ( bSpewDllInfo )
  1350. {
  1351. XBX_DumpDllInfo( GetBaseDirectory() );
  1352. Error( "Stopped!\n" );
  1353. }
  1354. int storageIDs[4];
  1355. XboxLaunch()->GetStorageID( storageIDs );
  1356. for ( int k = 0; k < 4; ++ k )
  1357. {
  1358. DWORD storageID = storageIDs[k];
  1359. if ( XBX_DescribeStorageDevice( storageID ) )
  1360. {
  1361. // Validate the storage device
  1362. XDEVICE_DATA deviceData;
  1363. DWORD ret = XContentGetDeviceData( storageID, &deviceData );
  1364. if ( ret != ERROR_SUCCESS )
  1365. {
  1366. // Device was removed
  1367. storageID = XBX_INVALID_STORAGE_ID;
  1368. XBX_QueueEvent( XEV_LISTENER_NOTIFICATION, WM_SYS_STORAGEDEVICESCHANGED, 0, 0 );
  1369. }
  1370. }
  1371. XBX_SetStorageDeviceId( k, storageID );
  1372. }
  1373. int userID = XboxLaunch()->GetUserID();
  1374. userID = XBX_INVALID_USER_ID; // TODO: currently game cannot recover from a restart with users signed-in
  1375. if ( userID == XBX_INVALID_USER_ID )
  1376. {
  1377. // didn't come from restart, start up with guest settings
  1378. XUSER_SIGNIN_INFO info;
  1379. for ( int i = 0; i < 4; ++i )
  1380. {
  1381. if ( ERROR_NO_SUCH_USER != XUserGetSigninInfo( i, 0, &info ) )
  1382. {
  1383. userID = i;
  1384. break;
  1385. }
  1386. }
  1387. XBX_SetNumGameUsers( 0 );
  1388. XBX_SetPrimaryUserId( XBX_INVALID_USER_ID );
  1389. XBX_ResetUserIdSlots();
  1390. XBX_SetPrimaryUserIsGuest( 1 );
  1391. }
  1392. else
  1393. {
  1394. int numGameUsers;
  1395. char slot2ctrlr[4];
  1396. char slot2guest[4];
  1397. XboxLaunch()->GetSlotUsers( numGameUsers, slot2ctrlr, slot2guest );
  1398. XBX_SetNumGameUsers( numGameUsers );
  1399. XBX_SetPrimaryUserId( userID );
  1400. if ( numGameUsers == 1 && slot2guest[0] == 1 )
  1401. XBX_SetPrimaryUserIsGuest( 1 );
  1402. else
  1403. XBX_SetPrimaryUserIsGuest( 0 );
  1404. for ( int k = 0; k < 4; ++ k )
  1405. {
  1406. XBX_SetUserId( k, slot2ctrlr[k] );
  1407. XBX_SetUserIsGuest( k, slot2guest[k] );
  1408. }
  1409. }
  1410. #ifdef PLATFORM_OSX
  1411. {
  1412. struct stat st;
  1413. if ( stat( RELAUNCH_FILE, &st ) == 0 )
  1414. {
  1415. unlink( RELAUNCH_FILE );
  1416. }
  1417. }
  1418. #endif
  1419. DevMsg( "[X360 LAUNCH] Started with the following payload:\n" );
  1420. DevMsg( " Num Game Users = %d\n", XBX_GetNumGameUsers() );
  1421. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  1422. {
  1423. DevMsg( " Storage Device %d = 0x%08X\n", XBX_GetStorageDeviceId( k ) );
  1424. }
  1425. #endif
  1426. // check for a named executable
  1427. const char *exeFilename = GetExecutableFilename();
  1428. if ( !IsGameConsole() && exeFilename[0] && Q_strcmp( exeFilename, "hl2" ) && !CommandLine()->FindParm( "-game" ) )
  1429. {
  1430. CommandLine()->RemoveParm( "-game" );
  1431. CommandLine()->AppendParm( "-game", exeFilename );
  1432. }
  1433. // Uncomment the following code to allow multiplayer on the Xbox 360 for trade shows.
  1434. #if 0
  1435. #if defined( CSTRIKE15 ) && defined( _X360 ) && !defined( _CERT )
  1436. if ( CommandLine()->FindParm( "-xnet_bypass_security" ) == 0 )
  1437. {
  1438. CommandLine()->AppendParm( "-xnet_bypass_security", "" );
  1439. Warning( "adding -xnet_bypass_security to command line. Remove this for shipping!\n" );
  1440. }
  1441. if ( CommandLine()->FindParm( "-demo_pressbuild_play_addr" ) == 0 )
  1442. {
  1443. CommandLine()->AppendParm( "-demo_pressbuild_play_addr", "192.168.1.100:27015" );
  1444. Warning( "adding -demo_pressbuild_play_addr to command line. Remove this for shipping!\n" );
  1445. }
  1446. #endif
  1447. #endif
  1448. #ifdef SIXENSE
  1449. // If the game arg is currently portal2
  1450. char const *game_param_val = NULL;
  1451. CommandLine()->CheckParm( "-game", &game_param_val );
  1452. if( game_param_val && !Q_strcmp( game_param_val, "portal2" ) )
  1453. {
  1454. // and if there is a portal2_sixense dir that contains a valid gameinfo.txt, then override the game parameter to use that instead
  1455. if( !CommandLine()->CheckParm( "-nosixense" ) && DoesFileExistIn( ".", "portal2_sixense/gameinfo.txt" ) )
  1456. {
  1457. CommandLine()->RemoveParm( "-game" );
  1458. CommandLine()->AppendParm( "-game", "portal2_sixense" );
  1459. }
  1460. }
  1461. #endif
  1462. #ifdef _PS3
  1463. if ( CommandLine()->CheckParm( "-dvddev" ) &&
  1464. !CommandLine()->CheckParm( "-basedir" ) )
  1465. {
  1466. CommandLine()->AppendParm( "-basedir", g_pPS3PathInfo->GameImagePath() );
  1467. }
  1468. #endif
  1469. #ifndef _CERT
  1470. if ( CommandLine()->CheckParm( "-tslist" ) )
  1471. {
  1472. //TestThreads(1);
  1473. int nTests = 10000;
  1474. DevMsg("Running TSList tests\n");
  1475. RunTSListTests( nTests );
  1476. DevMsg("Running TSQueue tests\n");
  1477. RunTSQueueTests( nTests );
  1478. DevMsg("Running Thread Pool tests\n");
  1479. RunThreadPoolTests();
  1480. }
  1481. #endif
  1482. // This call is to emulate steam's injection of the GameOverlay DLL into our process if we
  1483. // are running from the command line directly, this allows the same experience the user gets
  1484. // to be present when running from perforce, the call has no effect on X360
  1485. TryToLoadSteamOverlayDLL();
  1486. // See the function for why we do this.
  1487. RemoveSpuriousGameParameters();
  1488. #ifdef WIN32
  1489. if ( IsPC() )
  1490. {
  1491. // initialize winsock
  1492. WSAData wsaData;
  1493. int nError = ::WSAStartup( MAKEWORD(2,0), &wsaData );
  1494. if ( nError )
  1495. {
  1496. Msg( "Warning! Failed to start Winsock via WSAStartup = 0x%x.\n", nError);
  1497. }
  1498. }
  1499. #endif
  1500. // Run in text mode? (No graphics or sound).
  1501. if ( CommandLine()->CheckParm( "-textmode" ) )
  1502. {
  1503. #if defined( DEVELOPMENT_ONLY ) || defined( ALLOW_TEXT_MODE )
  1504. g_bTextMode = true;
  1505. InitTextMode();
  1506. #endif
  1507. }
  1508. #ifdef WIN32
  1509. #if defined( DEBUG ) && defined( ALLOW_MULTI_CLIENTS_PER_MACHINE )
  1510. else if ( true )
  1511. {
  1512. Warning("Skipping multiple clients from one machine check! Don't ship this way!\n");
  1513. }
  1514. #endif
  1515. else if ( !IsX360() )
  1516. {
  1517. int retval = -1;
  1518. // Can only run one windowed source app at a time
  1519. if ( !GrabSourceMutex() )
  1520. {
  1521. // We're going to hijack the existing session and load a new savegame into it. This will mainly occur when users click on links in Bugzilla that will automatically copy saves and load them
  1522. // directly from the web browser. The -hijack command prevents the launcher from objecting that there is already an instance of the game.
  1523. if (CommandLine()->CheckParm( "-hijack" ))
  1524. {
  1525. HWND hwndEngine = FindWindow( "Valve001", NULL );
  1526. // Can't find the engine
  1527. if ( hwndEngine == NULL )
  1528. {
  1529. ::MessageBox( NULL, "The modified entity keyvalues could not be sent to the Source Engine because the engine does not appear to be running.", "Source Engine Not Running", MB_OK | MB_ICONEXCLAMATION );
  1530. }
  1531. else
  1532. {
  1533. const char *szCommand = BuildCommand();
  1534. //
  1535. // Fill out the data structure to send to the engine.
  1536. //
  1537. COPYDATASTRUCT copyData;
  1538. copyData.cbData = strlen( szCommand ) + 1;
  1539. copyData.dwData = 0;
  1540. copyData.lpData = ( void * )szCommand;
  1541. if ( !::SendMessage( hwndEngine, WM_COPYDATA, 0, (LPARAM)&copyData ) )
  1542. {
  1543. ::MessageBox( NULL, "The Source Engine was found running, but did not accept the request to load a savegame. It may be an old version of the engine that does not support this functionality.", "Source Engine Declined Request", MB_OK | MB_ICONEXCLAMATION );
  1544. }
  1545. else
  1546. {
  1547. retval = 0;
  1548. }
  1549. free((void *)szCommand);
  1550. }
  1551. }
  1552. else
  1553. {
  1554. ::MessageBox(NULL, "Only one instance of the game can be running at one time.", "Source - Warning", MB_ICONINFORMATION | MB_OK);
  1555. }
  1556. return retval;
  1557. }
  1558. }
  1559. #elif defined( POSIX )
  1560. else
  1561. {
  1562. if ( !GrabSourceMutex() )
  1563. {
  1564. ::MessageBox(NULL, "Only one instance of the game can be running at one time.", "Source - Warning", 0 );
  1565. return -1;
  1566. }
  1567. }
  1568. #endif
  1569. if ( !IsX360() )
  1570. {
  1571. #ifdef WIN32
  1572. // Make low priority?
  1573. if ( CommandLine()->CheckParm( "-low" ) )
  1574. {
  1575. SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
  1576. }
  1577. else if ( CommandLine()->CheckParm( "-high" ) )
  1578. {
  1579. SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
  1580. }
  1581. #endif
  1582. // If game is not run from Steam then add -insecure in order to avoid client timeout message
  1583. if ( NULL == CommandLine()->CheckParm( "-steam" ) )
  1584. {
  1585. CommandLine()->AppendParm( "-insecure", NULL );
  1586. }
  1587. }
  1588. #ifndef _PS3
  1589. // Figure out the directory the executable is running from
  1590. // and make that be the current working directory
  1591. // on the PS3, however, there is no concept of current directories
  1592. _chdir( GetBaseDirectory() );
  1593. #endif
  1594. // When building cubemaps, we don't need sound and can't afford to have async I/O - cubemap writes to the BSP can collide with async bsp reads
  1595. if ( CommandLine()->CheckParm( "-buildcubemaps") )
  1596. {
  1597. CommandLine()->AppendParm( "-nosound", NULL );
  1598. CommandLine()->AppendParm( "-noasync", NULL );
  1599. }
  1600. g_LeakDump.m_bCheckLeaks = CommandLine()->CheckParm( "-leakcheck" ) ? true : false;
  1601. bool bRestart = true;
  1602. while ( bRestart )
  1603. {
  1604. bRestart = false;
  1605. CSourceAppSystemGroup sourceSystems;
  1606. CSteamApplication steamApplication( &sourceSystems );
  1607. #if defined( OSX ) && !defined( USE_SDL )
  1608. extern int ValveCocoaMain( CAppSystemGroup *pApp );
  1609. int nRetval = ValveCocoaMain( &steamApplication );
  1610. #else
  1611. int nRetval = steamApplication.Run();
  1612. #endif
  1613. #if ENABLE_HARDWARE_PROFILER
  1614. // Hack fix, causes memory leak, but prevents crash due to bad coding not doing proper teardown
  1615. // need to ensure these list anchors don't anchor stale pointers
  1616. g_pPhysicsMiniProfilers = NULL;
  1617. g_pOtherMiniProfilers = NULL;
  1618. #endif
  1619. if ( steamApplication.GetCurrentStage() == CSourceAppSystemGroup::INITIALIZATION )
  1620. {
  1621. bRestart = (nRetval == INIT_RESTART);
  1622. }
  1623. else if ( nRetval == RUN_RESTART )
  1624. {
  1625. bRestart = true;
  1626. }
  1627. bool bReslistCycle = false;
  1628. if ( !bRestart )
  1629. {
  1630. bReslistCycle = reslistgenerator->ShouldContinue();
  1631. bRestart = bReslistCycle;
  1632. }
  1633. if ( !bReslistCycle )
  1634. {
  1635. // Remove any overrides in case settings changed
  1636. CommandLine()->RemoveParm( "-w" );
  1637. CommandLine()->RemoveParm( "-h" );
  1638. CommandLine()->RemoveParm( "-width" );
  1639. CommandLine()->RemoveParm( "-height" );
  1640. CommandLine()->RemoveParm( "-sw" );
  1641. CommandLine()->RemoveParm( "-startwindowed" );
  1642. CommandLine()->RemoveParm( "-windowed" );
  1643. CommandLine()->RemoveParm( "-window" );
  1644. CommandLine()->RemoveParm( "-full" );
  1645. CommandLine()->RemoveParm( "-fullscreen" );
  1646. CommandLine()->RemoveParm( "-autoconfig" );
  1647. CommandLine()->RemoveParm( "+mat_hdr_level" );
  1648. }
  1649. }
  1650. #ifdef WIN32
  1651. if ( IsPC() )
  1652. {
  1653. // shutdown winsock
  1654. int nError = ::WSACleanup();
  1655. if ( nError )
  1656. {
  1657. Msg( "Warning! Failed to complete WSACleanup = 0x%x.\n", nError );
  1658. }
  1659. }
  1660. #endif
  1661. // Allow other source apps to run
  1662. ReleaseSourceMutex();
  1663. #if defined( WIN32 ) && !defined( _X360 )
  1664. // Now that the mutex has been released, check HKEY_CURRENT_USER\Software\Valve\Source\Relaunch URL. If there is a URL here, exec it.
  1665. // This supports the capability of immediately re-launching the the game via Steam in a different audio language
  1666. HKEY hKey;
  1667. if ( RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Source", NULL, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS )
  1668. {
  1669. char szValue[MAX_PATH];
  1670. DWORD dwValueLen = MAX_PATH;
  1671. if ( RegQueryValueEx( hKey, "Relaunch URL", NULL, NULL, (unsigned char*)szValue, &dwValueLen ) == ERROR_SUCCESS )
  1672. {
  1673. ShellExecute (0, "open", szValue, 0, 0, SW_SHOW);
  1674. RegDeleteValue( hKey, "Relaunch URL" );
  1675. }
  1676. RegCloseKey(hKey);
  1677. }
  1678. #elif defined( OSX )
  1679. struct stat st;
  1680. if ( stat( RELAUNCH_FILE, &st ) == 0 )
  1681. {
  1682. FILE *fp = fopen( RELAUNCH_FILE, "r" );
  1683. if ( fp )
  1684. {
  1685. char szCmd[256];
  1686. int nChars = fread( szCmd, 1, sizeof(szCmd), fp );
  1687. if ( nChars > 0 )
  1688. {
  1689. char szOpenLine[ MAX_PATH ];
  1690. Q_snprintf( szOpenLine, sizeof(szOpenLine), "open \"%s\"", szCmd );
  1691. system( szOpenLine );
  1692. }
  1693. fclose( fp );
  1694. unlink( RELAUNCH_FILE );
  1695. }
  1696. }
  1697. #endif
  1698. return 0;
  1699. }