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.

2978 lines
80 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. // fopen is needed to write steam_appid.txt
  8. #undef fopen
  9. #include <stdio.h>
  10. #if defined(OSX) || defined(LINUX) || (defined (WIN32) && defined( DX_TO_GL_ABSTRACTION ))
  11. #include "appframework/ilaunchermgr.h"
  12. #endif
  13. #if defined( _WIN32 )
  14. #if !defined( _X360 )
  15. #include "winlite.h"
  16. #endif
  17. #elif defined(LINUX)
  18. #elif defined( _PS3 )
  19. #elif defined(OSX)
  20. #include <Carbon/Carbon.h>
  21. #else
  22. #error
  23. #endif
  24. #include "quakedef.h"
  25. #include "idedicatedexports.h"
  26. #include "engine_launcher_api.h"
  27. #include "ivideomode.h"
  28. #include "common.h"
  29. #include "iregistry.h"
  30. #include "keys.h"
  31. #include "cdll_engine_int.h"
  32. #include "traceinit.h"
  33. #include "iengine.h"
  34. #include "igame.h"
  35. #include "tier1/fmtstr.h"
  36. #include "engine_hlds_api.h"
  37. #include "filesystem_engine.h"
  38. #include "tier0/icommandline.h"
  39. #include "cl_main.h"
  40. #include "client.h"
  41. #include "tier3/tier3.h"
  42. #include "MapReslistGenerator.h"
  43. #include "toolframework/itoolframework.h"
  44. #include "DevShotGenerator.h"
  45. #include "gl_shader.h"
  46. #include "l_studio.h"
  47. #include "IHammer.h"
  48. #ifdef _WIN32
  49. #include "vgui/ILocalize.h"
  50. #endif
  51. #include "sys_dll.h"
  52. #include "materialsystem/materialsystem_config.h"
  53. #include "server.h"
  54. #include "avi/iavi.h"
  55. #include "avi/ibik.h"
  56. #include "datacache/idatacache.h"
  57. #include "vphysics_interface.h"
  58. #include "inputsystem/iinputsystem.h"
  59. #include "appframework/IAppSystemGroup.h"
  60. #include "tier0/systeminformation.h"
  61. #ifdef _WIN32
  62. #include "VGuiMatSurface/IMatSystemSurface.h"
  63. #endif
  64. #include "steam/steam_api.h"
  65. // This is here just for legacy support of older .dlls!!!
  66. #include "SoundEmitterSystem/isoundemittersystembase.h"
  67. #include "eiface.h"
  68. #include "matchmaking/imatchframework.h"
  69. #include "profile.h"
  70. #include "status.h"
  71. #include "vjobs_interface.h"
  72. #ifndef DEDICATED
  73. #include "sys_mainwind.h"
  74. #include "vgui/ISystem.h"
  75. #include "vgui_controls/Controls.h"
  76. #include "IGameUIFuncs.h"
  77. #include "cl_steamauth.h"
  78. #endif // DEDICATED
  79. #if defined( INCLUDE_SCALEFORM )
  80. #include "scaleformui/scaleformui.h"
  81. #endif
  82. #if defined(_WIN32)
  83. #include <eh.h>
  84. #include <imm.h>
  85. #endif
  86. #if defined( _X360 )
  87. #include "xbox/xbox_win32stubs.h"
  88. #else
  89. #include "xbox/xboxstubs.h"
  90. #endif
  91. #if defined( _PS3 ) && !defined( NO_STEAM )
  92. #include "ps3_pathinfo.h"
  93. #include "steam/steamps3params_internal.h"
  94. SteamPS3ParamsInternal_t g_EngineSteamPS3ParamsInternal;
  95. SteamPS3Params_t g_EngineSteamPS3Params;
  96. #endif
  97. #ifdef _PS3
  98. #include <np.h>
  99. #include "ps3_cstrike15/ps3_title_id.h"
  100. #include "ps3/saverestore_ps3_api_ui.h"
  101. #endif
  102. // memdbgon must be the last include file in a .cpp file!!!
  103. #include "tier0/memdbgon.h"
  104. //-----------------------------------------------------------------------------
  105. // Globals
  106. //-----------------------------------------------------------------------------
  107. IDedicatedExports *dedicated = NULL;
  108. extern CreateInterfaceFn g_AppSystemFactory;
  109. IHammer *g_pHammer = NULL;
  110. IPhysics *g_pPhysics = NULL;
  111. #if defined(OSX) || defined(LINUX) || (defined (WIN32) && defined( DX_TO_GL_ABSTRACTION ))
  112. ILauncherMgr *g_pLauncherMgr = NULL;
  113. #endif
  114. IAvi *avi = NULL;
  115. IBik *bik = NULL;
  116. #ifdef _PS3
  117. IPS3SaveRestoreToUI *ps3saveuiapi = NULL;
  118. #endif
  119. #if defined( INCLUDE_SCALEFORM )
  120. IScaleformUI* g_pScaleformUI = NULL;
  121. #endif
  122. #ifndef DEDICATED
  123. extern CreateInterfaceFn g_ClientFactory;
  124. #endif
  125. bool g_bRunningFromPerforce;
  126. AppId_t g_unSteamAppID = k_uAppIdInvalid;
  127. CSysModule *g_pMatchmakingDllModule = NULL;
  128. CreateInterfaceFn g_pfnMatchmakingFactory = NULL;
  129. IVJobs * g_pVJobs = NULL;
  130. #ifdef ENGINE_MANAGES_VJOBS
  131. CSysModule *g_pVjobsDllModule = NULL;
  132. CreateInterfaceFn g_pfnVjobsFactory = NULL;
  133. bool g_bVjobsReload = false;
  134. bool g_bVjobsTest = false; // this is temporary, debug-only variable
  135. #endif
  136. IMatchFramework *g_pIfaceMatchFramework = NULL;
  137. bool s_bIsDedicatedServer = false;
  138. //-----------------------------------------------------------------------------
  139. // Forward declarations
  140. //-----------------------------------------------------------------------------
  141. void Host_GetHostInfo(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen );
  142. const char *Key_BindingForKey( ButtonCode_t code );
  143. void COM_ShutdownFileSystem( void );
  144. void COM_InitFilesystem( const char *pFullModPath );
  145. void Host_ReadPreStartupConfiguration();
  146. void EditorToggle_f();
  147. #ifdef _WIN32
  148. HWND *pmainwindow = NULL;
  149. #elif OSX
  150. WindowRef pmainwindow;
  151. #elif LINUX
  152. void *pmainwindow = NULL;
  153. #elif defined( _PS3 )
  154. void *pmainwindow = NULL;
  155. #else
  156. #error
  157. #endif
  158. //-----------------------------------------------------------------------------
  159. // ConVars and console commands
  160. //-----------------------------------------------------------------------------
  161. #if !defined(DEDICATED)
  162. static ConCommand editor_toggle( "editor_toggle", EditorToggle_f, "Disables the simulation and returns focus to the editor", FCVAR_CHEAT );
  163. #endif
  164. #ifndef DEDICATED
  165. //-----------------------------------------------------------------------------
  166. // Purpose: exports an interface that can be used by the launcher to run the engine
  167. // this is the exported function when compiled as a blob
  168. //-----------------------------------------------------------------------------
  169. void EXPORT F( IEngineAPI **api )
  170. {
  171. CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary to prevent the LTCG compiler from crashing.
  172. *api = ( IEngineAPI * )(factory(VENGINE_LAUNCHER_API_VERSION, NULL));
  173. }
  174. #endif // DEDICATED
  175. extern bool cs_initialized;
  176. extern int lowshift;
  177. static char *empty_string = "";
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. //-----------------------------------------------------------------------------
  181. extern void SCR_UpdateScreen(void);
  182. extern bool g_bMajorMapChange;
  183. extern bool g_bPrintingKeepAliveDots;
  184. void Sys_ShowProgressTicks(char* specialProgressMsg)
  185. {
  186. #ifdef LATER
  187. #define MAX_NUM_TICS 40
  188. static long numTics = 0;
  189. // Nothing to do if not using Steam
  190. if ( !g_pFileSystem->IsSteam() )
  191. return;
  192. // Update number of tics to show...
  193. numTics++;
  194. if ( isDedicated )
  195. {
  196. if ( g_bMajorMapChange )
  197. {
  198. g_bPrintingKeepAliveDots = TRUE;
  199. Msg(".");
  200. }
  201. }
  202. else
  203. {
  204. int i;
  205. int numTicsToPrint = numTics % (MAX_NUM_TICS-1);
  206. char msg[MAX_NUM_TICS+1];
  207. Q_strncpy(msg, ".", sizeof(msg));
  208. // Now add in the growing number of tics...
  209. for ( i = 1 ; i < numTicsToPrint ; i++ )
  210. {
  211. Q_strncat(msg, ".", sizeof(msg), COPY_ALL_CHARACTERS);
  212. }
  213. SCR_UpdateScreen();
  214. }
  215. #endif
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose:
  219. //-----------------------------------------------------------------------------
  220. void ClearIOStates( void )
  221. {
  222. #ifndef DEDICATED
  223. if ( g_ClientDLL )
  224. {
  225. g_ClientDLL->IN_ClearStates();
  226. }
  227. #endif
  228. }
  229. void MoveConsoleWindowToFront()
  230. {
  231. #ifdef _WIN32
  232. // TODO: remove me!!!!!
  233. // Move the window to the front.
  234. HINSTANCE hInst = LoadLibrary( "kernel32.dll" );
  235. if ( hInst )
  236. {
  237. typedef HWND (*GetConsoleWindowFn)();
  238. GetConsoleWindowFn fn = (GetConsoleWindowFn)GetProcAddress( hInst, "GetConsoleWindow" );
  239. if ( fn )
  240. {
  241. HWND hwnd = fn();
  242. ShowWindow( hwnd, SW_SHOW );
  243. UpdateWindow( hwnd );
  244. SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
  245. }
  246. FreeLibrary( hInst );
  247. }
  248. #endif
  249. }
  250. #if defined( _WIN32 ) && !defined( _X360 )
  251. #include <conio.h>
  252. #endif
  253. CUtlVector<char> g_TextModeLine;
  254. char NextGetch()
  255. {
  256. return -1;
  257. // NOTE: for some reason, kbhit() KILLS performance on the client.. when using it, the client
  258. // goes so slow that it's player's motion is all jerky. If we need input, probably the
  259. // best thing to do is to hook the console window's wndproc and get the keydown messages.
  260. /*
  261. // Sort of hacky to overload the gamemsg loop with these messages, but it does the trick.
  262. if ( VCRGetMode() == VCR_Playback )
  263. {
  264. unsigned int uMsg, wParam;
  265. long lParam;
  266. if ( VCRHook_PlaybackGameMsg( uMsg, wParam, lParam ) )
  267. {
  268. Assert( uMsg == 0xFFFF );
  269. return (char)wParam;
  270. }
  271. else
  272. {
  273. return -1;
  274. }
  275. }
  276. else
  277. {
  278. if ( kbhit() )
  279. {
  280. char ch = getch();
  281. VCRHook_RecordGameMsg( 0xFFFF, ch, 0 );
  282. return ch;
  283. }
  284. else
  285. {
  286. VCRHook_RecordEndGameMsg();
  287. return -1;
  288. }
  289. }
  290. */
  291. }
  292. void EatTextModeKeyPresses()
  293. {
  294. if ( !g_bTextMode )
  295. return;
  296. static bool bFirstRun = true;
  297. if ( bFirstRun )
  298. {
  299. bFirstRun = false;
  300. MoveConsoleWindowToFront();
  301. }
  302. char ch;
  303. while ( (ch = NextGetch()) != -1 )
  304. {
  305. if ( ch == 8 )
  306. {
  307. // Backspace..
  308. if ( g_TextModeLine.Count() )
  309. {
  310. g_TextModeLine.Remove( g_TextModeLine.Count() - 1 );
  311. }
  312. }
  313. else if ( ch == '\r' )
  314. {
  315. // Finish the line.
  316. if ( g_TextModeLine.Count() )
  317. {
  318. g_TextModeLine.AddMultipleToTail( 2, "\n" );
  319. Cbuf_AddText( Cbuf_GetCurrentPlayer(), g_TextModeLine.Base() );
  320. g_TextModeLine.Purge();
  321. }
  322. printf( "\n" );
  323. }
  324. else
  325. {
  326. g_TextModeLine.AddToTail( ch );
  327. }
  328. printf( "%c", ch );
  329. }
  330. }
  331. //-----------------------------------------------------------------------------
  332. // The SDK launches the game with the full path to gameinfo.txt, so we need
  333. // to strip off the path.
  334. //-----------------------------------------------------------------------------
  335. const char *GetModDirFromPath( const char *pszPath )
  336. {
  337. char *pszSlash = Q_strrchr( pszPath, '\\' );
  338. if ( pszSlash )
  339. {
  340. return pszSlash + 1;
  341. }
  342. else if ( ( pszSlash = Q_strrchr( pszPath, '/' ) ) != NULL )
  343. {
  344. return pszSlash + 1;
  345. }
  346. // Must just be a mod directory already.
  347. return pszPath;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose: Main entry
  351. //-----------------------------------------------------------------------------
  352. #ifndef DEDICATED
  353. #include "gl_matsysiface.h"
  354. #endif
  355. //-----------------------------------------------------------------------------
  356. // Inner loop: initialize, shutdown main systems, load steam to
  357. //-----------------------------------------------------------------------------
  358. class CModAppSystemGroup : public CAppSystemGroup
  359. {
  360. typedef CAppSystemGroup BaseClass;
  361. public:
  362. // constructor
  363. CModAppSystemGroup( bool bServerOnly, CAppSystemGroup *pParentAppSystem = NULL )
  364. : BaseClass( pParentAppSystem ),
  365. m_bServerOnly( bServerOnly )
  366. {
  367. }
  368. CreateInterfaceFn GetFactory()
  369. {
  370. return CAppSystemGroup::GetFactory();
  371. }
  372. // Methods of IApplication
  373. virtual bool Create();
  374. virtual bool PreInit();
  375. virtual int Main();
  376. virtual void PostShutdown();
  377. virtual void Destroy();
  378. private:
  379. bool IsServerOnly() const
  380. {
  381. return m_bServerOnly;
  382. }
  383. bool ModuleAlreadyInList( CUtlVector< AppSystemInfo_t >& list, const char *moduleName, const char *interfaceName );
  384. bool AddLegacySystems();
  385. bool m_bServerOnly;
  386. };
  387. #ifndef DEDICATED
  388. //-----------------------------------------------------------------------------
  389. //
  390. // Main engine interface exposed to launcher
  391. //
  392. //-----------------------------------------------------------------------------
  393. class CEngineAPI : public CTier3AppSystem< IEngineAPI >
  394. {
  395. typedef CTier3AppSystem< IEngineAPI > BaseClass;
  396. public:
  397. virtual bool Connect( CreateInterfaceFn factory );
  398. virtual void Disconnect();
  399. virtual void *QueryInterface( const char *pInterfaceName );
  400. virtual InitReturnVal_t Init();
  401. virtual void Shutdown();
  402. // This function must be called before init
  403. virtual bool SetStartupInfo( StartupInfo_t &info );
  404. virtual int Run( );
  405. // Sets the engine to run in a particular editor window
  406. virtual void SetEngineWindow( void *hWnd );
  407. // Posts a console command
  408. virtual void PostConsoleCommand( const char *pConsoleCommand );
  409. // Are we running the simulation?
  410. virtual bool IsRunningSimulation( ) const;
  411. // Start/stop running the simulation
  412. virtual void ActivateSimulation( bool bActive );
  413. // Reset the map we're on
  414. virtual void SetMap( const char *pMapName );
  415. bool MainLoop();
  416. private:
  417. int RunListenServer();
  418. // Hooks a particular mod up to the registry
  419. void SetRegistryMod( const char *pModName );
  420. // One-time setup, based on the initially selected mod
  421. // FIXME: This should move into the launcher!
  422. bool OnStartup( void *pInstance, const char *pStartupModName );
  423. void OnShutdown();
  424. // Initialization, shutdown of a mod.
  425. bool ModInit( const char *pModName, const char *pGameDir );
  426. void ModShutdown();
  427. // Initializes, shuts down the registry
  428. bool InitRegistry( const char *pModName );
  429. void ShutdownRegistry();
  430. // Handles there being an error setting up the video mode
  431. InitReturnVal_t HandleSetModeError();
  432. // Purpose: Message pump when running stand-alone
  433. void PumpMessages();
  434. // Purpose: Message pump when running with the editor
  435. void PumpMessagesEditMode( bool &bIdle, long &lIdleCount );
  436. // Activate/deactivates edit mode shaders
  437. void ActivateEditModeShaders( bool bActive );
  438. private:
  439. void *m_hEditorHWnd;
  440. bool m_bRunningSimulation;
  441. StartupInfo_t m_StartupInfo;
  442. };
  443. //-----------------------------------------------------------------------------
  444. // Singleton interface
  445. //-----------------------------------------------------------------------------
  446. static CEngineAPI s_EngineAPI;
  447. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineAPI, IEngineAPI, VENGINE_LAUNCHER_API_VERSION, s_EngineAPI );
  448. //-----------------------------------------------------------------------------
  449. // Connect, disconnect
  450. //-----------------------------------------------------------------------------
  451. bool CEngineAPI::Connect( CreateInterfaceFn factory )
  452. {
  453. // Store off the app system factory...
  454. g_AppSystemFactory = factory;
  455. if ( !BaseClass::Connect( factory ) )
  456. return false;
  457. g_pFileSystem = g_pFullFileSystem;
  458. if ( !g_pFileSystem )
  459. return false;
  460. #ifndef DBGFLAG_STRINGS_STRIP
  461. g_pFileSystem->SetWarningFunc( Warning );
  462. #endif
  463. if ( !Shader_Connect( true ) )
  464. return false;
  465. g_pPhysics = (IPhysics*)factory( VPHYSICS_INTERFACE_VERSION, NULL );
  466. if( IsPS3() )
  467. {
  468. // only PS/3 uses vjobs.prx
  469. g_pVJobs = (IVJobs *)factory( VJOBS_INTERFACE_VERSION, NULL );
  470. }
  471. g_pSoundEmitterSystem = (ISoundEmitterSystemBase *)factory(SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL);
  472. #if defined( INCLUDE_SCALEFORM )
  473. g_pScaleformUI = ( IScaleformUI* ) factory( SCALEFORMUI_INTERFACE_VERSION, NULL );
  474. #endif
  475. if ( IsPC() && !IsPosix() )
  476. {
  477. avi = (IAvi*)factory( AVI_INTERFACE_VERSION, NULL );
  478. if ( !avi )
  479. return false;
  480. }
  481. #if ( !defined( _GAMECONSOLE ) || defined( BINK_ENABLED_FOR_CONSOLE ) ) && defined( BINK_VIDEO )
  482. bik = (IBik*)factory( BIK_INTERFACE_VERSION, NULL );
  483. if ( !bik )
  484. return false;
  485. #endif
  486. #ifdef _PS3
  487. ps3saveuiapi = (IPS3SaveRestoreToUI *)factory( IPS3SAVEUIAPI_VERSION_STRING, NULL );
  488. if ( !ps3saveuiapi )
  489. return false;
  490. #endif
  491. if ( !g_pStudioRender || !g_pDataCache || !g_pPhysics || !g_pMDLCache || !g_pMatSystemSurface || !g_pInputSystem || !g_pSoundEmitterSystem)
  492. {
  493. Warning( "Engine wasn't able to acquire required interfaces!\n" );
  494. return false;
  495. }
  496. if (!g_pStudioRender)
  497. {
  498. Sys_Error( "Unable to init studio render system version %s\n", STUDIO_RENDER_INTERFACE_VERSION );
  499. return false;
  500. }
  501. g_pHammer = (IHammer*)factory( INTERFACEVERSION_HAMMER, NULL );
  502. #if defined( USE_SDL )
  503. g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
  504. #elif defined( OSX )
  505. g_pLauncherMgr = (ILauncherMgr *)factory( COCOAMGR_INTERFACE_VERSION, NULL );
  506. #endif
  507. ConnectMDLCacheNotify();
  508. return true;
  509. }
  510. void CEngineAPI::Disconnect()
  511. {
  512. DisconnectMDLCacheNotify();
  513. g_pHammer = NULL;
  514. g_pPhysics = NULL;
  515. g_pSoundEmitterSystem = NULL;
  516. Shader_Disconnect();
  517. g_pFileSystem = NULL;
  518. BaseClass::Disconnect();
  519. g_AppSystemFactory = NULL;
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Query interface
  523. //-----------------------------------------------------------------------------
  524. void *CEngineAPI::QueryInterface( const char *pInterfaceName )
  525. {
  526. // Loading the engine DLL mounts *all* engine interfaces
  527. CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary
  528. return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing.
  529. }
  530. static bool WantsFullMemoryDumps()
  531. {
  532. #if defined( _WIN32 )
  533. return CommandLine()->FindParm( "-full_memory_dumps" ) ? true : false;
  534. #else
  535. return false;
  536. #endif
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Sets startup info
  540. //-----------------------------------------------------------------------------
  541. bool CEngineAPI::SetStartupInfo( StartupInfo_t &info )
  542. {
  543. g_bTextMode = info.m_bTextMode;
  544. // Set up the engineparms_t which contains global information about the mod
  545. host_parms.basedir = const_cast<char*>( info.m_pBaseDirectory );
  546. // Copy off all the startup info
  547. m_StartupInfo = info;
  548. #if defined( _PS3 ) && !defined( NO_STEAM )
  549. {
  550. bool bPublicUniverse = !CommandLine()->FindParm( "-steamBeta" );
  551. //////// DISABLE FOR SHIP! //////////
  552. // BETA: bPublicUniverse = !!CommandLine()->FindParm( "-steamPublic" ); // default=beta; require -steamPublic to run against public
  553. // PUBLIC: bPublicUniverse = !CommandLine()->FindParm( "-steamBeta" ); // default=public; require -steamBeta to run against beta
  554. if ( bPublicUniverse )
  555. {
  556. Msg( "Connecting to Steam Public\n" );
  557. g_EngineSteamPS3Params.m_nAppId = 710;
  558. }
  559. else
  560. {
  561. Msg( "Connecting to Steam Beta\n" );
  562. g_EngineSteamPS3Params.m_nAppId = 710;
  563. g_EngineSteamPS3ParamsInternal.m_nVersion = STEAM_PS3_PARAMS_INTERNAL_VERSION;
  564. g_EngineSteamPS3ParamsInternal.m_eUniverse = k_EUniverseBeta;
  565. g_EngineSteamPS3ParamsInternal.m_pchCMForce = "";
  566. g_EngineSteamPS3ParamsInternal.m_bAutoReloadVGUIResources = false;
  567. g_EngineSteamPS3Params.pReserved = &g_EngineSteamPS3ParamsInternal;
  568. }
  569. if ( int nSteamTTY = CommandLine()->ParmValue( "-steamTTY", int(0) ) )
  570. g_EngineSteamPS3Params.m_cSteamInputTTY = nSteamTTY;
  571. g_EngineSteamPS3Params.m_unVersion = STEAM_PS3_CURRENT_PARAMS_VER;
  572. Q_strncpy( g_EngineSteamPS3Params.m_rgchInstallationPath, g_pPS3PathInfo->PrxPath(), sizeof( g_EngineSteamPS3Params.m_rgchInstallationPath ) );
  573. Q_strncpy( g_EngineSteamPS3Params.m_rgchSystemCache, g_pPS3PathInfo->SystemCachePath(), sizeof( g_EngineSteamPS3Params.m_rgchSystemCache ) );
  574. Q_strncpy( g_EngineSteamPS3Params.m_rgchGameData, g_pPS3PathInfo->SystemCachePath(), sizeof( g_EngineSteamPS3Params.m_rgchGameData ) );
  575. Q_strncpy( g_EngineSteamPS3Params.m_rgchNpServiceID, PS3_GAME_SERVICE_ID, STEAM_PS3_SERVICE_ID_MAX );
  576. Q_strncpy( g_EngineSteamPS3Params.m_rgchNpCommunicationID, PS3_GAME_COMMUNICATION_ID, STEAM_PS3_COMMUNICATION_ID_MAX );
  577. const SceNpCommunicationSignature npcommsign = PS3_GAME_COMMUNICATION_SIGNATURE;
  578. Q_memcpy( g_EngineSteamPS3Params.m_rgchNpCommunicationSig, &npcommsign, STEAM_PS3_COMMUNICATION_SIG_MAX );
  579. Q_strncpy( g_EngineSteamPS3Params.m_rgchSteamLanguage, XBX_GetLanguageString(), STEAM_PS3_LANGUAGE_MAX );
  580. if ( !V_stricmp( g_pPS3PathInfo->GetParamSFO_TitleID(), PS3_GAME_TITLE_ID_WW_SCEE ) )
  581. Q_strncpy( g_EngineSteamPS3Params.m_rgchRegionCode, "SCEE", STEAM_PS3_REGION_CODE_MAX );
  582. else if ( !V_stricmp( g_pPS3PathInfo->GetParamSFO_TitleID(), PS3_GAME_TITLE_ID_WW_SCEJ ) )
  583. Q_strncpy( g_EngineSteamPS3Params.m_rgchRegionCode, "SCEJ", STEAM_PS3_REGION_CODE_MAX );
  584. else
  585. Q_strncpy( g_EngineSteamPS3Params.m_rgchRegionCode, "SCEA", STEAM_PS3_REGION_CODE_MAX );
  586. MEM_ALLOC_CREDIT_( "STEAM: g_EngineSteamPS3Params.m_sysNetInitInfo" );
  587. g_EngineSteamPS3Params.m_sysNetInitInfo.m_bNeedInit = true;
  588. g_EngineSteamPS3Params.m_sysNetInitInfo.m_nMemorySize = 512 * 1024;
  589. g_EngineSteamPS3Params.m_sysNetInitInfo.m_pMemory = malloc( g_EngineSteamPS3Params.m_sysNetInitInfo.m_nMemorySize );
  590. g_EngineSteamPS3Params.m_sysSysUtilUserInfo.m_bNeedInit = true;
  591. g_EngineSteamPS3Params.m_sysJpgInitInfo.m_bNeedInit = true;
  592. g_EngineSteamPS3Params.m_sysPngInitInfo.m_bNeedInit = true;
  593. g_EngineSteamPS3Params.m_bIncludeNewsPage = false;
  594. #if defined(NO_STEAM_PS3_OVERLAY)
  595. g_EngineSteamPS3Params.m_bPersonaStateOffline = true;
  596. #else
  597. g_EngineSteamPS3Params.m_bPersonaStateOffline = false;
  598. #endif
  599. }
  600. #endif
  601. // Needs to be done prior to init material system config
  602. TRACEINIT( COM_InitFilesystem( m_StartupInfo.m_pInitialMod ), COM_ShutdownFileSystem() );
  603. //
  604. // VPK content-shadowing overrides
  605. // See below:
  606. // CDedicatedServerAPI::ModInit
  607. // to ensure that dedicated servers also mount the VPKs to check clients CRCs
  608. //
  609. // This is the client initializing, if we are running in lowviolence mode then inject the lowviolence VPK at the head of search path
  610. if ( CommandLine()->FindParm( "-pakxv_lowviolence" ) )
  611. {
  612. g_pFullFileSystem->AddSearchPath( "lowviolence", "COMPAT:GAME", PATH_ADD_TO_HEAD );
  613. }
  614. if ( CommandLine()->FindParm( "-perfectworld" ) )
  615. {
  616. g_pFullFileSystem->AddSearchPath( "perfectworld", "COMPAT:GAME", PATH_ADD_TO_HEAD );
  617. }
  618. // Enable file tracking - client always does this in case it connects to a pure server.
  619. // server only does this if sv_pure is set
  620. if ( IsPC() )
  621. {
  622. KeyValues *modinfo = new KeyValues("ModInfo");
  623. if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) )
  624. {
  625. // If it's not singleplayer_only
  626. if ( V_stricmp( modinfo->GetString("type", "singleplayer_only"), "singleplayer_only") == 0 )
  627. {
  628. DevMsg( "Disabling whitelist file tracking in filesystem...\n" );
  629. g_pFileSystem->EnableWhitelistFileTracking( false, false, false );
  630. }
  631. else
  632. {
  633. DevMsg( "Enabling whitelist file tracking in filesystem...\n" );
  634. g_pFileSystem->EnableWhitelistFileTracking( true, false, false );
  635. }
  636. }
  637. modinfo->deleteThis();
  638. }
  639. //
  640. // Configure breakpad
  641. //
  642. // Parse AppID from steam.inf file
  643. extern void Sys_Version( bool bDedicated );
  644. Sys_Version( false );
  645. #if !defined( NO_STEAM ) && !defined( _GAMECONSOLE )
  646. if ( !CommandLine()->FindParm( "-nobreakpad" ) )
  647. {
  648. // AppID of the client will be automatically used
  649. extern int32 GetHostVersion();
  650. extern int32 GetClientVersion();
  651. CFmtStr fmtClientVersion( "%d.%d", GetHostVersion(), GetClientVersion() );
  652. Msg( "Using breakpad minidump system %u/%s\n", g_unSteamAppID, fmtClientVersion.Access() );
  653. SteamAPI_UseBreakpadCrashHandler( fmtClientVersion.Access(), __DATE__, __TIME__, WantsFullMemoryDumps(), NULL, NULL );
  654. }
  655. #endif // !NO_STEAM && !_GAMECONSOLE
  656. // turn on the Steam3 API early so we can query app data up front
  657. #if !defined( DEDICATED ) && !defined( NO_STEAM )
  658. TRACEINIT( Steam3Client().Activate(), Steam3Client().Shutdown() );
  659. if ( IsPS3() )
  660. {
  661. #if !defined( CSTRIKE15 )
  662. // TODO: PS3_BUILDFIX: We probably want to turn this back on after we get the steam client working for CStrike15
  663. // this is only relevant for PS3
  664. if ( !Steam3Client().IsInitialized() )
  665. {
  666. return false;
  667. }
  668. #endif // CSTRIKE15
  669. }
  670. if ( !Steam3Client().IsInitialized() || !Steam3Client().SteamUser() ||
  671. !Steam3Client().SteamUser()->GetSteamID().IsValid() || !Steam3Client().SteamUser()->GetSteamID().BIndividualAccount() || !Steam3Client().SteamUser()->GetSteamID().GetAccountID() )
  672. {
  673. Error( "FATAL ERROR: Failed to connect with local Steam Client process!\n\nPlease make sure that you are running latest version of Steam Client.\nYou can check for Steam Client updates using Steam main menu:\n Steam > Check for Steam Client Updates..." );
  674. return false;
  675. }
  676. //
  677. // Setup a search path for USRLOCAL data (configs / save games / etc.) that isn't intended to be shared across multiple accounts
  678. //
  679. if ( g_pFileSystem )
  680. {
  681. char chUserLocalDataFolder[ MAX_PATH ] = {};
  682. if ( char const * pszLocalOverride = getenv( "USRLOCAL" DLLExtTokenPaste2( VPCGAMECAPS ) ) )
  683. {
  684. Msg( "USRLOCAL path using environment setting '%s':\n%s\n", "USRLOCAL" DLLExtTokenPaste2( VPCGAMECAPS ), pszLocalOverride );
  685. g_pFileSystem->AddSearchPath( pszLocalOverride, "USRLOCAL" );
  686. }
  687. else if ( Steam3Client().SteamUser()->GetUserDataFolder( chUserLocalDataFolder, sizeof( chUserLocalDataFolder ) ) )
  688. {
  689. Msg( "USRLOCAL path using Steam profile data folder:\n%s\n", chUserLocalDataFolder );
  690. g_pFileSystem->AddSearchPath( chUserLocalDataFolder, "USRLOCAL" );
  691. }
  692. else
  693. {
  694. Warning( "USRLOCAL path not found!\n" );
  695. }
  696. }
  697. #endif
  698. return true;
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Init, shutdown
  702. //-----------------------------------------------------------------------------
  703. InitReturnVal_t CEngineAPI::Init()
  704. {
  705. if ( CommandLine()->FindParm( "-sv_benchmark" ) != 0 )
  706. {
  707. Plat_SetBenchmarkMode( true );
  708. }
  709. InitReturnVal_t nRetVal = BaseClass::Init();
  710. if ( nRetVal != INIT_OK )
  711. return nRetVal;
  712. m_bRunningSimulation = false;
  713. // Initialize the FPU control word
  714. #if !defined( DEDICATED ) && !defined( _X360 ) && !defined( _PS3 ) && !defined( PLATFORM_64BITS ) && !defined( LINUX ) && !defined(__clang__)
  715. _asm
  716. {
  717. fninit
  718. }
  719. #endif
  720. SetupFPUControlWord();
  721. // This creates the videomode singleton object, it doesn't depend on the registry
  722. VideoMode_Create();
  723. // Initialize the editor hwnd to render into
  724. m_hEditorHWnd = NULL;
  725. // One-time setup
  726. // FIXME: OnStartup + OnShutdown should be removed + moved into the launcher
  727. // or the launcher code should be merged into the engine into the code in OnStartup/OnShutdown
  728. if ( !OnStartup( m_StartupInfo.m_pInstance, m_StartupInfo.m_pInitialMod ) )
  729. {
  730. return HandleSetModeError();
  731. }
  732. #if defined( POSIX ) && !defined( _PS3 )
  733. // on OSX by the time we've initialized cl_language we've already initialized the
  734. // font manager and made a bunch of language-related decisions.
  735. // on windows, the code sniffs the registry directly (slightly evil) and doesn't have
  736. // this problem.
  737. if ( Steam3Client().SteamApps() )
  738. {
  739. extern ConVar cl_language;
  740. cl_language.SetValue( Steam3Client().SteamApps()->GetCurrentGameLanguage() );
  741. }
  742. #endif
  743. return INIT_OK;
  744. }
  745. void CEngineAPI::Shutdown()
  746. {
  747. VideoMode_Destroy();
  748. BaseClass::Shutdown();
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Sets the engine to run in a particular editor window
  752. //-----------------------------------------------------------------------------
  753. void CEngineAPI::SetEngineWindow( void *hWnd )
  754. {
  755. if ( !InEditMode() )
  756. return;
  757. // Detach input from the previous editor window
  758. game->InputDetachFromGameWindow();
  759. m_hEditorHWnd = hWnd;
  760. videomode->SetGameWindow( m_hEditorHWnd );
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Posts a console command
  764. //-----------------------------------------------------------------------------
  765. void CEngineAPI::PostConsoleCommand( const char *pCommand )
  766. {
  767. Assert( 0 ); // This isn't being used, but I'm assuming it would be for a dedicated server type console, so issueing the command into the server's buffer may make sense.
  768. Cbuf_AddText( CBUF_SERVER, pCommand );
  769. }
  770. //-----------------------------------------------------------------------------
  771. // Is the engine currently rinning?
  772. //-----------------------------------------------------------------------------
  773. bool CEngineAPI::IsRunningSimulation() const
  774. {
  775. return (eng->GetState() == IEngine::DLL_ACTIVE);
  776. }
  777. //-----------------------------------------------------------------------------
  778. // Reset the map we're on
  779. //-----------------------------------------------------------------------------
  780. void CEngineAPI::SetMap( const char *pMapName )
  781. {
  782. // if ( !Q_stricmp( sv.mapname, pMapName ) )
  783. // return;
  784. char buf[MAX_PATH];
  785. Q_snprintf( buf, MAX_PATH, "map %s", pMapName );
  786. Cbuf_AddText( Cbuf_GetCurrentPlayer(), buf );
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Start/stop running the simulation
  790. //-----------------------------------------------------------------------------
  791. void CEngineAPI::ActivateSimulation( bool bActive )
  792. {
  793. // FIXME: Not sure what will happen in this case
  794. if ( ( eng->GetState() != IEngine::DLL_ACTIVE ) &&
  795. ( eng->GetState() != IEngine::DLL_PAUSED ) )
  796. {
  797. return;
  798. }
  799. bool bCurrentlyActive = (eng->GetState() != IEngine::DLL_PAUSED);
  800. if ( bActive == bCurrentlyActive )
  801. return;
  802. // FIXME: Should attachment/detachment be part of the state machine in IEngine?
  803. if ( !bActive )
  804. {
  805. eng->SetNextState( IEngine::DLL_PAUSED );
  806. // Detach input from the previous editor window
  807. game->InputDetachFromGameWindow();
  808. }
  809. else
  810. {
  811. eng->SetNextState( IEngine::DLL_ACTIVE );
  812. // Start accepting input from the new window
  813. // FIXME: What if the attachment fails?
  814. game->InputAttachToGameWindow();
  815. }
  816. }
  817. //-----------------------------------------------------------------------------
  818. // Purpose: Message pump when running stand-alone
  819. //-----------------------------------------------------------------------------
  820. void CEngineAPI::PumpMessages()
  821. {
  822. #if defined( WIN32 ) && !defined( USE_SDL )
  823. MSG msg;
  824. while ( PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE ) )
  825. {
  826. #if defined( INCLUDE_SCALEFORM )
  827. if ( g_pScaleformUI )
  828. {
  829. // Scaleform IME requirement. Pass these messages to GFxIME BEFORE any TranlsateMessage/DispatchMessage.
  830. if ( (msg.message == WM_KEYDOWN) || (msg.message == WM_KEYUP) || ImmIsUIMessage( NULL, msg.message, msg.wParam, msg.lParam )
  831. || (msg.message == WM_LBUTTONDOWN) || (msg.message == WM_LBUTTONUP) )
  832. {
  833. g_pScaleformUI->PreProcessKeyboardEvent( (size_t)msg.hwnd, msg.message, msg.wParam, msg.lParam );
  834. }
  835. }
  836. #endif
  837. TranslateMessage( &msg );
  838. DispatchMessageW( &msg );
  839. }
  840. #elif defined( OSX ) || defined( USE_SDL )
  841. g_pLauncherMgr->PumpWindowsMessageLoop();
  842. #else
  843. #error
  844. #endif
  845. // Get input from attached devices
  846. g_pInputSystem->PollInputState( GetBaseLocalClient().IsActive() );
  847. // NOTE: Under some implementations of Win9x,
  848. // dispatching messages can cause the FPU control word to change
  849. if ( IsPC() )
  850. {
  851. SetupFPUControlWord();
  852. }
  853. game->DispatchAllStoredGameMessages();
  854. if ( IsPC() )
  855. {
  856. EatTextModeKeyPresses();
  857. }
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose: Message pump when running stand-alone
  861. //-----------------------------------------------------------------------------
  862. void CEngineAPI::PumpMessagesEditMode( bool &bIdle, long &lIdleCount )
  863. {
  864. if ( bIdle && !g_pHammer->HammerOnIdle( lIdleCount++ ) )
  865. {
  866. bIdle = false;
  867. }
  868. #ifdef WIN32
  869. MSG msg;
  870. while ( PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) )
  871. {
  872. if ( msg.message == WM_QUIT )
  873. {
  874. eng->SetQuitting( IEngine::QUIT_TODESKTOP );
  875. break;
  876. }
  877. if ( msg.hwnd == (HWND)game->GetMainWindow() )
  878. {
  879. TranslateMessage(&msg);
  880. DispatchMessageW(&msg);
  881. }
  882. else
  883. {
  884. if ( !g_pHammer->HammerPreTranslateMessage(&msg) )
  885. {
  886. TranslateMessage(&msg);
  887. DispatchMessageW(&msg);
  888. }
  889. }
  890. // Reset idle state after pumping idle message.
  891. if ( g_pHammer->HammerIsIdleMessage(&msg) )
  892. {
  893. bIdle = true;
  894. lIdleCount = 0;
  895. }
  896. }
  897. #elif defined( OSX ) && defined( PLATFORM_64BITS )
  898. // Do nothing, but let someone know we're doing nothing.
  899. Assert( !"OSX-64 not implemented." );
  900. #elif defined( OSX )
  901. EventRef theEvent;
  902. EventTargetRef theTarget;
  903. EventTime eventTimeout = kEventDurationNoWait;
  904. theTarget = GetEventDispatcherTarget();
  905. while ( ReceiveNextEvent( 0, NULL, eventTimeout, true, &theEvent ) == noErr)
  906. {
  907. OSErr ret = SendEventToEventTarget (theEvent, theTarget);
  908. if ( ret != noErr )
  909. {
  910. EventRecord clevent;
  911. ConvertEventRefToEventRecord( theEvent, &clevent);
  912. if ( clevent.what==kHighLevelEvent )
  913. {
  914. AEProcessAppleEvent( &clevent );
  915. }
  916. }
  917. ReleaseEvent(theEvent);
  918. }
  919. #elif defined( _PS3 )
  920. #elif defined( LINUX )
  921. #else
  922. #error
  923. #endif
  924. // NOTE: Under some implementations of Win9x,
  925. // dispatching messages can cause the FPU control word to change
  926. SetupFPUControlWord();
  927. game->DispatchAllStoredGameMessages();
  928. }
  929. //-----------------------------------------------------------------------------
  930. // Activate/deactivates edit mode shaders
  931. //-----------------------------------------------------------------------------
  932. void CEngineAPI::ActivateEditModeShaders( bool bActive )
  933. {
  934. if ( InEditMode() && ( g_pMaterialSystemConfig->bEditMode != bActive ) )
  935. {
  936. MaterialSystem_Config_t config = *g_pMaterialSystemConfig;
  937. config.bEditMode = bActive;
  938. OverrideMaterialSystemConfig( config );
  939. }
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Purpose: Message pump
  943. //-----------------------------------------------------------------------------
  944. bool CEngineAPI::MainLoop()
  945. {
  946. bool bIdle = true;
  947. long lIdleCount = 0;
  948. // Main message pump
  949. while ( true )
  950. {
  951. // Pump messages unless someone wants to quit
  952. if ( eng->GetQuitting() != IEngine::QUIT_NOTQUITTING )
  953. {
  954. if ( eng->GetQuitting() != IEngine::QUIT_TODESKTOP )
  955. return true;
  956. return false;
  957. }
  958. // Pump the message loop
  959. if ( !InEditMode() )
  960. {
  961. PumpMessages();
  962. }
  963. else
  964. {
  965. PumpMessagesEditMode( bIdle, lIdleCount );
  966. }
  967. // Deactivate edit mode shaders
  968. ActivateEditModeShaders( false );
  969. eng->Frame();
  970. // Reactivate edit mode shaders (in Edit mode only...)
  971. ActivateEditModeShaders( true );
  972. if ( InEditMode() )
  973. {
  974. g_pHammer->RunFrame();
  975. }
  976. }
  977. return false;
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Initializes, shuts down the registry
  981. //-----------------------------------------------------------------------------
  982. bool CEngineAPI::InitRegistry( const char *pModName )
  983. {
  984. if ( IsPC() )
  985. {
  986. char szRegSubPath[MAX_PATH];
  987. Q_snprintf( szRegSubPath, sizeof(szRegSubPath), "%s\\%s", "Source", pModName );
  988. return registry->Init( szRegSubPath );
  989. }
  990. return true;
  991. }
  992. void CEngineAPI::ShutdownRegistry( )
  993. {
  994. if ( IsPC() )
  995. {
  996. registry->Shutdown( );
  997. }
  998. }
  999. #if defined( _PS3 )
  1000. int PS3_WindowProc_Proxy( xevent_t const &ev );
  1001. #endif
  1002. //-----------------------------------------------------------------------------
  1003. // One-time setup, based on the initially selected mod
  1004. // FIXME: This should move into the launcher!
  1005. //-----------------------------------------------------------------------------
  1006. bool CEngineAPI::OnStartup( void *pInstance, const char *pStartupModName )
  1007. {
  1008. // This fixes a bug on certain machines where the input will
  1009. // stop coming in for about 1 second when someone hits a key.
  1010. // (true means to disable priority boost)
  1011. #ifdef WIN32
  1012. if ( IsPC() )
  1013. {
  1014. SetThreadPriorityBoost( GetCurrentThread(), true );
  1015. }
  1016. #endif
  1017. // FIXME: Turn videomode + game into IAppSystems?
  1018. // Try to create the window
  1019. COM_TimestampedLog( "game->Init" );
  1020. splitscreen->Init();
  1021. // This has to happen before CreateGameWindow to set up the instance
  1022. // for use by the code that creates the window
  1023. if ( !game->Init( pInstance ) )
  1024. {
  1025. goto onStartupError;
  1026. }
  1027. // Try to create the window
  1028. COM_TimestampedLog( "videomode->Init" );
  1029. // This needs to be after Shader_Init and registry->Init
  1030. // This way mods can have different default video settings
  1031. if ( !videomode->Init( ) )
  1032. {
  1033. goto onStartupShutdownGame;
  1034. }
  1035. COM_TimestampedLog( "InitRegistry" );
  1036. // We need to access the registry to get various settings (specifically,
  1037. // InitMaterialSystemConfig requires it).
  1038. if ( !InitRegistry( pStartupModName ) )
  1039. {
  1040. goto onStartupShutdownVideoMode;
  1041. }
  1042. COM_TimestampedLog( "materials->ModInit" );
  1043. materials->ModInit();
  1044. COM_TimestampedLog( "InitMaterialSystemConfig" );
  1045. // Setup the material system config record, CreateGameWindow depends on it
  1046. // (when we're running stand-alone)
  1047. InitMaterialSystemConfig( InEditMode() );
  1048. {
  1049. #if defined( _X360 )
  1050. XBX_NotifyCreateListener( XNOTIFY_ALL );
  1051. #elif defined( _PS3 )
  1052. ps3syscbckeventhdlr_t hdlr = { PS3_WindowProc_Proxy };
  1053. XBX_NotifyCreateListener( reinterpret_cast< uint64 >( &hdlr ) );
  1054. #endif
  1055. }
  1056. COM_TimestampedLog( "ShutdownRegistry" );
  1057. ShutdownRegistry();
  1058. return true;
  1059. // Various error conditions
  1060. onStartupShutdownVideoMode:
  1061. videomode->Shutdown();
  1062. onStartupShutdownGame:
  1063. game->Shutdown();
  1064. onStartupError:
  1065. return false;
  1066. }
  1067. //-----------------------------------------------------------------------------
  1068. // One-time shutdown (shuts down stuff set up in OnStartup)
  1069. // FIXME: This should move into the launcher!
  1070. //-----------------------------------------------------------------------------
  1071. void CEngineAPI::OnShutdown()
  1072. {
  1073. if ( videomode )
  1074. {
  1075. videomode->Shutdown();
  1076. }
  1077. // Shut down the game
  1078. game->Shutdown();
  1079. materials->ModShutdown();
  1080. TRACESHUTDOWN( COM_ShutdownFileSystem() );
  1081. splitscreen->Shutdown();
  1082. #ifdef _PS3
  1083. XBX_NotifyCreateListener( 0 );
  1084. #endif
  1085. }
  1086. static bool IsValveMod( const char *pModName )
  1087. {
  1088. // Figure out if we're running a Valve mod or not.
  1089. return ( Q_stricmp( pModName, "cstrike" ) == 0 ||
  1090. Q_stricmp( pModName, "dod" ) == 0 ||
  1091. Q_stricmp( pModName, "hl1mp" ) == 0 ||
  1092. Q_stricmp( pModName, "tf" ) == 0 ||
  1093. Q_stricmp( pModName, "hl2mp" ) == 0 ||
  1094. Q_stricmp( pModName, "csgo" ) == 0 );
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Initialization, shutdown of a mod.
  1098. //-----------------------------------------------------------------------------
  1099. bool CEngineAPI::ModInit( const char *pModName, const char *pGameDir )
  1100. {
  1101. COM_TimestampedLog( "ModInit" );
  1102. // Set up the engineparms_t which contains global information about the mod
  1103. host_parms.mod = COM_StringCopy( GetModDirFromPath( pModName ) );
  1104. host_parms.game = COM_StringCopy( pGameDir );
  1105. // By default, restrict server commands in Valve games and don't restrict them in mods.
  1106. bool bRestrictCommands = IsValveMod( host_parms.mod );
  1107. GetBaseLocalClient().m_bRestrictServerCommands = bRestrictCommands;
  1108. GetBaseLocalClient().m_bRestrictClientCommands = bRestrictCommands;
  1109. // build the registry path we're going to use for this mod
  1110. InitRegistry( pModName );
  1111. // This sets up the game search path, depends on host_parms
  1112. TRACEINIT( MapReslistGenerator_Init(), MapReslistGenerator_Shutdown() );
  1113. #if !defined( _X360 )
  1114. TRACEINIT( DevShotGenerator_Init(), DevShotGenerator_Shutdown() );
  1115. #endif
  1116. COM_TimestampedLog( "Host_ReadPreStartupConfiguration - Start" );
  1117. // Slam cvars based on mod/config.cfg
  1118. Host_ReadPreStartupConfiguration();
  1119. COM_TimestampedLog( "Host_ReadPreStartupConfiguration - Finish" );
  1120. // Create the game window now that we have a search path
  1121. // FIXME: Deal with initial window width + height better
  1122. if ( !videomode || !videomode->CreateGameWindow( g_pMaterialSystemConfig->m_VideoMode.m_Width, g_pMaterialSystemConfig->m_VideoMode.m_Height, g_pMaterialSystemConfig->Windowed(), g_pMaterialSystemConfig->NoWindowBorder() ) )
  1123. {
  1124. return false;
  1125. }
  1126. return true;
  1127. }
  1128. void CEngineAPI::ModShutdown()
  1129. {
  1130. COM_StringFree(host_parms.mod);
  1131. COM_StringFree(host_parms.game);
  1132. // Stop accepting input from the window
  1133. game->InputDetachFromGameWindow();
  1134. #if !defined( _X360 )
  1135. TRACESHUTDOWN( DevShotGenerator_Shutdown() );
  1136. #endif
  1137. TRACESHUTDOWN( MapReslistGenerator_Shutdown() );
  1138. ShutdownRegistry();
  1139. }
  1140. //-----------------------------------------------------------------------------
  1141. // Purpose: Handles there being an error setting up the video mode
  1142. // Output : Returns true on if the engine should restart, false if it should quit
  1143. //-----------------------------------------------------------------------------
  1144. InitReturnVal_t CEngineAPI::HandleSetModeError()
  1145. {
  1146. // show an error, see if the user wants to restart
  1147. if ( CommandLine()->FindParm( "-safe" ) )
  1148. {
  1149. Sys_MessageBox( "Failed to set video mode.\n\nThis game has a minimum requirement of DirectX 7.0 compatible hardware.\n", "Video mode error", false );
  1150. return INIT_FAILED;
  1151. }
  1152. if ( CommandLine()->FindParm( "-autoconfig" ) )
  1153. {
  1154. if ( Sys_MessageBox( "Failed to set video mode - falling back to safe mode settings.\n\nGame will now restart with the new video settings.", "Video - safe mode fallback", true ))
  1155. {
  1156. CommandLine()->AppendParm( "-safe", NULL );
  1157. return (InitReturnVal_t)INIT_RESTART;
  1158. }
  1159. return INIT_FAILED;
  1160. }
  1161. if ( Sys_MessageBox( "Failed to set video mode - resetting to defaults.\n\nGame will now restart with the new video settings.", "Video mode warning", true ) )
  1162. {
  1163. CommandLine()->AppendParm( "-autoconfig", NULL );
  1164. return (InitReturnVal_t)INIT_RESTART;
  1165. }
  1166. return INIT_FAILED;
  1167. }
  1168. //-----------------------------------------------------------------------------
  1169. // Purpose: Main loop for non-dedicated servers
  1170. //-----------------------------------------------------------------------------
  1171. int CEngineAPI::RunListenServer()
  1172. {
  1173. //
  1174. // NOTE: Systems set up here should depend on the mod
  1175. // Systems which are mod-independent should be set up in the launcher or Init()
  1176. //
  1177. // Innocent until proven guilty
  1178. int nRunResult = RUN_OK;
  1179. // Happens every time we start up and shut down a mod
  1180. if ( ModInit( m_StartupInfo.m_pInitialMod, m_StartupInfo.m_pInitialGame ) )
  1181. {
  1182. CModAppSystemGroup modAppSystemGroup( false, m_StartupInfo.m_pParentAppSystemGroup );
  1183. #ifdef USE_HACKY_MATERIAL_SYSTEM_TEST
  1184. RunMaterialSystemTest();
  1185. #endif
  1186. // Store off the app system factory...
  1187. g_AppSystemFactory = modAppSystemGroup.GetFactory();
  1188. nRunResult = modAppSystemGroup.Run();
  1189. g_AppSystemFactory = NULL;
  1190. // Shuts down the mod
  1191. ModShutdown();
  1192. // Disconnects from the editor window
  1193. videomode->SetGameWindow( NULL );
  1194. }
  1195. // Closes down things that were set up in OnStartup
  1196. // FIXME: OnStartup + OnShutdown should be removed + moved into the launcher
  1197. // or the launcher code should be merged into the engine into the code in OnStartup/OnShutdown
  1198. OnShutdown();
  1199. return nRunResult;
  1200. }
  1201. #if 0
  1202. CON_COMMAND( bigalloc, "huge alloc crash" )
  1203. {
  1204. Msg( "pre-crash %d\n", g_pMemAlloc->MemoryAllocFailed() );
  1205. void *buf = malloc( UINT_MAX );
  1206. Msg( "post-alloc %d\n", g_pMemAlloc->MemoryAllocFailed() );
  1207. *(int *)buf = 0;
  1208. }
  1209. #endif
  1210. #if defined( _PS3 ) && !defined(NO_STEAM) && !defined(_CERT)
  1211. CON_COMMAND_F( steam_login_new_acct, "logs in and creates a new account if necessary", FCVAR_DEVELOPMENTONLY )
  1212. {
  1213. Steam3Client().SteamUser()->LogOnAndCreateNewSteamAccountIfNeeded( false );
  1214. }
  1215. CON_COMMAND_F( steam_login_link_acct, "<username> <password>", FCVAR_DEVELOPMENTONLY )
  1216. {
  1217. if ( args.ArgC() != 3 )
  1218. return;
  1219. Steam3Client().SteamUser()->LogOnAndLinkSteamAccountToPSN( false, args[1], args[2] );
  1220. }
  1221. CON_COMMAND_F( steam_login, "log into steam with an already linked account", FCVAR_DEVELOPMENTONLY )
  1222. {
  1223. Steam3Client().SteamUser()->LogOn( false );
  1224. }
  1225. #endif
  1226. CON_COMMAND( reload_vjobs, "reload vjobs module" )
  1227. {
  1228. const char * pModuleName = "vjobs" DLL_EXT_STRING;
  1229. extern CAppSystemGroup *s_pCurrentAppSystem;
  1230. if( g_pVJobs )
  1231. {
  1232. MaterialLock_t matlock = materials->Lock();
  1233. g_pVJobs->BeforeReload();
  1234. s_pCurrentAppSystem->ReloadModule( pModuleName );
  1235. g_pVJobs->AfterReload();
  1236. materials->Unlock( matlock );
  1237. }
  1238. else
  1239. {
  1240. Warning("vjobs interface not connected\n");
  1241. }
  1242. }
  1243. CON_COMMAND( render_blanks, "render N blank frames" )
  1244. {
  1245. uint nFrames = 0;
  1246. if( *args[1] )
  1247. nFrames = atoi( args[1] );
  1248. if( !nFrames || nFrames > 1000 )
  1249. {
  1250. nFrames = 10;
  1251. Msg("Clamping to %d frames", nFrames );
  1252. }
  1253. MaterialLock_t matlock = materials->Lock();
  1254. materials->SpinPresent( nFrames );
  1255. materials->Unlock( matlock );
  1256. }
  1257. extern void S_ClearBuffer();
  1258. #endif // #ifndef DEDICATED
  1259. extern bool g_bUpdateMinidumpComment;
  1260. void GetSpew( char *buf, size_t buflen );
  1261. #if defined( _X360 )
  1262. #define DUMP_COMMENT_SIZE 3500
  1263. #else
  1264. // should not exceed 32K, since current breakpad minidump reading code limits total comment size to 32k.
  1265. #define DUMP_COMMENT_SIZE 32768
  1266. #endif
  1267. // Turn this to 1 to allow for > 3kb of comments in dumps
  1268. static ConVar sys_minidumpexpandedspew( "sys_minidumpexpandedspew", "0" );
  1269. extern "C" void __cdecl FailSafe( unsigned int uStructuredExceptionCode, struct _EXCEPTION_POINTERS * pExceptionInfo )
  1270. {
  1271. // Nothing, this just catches a crash when creating the comment block
  1272. }
  1273. class CErrorText
  1274. {
  1275. public:
  1276. explicit CErrorText( int size ) :
  1277. m_Size( size ),
  1278. m_errorText( new char[ size ] )
  1279. {
  1280. Q_memset( m_errorText, 0x00, m_Size );
  1281. }
  1282. ~CErrorText()
  1283. {
  1284. delete[] m_errorText;
  1285. }
  1286. void BuildComment( char const *pchSysErrorText )
  1287. {
  1288. #if !defined( _PS3 )
  1289. #ifdef IS_WINDOWS_PC
  1290. // This warning is not actually true in this context.
  1291. #pragma warning( suppress : 4535 ) // warning C4535: calling _set_se_translator() requires /EHa
  1292. _se_translator_function curfilter = _set_se_translator( &FailSafe );
  1293. #endif
  1294. try
  1295. {
  1296. int nSize = m_Size;
  1297. nSize = MIN( nSize, DUMP_COMMENT_SIZE );
  1298. Q_memset( m_errorText, 0x00, nSize );
  1299. if ( pchSysErrorText )
  1300. {
  1301. // Strip trailing return character (note this overwrites the return character built into the string)
  1302. char *pchFixup = (char *)pchSysErrorText;
  1303. int lenFixed = Q_strlen( pchFixup );
  1304. if ( pchFixup[ lenFixed - 1 ] == '\n' )
  1305. {
  1306. pchFixup[ lenFixed - 1 ] = 0;
  1307. }
  1308. V_snprintf( m_errorText, nSize, "\nSys_Error( %s )\n", pchFixup );
  1309. }
  1310. else
  1311. {
  1312. V_snprintf( m_errorText, nSize, "\nCrash\n" );
  1313. }
  1314. V_strncat( m_errorText, Status_GetBuffer(), nSize );
  1315. // Latch in case below stuff crashes
  1316. #if !defined( NO_STEAM )
  1317. SteamAPI_SetMiniDumpComment( m_errorText );
  1318. #endif
  1319. bool bExtendedSpew = sys_minidumpexpandedspew.GetBool();
  1320. if ( bExtendedSpew )
  1321. {
  1322. try
  1323. {
  1324. V_strncat( m_errorText, "\nConVars (non-default)\n\n", nSize );
  1325. char header[ 128 ];
  1326. V_snprintf( header, sizeof( header ), "%25.25s %25.25s %25.25s\n", "var", "value", "default" );
  1327. V_strncat( m_errorText, header, nSize );
  1328. int len = V_strlen( m_errorText );
  1329. if ( len < nSize )
  1330. {
  1331. int remainder = nSize - len;
  1332. char *pbuf = m_errorText + len;
  1333. ICvar::Iterator iter( g_pCVar );
  1334. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  1335. {
  1336. ConCommandBase *var = iter.Get();
  1337. if ( var->IsCommand() )
  1338. continue;
  1339. const ConVar *cvar = ( const ConVar * )var;
  1340. if ( cvar->GetFlags() & ( FCVAR_SERVER_CANNOT_QUERY | FCVAR_PROTECTED ) )
  1341. continue;
  1342. if ( !( cvar->GetFlags() & FCVAR_NEVER_AS_STRING ) )
  1343. {
  1344. char var1[ MAX_OSPATH ];
  1345. char var2[ MAX_OSPATH ];
  1346. Q_strncpy( var1, Host_CleanupConVarStringValue( cvar->GetString() ), sizeof( var1 ) );
  1347. Q_strncpy( var2, Host_CleanupConVarStringValue( cvar->GetDefault() ), sizeof( var2 ) );
  1348. if ( !Q_stricmp( var1, var2 ) )
  1349. continue;
  1350. }
  1351. else
  1352. {
  1353. if ( cvar->GetFloat() == Q_atof( cvar->GetDefault() ) )
  1354. continue;
  1355. }
  1356. char cvarcmd[ MAX_OSPATH ];
  1357. int add = 0;
  1358. if ( !( cvar->GetFlags() & FCVAR_NEVER_AS_STRING ) )
  1359. {
  1360. add = Q_snprintf( cvarcmd, sizeof(cvarcmd),"%25.25s %25.25s %25.25s\n",
  1361. cvar->GetName(), Host_CleanupConVarStringValue( cvar->GetString() ), cvar->GetDefault() );
  1362. }
  1363. else
  1364. {
  1365. add = Q_snprintf( cvarcmd, sizeof(cvarcmd),"%25.25s %25.25f %25.25f\n",
  1366. cvar->GetName(), cvar->GetFloat(), Q_atof( cvar->GetDefault() ) );
  1367. }
  1368. int toCopy = MIN( add, remainder );
  1369. if ( toCopy <= 0 )
  1370. break;
  1371. Q_memcpy( pbuf, cvarcmd, toCopy );
  1372. pbuf += toCopy;
  1373. remainder -= toCopy;
  1374. if ( remainder <= 0 )
  1375. break;
  1376. }
  1377. *pbuf = 0;
  1378. }
  1379. V_strncat( m_errorText, "\nConsole History (reversed)\n\n", nSize );
  1380. // Get console
  1381. len = V_strlen( m_errorText );
  1382. if ( len < nSize )
  1383. {
  1384. GetSpew( m_errorText + len, nSize - len );
  1385. }
  1386. }
  1387. catch ( ... )
  1388. {
  1389. Q_strncat( m_errorText, "exception thrown building console/convar history!!!\n", nSize );
  1390. }
  1391. #if !defined( NO_STEAM )
  1392. SteamAPI_SetMiniDumpComment( m_errorText );
  1393. #endif
  1394. }
  1395. }
  1396. catch ( ... )
  1397. {
  1398. // Oh oh
  1399. }
  1400. #ifdef IS_WINDOWS_PC
  1401. _set_se_translator( curfilter );
  1402. #endif
  1403. #endif
  1404. }
  1405. public:
  1406. int m_Size;
  1407. char *m_errorText;
  1408. };
  1409. static CErrorText errorText( DUMP_COMMENT_SIZE );
  1410. void BuildMinidumpComment( char const *pchSysErrorText )
  1411. {
  1412. errorText.BuildComment( pchSysErrorText );
  1413. }
  1414. #ifndef DEDICATED
  1415. extern "C" void __cdecl WriteMiniDumpUsingExceptionInfo( unsigned int uStructuredExceptionCode, struct _EXCEPTION_POINTERS * pExceptionInfo )
  1416. {
  1417. // TODO: dynamically set the minidump comment from contextual info about the crash (i.e current VPROF node)?
  1418. #if !defined( NO_STEAM ) && !defined( _PS3 )
  1419. if ( g_bUpdateMinidumpComment )
  1420. {
  1421. Status_Update();
  1422. BuildMinidumpComment( NULL );
  1423. }
  1424. SteamAPI_WriteMiniDump( uStructuredExceptionCode, pExceptionInfo, build_number() );
  1425. // Clear DSound Buffers so the sound doesn't loop while the game shuts down
  1426. // try
  1427. // {
  1428. // S_ClearBuffer();
  1429. // }
  1430. // catch ( ... )
  1431. // {
  1432. // }
  1433. #endif
  1434. }
  1435. extern "C" void __cdecl WriteMiniDump( void );
  1436. //-----------------------------------------------------------------------------
  1437. // Purpose: Main
  1438. //-----------------------------------------------------------------------------
  1439. int CEngineAPI::Run()
  1440. {
  1441. if ( CommandLine()->FindParm("-insecure") )
  1442. {
  1443. extern void Host_DisallowSecureServers();
  1444. Host_DisallowSecureServers();
  1445. }
  1446. #ifdef _X360
  1447. return RunListenServer(); // don't handle exceptions on 360 (because if we do then minidumps won't work at all)
  1448. #elif defined ( _WIN32 )
  1449. if ( !Plat_IsInDebugSession() && !CommandLine()->FindParm( "-nominidumps") )
  1450. {
  1451. // This warning is not actually true in this context.
  1452. #pragma warning( suppress : 4535 ) // warning C4535: calling _set_se_translator() requires /EHa
  1453. _set_se_translator( WriteMiniDumpUsingExceptionInfo );
  1454. try // this try block allows the SE translator to work
  1455. {
  1456. return RunListenServer();
  1457. }
  1458. catch( ... )
  1459. {
  1460. #if defined(_WIN32) && !defined( _X360 )
  1461. // We don't want global destructors in our process OR in any DLL to get executed.
  1462. // _exit() avoids calling global destructors in our module, but not in other DLLs.
  1463. TerminateProcess( GetCurrentProcess(), 100 );
  1464. #else
  1465. _exit( 100 );
  1466. #endif
  1467. return RUN_OK;
  1468. }
  1469. }
  1470. else
  1471. {
  1472. return RunListenServer();
  1473. }
  1474. #elif defined( _PS3 )
  1475. return RunListenServer();
  1476. #else
  1477. Assert( !"Impl minidump handling on Posix" );
  1478. return RunListenServer();
  1479. #endif
  1480. }
  1481. #endif // DEDICATED
  1482. bool g_bUsingLegacyAppSystems = false;
  1483. bool CModAppSystemGroup::AddLegacySystems()
  1484. {
  1485. g_bUsingLegacyAppSystems = true;
  1486. AppSystemInfo_t appSystems[] =
  1487. {
  1488. { "soundemittersystem" DLL_EXT_STRING, SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
  1489. { "", "" } // Required to terminate the list
  1490. };
  1491. if ( !AddSystems( appSystems ) )
  1492. return false;
  1493. #if !defined( _LINUX ) && !defined( _GAMECONSOLE )
  1494. // if ( CommandLine()->FindParm( "-tools" ) )
  1495. {
  1496. AppModule_t toolFrameworkModule = LoadModule( "engine" DLL_EXT_STRING );
  1497. if ( !AddSystem( toolFrameworkModule, VTOOLFRAMEWORK_INTERFACE_VERSION ) )
  1498. return false;
  1499. }
  1500. #endif
  1501. return true;
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. static int VerToInt( const char *pszVersion )
  1505. {
  1506. char szOut[ 32 ];
  1507. const char *pIn = pszVersion;
  1508. char *pOut = szOut;
  1509. if ( !pszVersion || strlen( pszVersion ) > sizeof( szOut ) ) // double check we won't overflow the buffer
  1510. {
  1511. return 0;
  1512. }
  1513. while ( *pIn )
  1514. {
  1515. if ( *pIn != '.' )
  1516. {
  1517. *pOut++ = *pIn;
  1518. }
  1519. pIn++;
  1520. }
  1521. *pOut = '\0';
  1522. return atoi( szOut );
  1523. }
  1524. #define VERSION_KEY "PatchVersion="
  1525. #define CLIENT_VERSION_KEY "ClientVersion="
  1526. #define SERVER_VERSION_KEY "ServerVersion="
  1527. #define PRODUCT_KEY "ProductName="
  1528. #define APPID_KEY "AppID="
  1529. #define PRODUCT_STRING "valve"
  1530. #define VERSION_STRING "1.0.1.0"
  1531. #define FS_MAGIC_NUM_KEY "FSKey="
  1532. static CUtlString g_sVersionString;
  1533. static CUtlString g_sProductString;
  1534. static int32 sHostVersion;
  1535. static int32 sClientVersion;
  1536. static int32 sServerVersion;
  1537. //-----------------------------------------------------------------------------
  1538. const char *GetHostVersionString()
  1539. {
  1540. return g_sVersionString.String();
  1541. }
  1542. //-----------------------------------------------------------------------------
  1543. const char *GetHostProductString()
  1544. {
  1545. return g_sProductString.String();
  1546. }
  1547. int32 GetHostVersion()
  1548. {
  1549. return sHostVersion;
  1550. }
  1551. //-----------------------------------------------------------------------------
  1552. int32 GetClientVersion()
  1553. {
  1554. // if we are running from perforce, we report 0 as version so checking isn't enforced
  1555. if ( g_bRunningFromPerforce )
  1556. {
  1557. return 0;
  1558. }
  1559. return sClientVersion;
  1560. }
  1561. //-----------------------------------------------------------------------------
  1562. int32 GetServerVersion()
  1563. {
  1564. // if we are running from perforce, we report 0 as version so checking isn't enforced
  1565. if ( g_bRunningFromPerforce )
  1566. {
  1567. return 0;
  1568. }
  1569. return sServerVersion;
  1570. }
  1571. const char *Sys_GetVersionString()
  1572. {
  1573. return g_sVersionString.String();
  1574. }
  1575. const char *Sys_GetProductString()
  1576. {
  1577. return g_sProductString;
  1578. }
  1579. static bool ParseSteamInfFile( const char *szFileName, AppId_t &unSteamAppID )
  1580. {
  1581. char *buffer;
  1582. int bufsize = 0;
  1583. FileHandle_t fp = NULL;
  1584. const char *pbuf = NULL;
  1585. const int numKeysExpected = 5; // number of expected keys
  1586. int gotKeys = 0;
  1587. // Mod's steam.inf is first option, the the steam.inf in the game GCF.
  1588. fp = g_pFileSystem->Open( szFileName, "r" );
  1589. if ( fp )
  1590. {
  1591. bufsize = g_pFileSystem->Size( fp );
  1592. buffer = ( char * )stackalloc( bufsize + 1 );
  1593. Assert( buffer );
  1594. int iBytesRead = g_pFileSystem->Read( buffer, bufsize, fp );
  1595. g_pFileSystem->Close( fp );
  1596. buffer[iBytesRead] = '\0';
  1597. // Read
  1598. pbuf = buffer;
  1599. while ( 1 )
  1600. {
  1601. pbuf = COM_Parse( pbuf );
  1602. if ( !pbuf )
  1603. break;
  1604. if ( Q_strlen( com_token ) <= 0 )
  1605. break;
  1606. if ( !Q_strnicmp( com_token, VERSION_KEY, Q_strlen( VERSION_KEY ) ) )
  1607. {
  1608. char buf[ 256 ];
  1609. Q_strncpy( buf, com_token+Q_strlen( VERSION_KEY ), sizeof( buf ) - 1 );
  1610. buf[ sizeof( buf ) - 1 ] = '\0';
  1611. g_sVersionString = buf;
  1612. sHostVersion = VerToInt( buf );
  1613. gotKeys++;
  1614. continue;
  1615. }
  1616. if ( !Q_strnicmp( com_token, CLIENT_VERSION_KEY, Q_strlen( CLIENT_VERSION_KEY ) ) )
  1617. {
  1618. char buf[ 256 ];
  1619. Q_strncpy( buf, com_token+Q_strlen( CLIENT_VERSION_KEY ), sizeof( buf ) - 1 );
  1620. buf[ sizeof( buf ) - 1 ] = '\0';
  1621. sClientVersion = atoi( buf );
  1622. gotKeys++;
  1623. continue;
  1624. }
  1625. if ( !Q_strnicmp( com_token, SERVER_VERSION_KEY, Q_strlen( SERVER_VERSION_KEY ) ) )
  1626. {
  1627. char buf[ 256 ];
  1628. Q_strncpy( buf, com_token+Q_strlen( SERVER_VERSION_KEY ), sizeof( buf ) - 1 );
  1629. buf[ sizeof( buf ) - 1 ] = '\0';
  1630. sServerVersion = atoi( buf );
  1631. gotKeys++;
  1632. continue;
  1633. }
  1634. if ( !Q_strnicmp( com_token, PRODUCT_KEY, Q_strlen( PRODUCT_KEY ) ) )
  1635. {
  1636. char buf[ 256 ];
  1637. Q_strncpy( buf, com_token+Q_strlen( PRODUCT_KEY ), sizeof( buf ) - 1 );
  1638. buf[ sizeof( buf ) - 1 ] = '\0';
  1639. g_sProductString = buf;
  1640. gotKeys++;
  1641. continue;
  1642. }
  1643. // Steam reads the AppID out of steam_appid.txt
  1644. if ( !Q_strnicmp( com_token, APPID_KEY, Q_strlen( APPID_KEY ) ) )
  1645. {
  1646. char szAppID[32];
  1647. Q_strncpy( szAppID, com_token + Q_strlen( APPID_KEY ), sizeof( szAppID ) - 1 );
  1648. unSteamAppID = atoi(szAppID);
  1649. gotKeys++;
  1650. continue;
  1651. }
  1652. }
  1653. }
  1654. return gotKeys == numKeysExpected;
  1655. }
  1656. //-----------------------------------------------------------------------------
  1657. static bool ParsePerforceInfFile( const char *szFileName, uint64 &unFileSystemMagicNumber )
  1658. {
  1659. char *buffer;
  1660. int bufsize = 0;
  1661. FileHandle_t fp = NULL;
  1662. // Mod's steam.inf is first option, the the steam.inf in the game GCF.
  1663. fp = g_pFileSystem->Open( szFileName, "r" );
  1664. if ( fp )
  1665. {
  1666. bufsize = g_pFileSystem->Size( fp );
  1667. buffer = ( char * )_alloca( bufsize + 1 );
  1668. Assert( buffer );
  1669. int iBytesRead = g_pFileSystem->Read( buffer, bufsize, fp );
  1670. g_pFileSystem->Close( fp );
  1671. buffer[iBytesRead] = '\0';
  1672. // Read
  1673. const char *pbuf = buffer;
  1674. while ( 1 )
  1675. {
  1676. pbuf = COM_Parse( pbuf );
  1677. if ( !pbuf )
  1678. break;
  1679. if ( Q_strlen( com_token ) <= 0 )
  1680. break;
  1681. // Get the magic number that allows us to run without Steam internally. This magic number should only live in the Perforce.inf
  1682. // file which is never shipped.
  1683. if ( !Q_strnicmp( com_token, FS_MAGIC_NUM_KEY, Q_strlen( FS_MAGIC_NUM_KEY ) ) )
  1684. {
  1685. char szFSKey[64];
  1686. Q_strncpy( szFSKey, com_token + Q_strlen( FS_MAGIC_NUM_KEY ), sizeof( szFSKey ) - 1 );
  1687. unFileSystemMagicNumber = atoi(szFSKey);
  1688. return true;
  1689. }
  1690. }
  1691. }
  1692. return false;
  1693. }
  1694. void Sys_Version( bool bDedicated )
  1695. {
  1696. #if defined( _X360 )
  1697. // [Forrest] $FIXME Hack: The Xbox doesn't have a steam.inf file from which to load a patch version.
  1698. // However, if GetHostVersion doesn't match between the Xbox and the PC dedicated server then they can't connect.
  1699. // Perhaps the version checks should be removed when an Xbox is connected, but for now I'll just hard-code a matching version.
  1700. sHostVersion = 10040;
  1701. #endif
  1702. #if !defined( _X360 )
  1703. g_sVersionString = VERSION_STRING;
  1704. g_sProductString = PRODUCT_STRING;
  1705. uint64 unFSMagicNumber = 0;
  1706. if ( !ParseSteamInfFile( "steam.inf", g_unSteamAppID ) )
  1707. {
  1708. Sys_Error( "Unable to load version from steam.inf" );
  1709. }
  1710. // if we aren't launched by Steam try reading a local perforce inf file
  1711. // this lets us tell the internal staging/main builds to use the right app ids
  1712. // if we arent launched by steam - we havent resolved our universe yet so we dont know
  1713. // what it is - so check perforce.inf always for now
  1714. if ( !g_pFileSystem->IsSteam() )
  1715. ParsePerforceInfFile( "perforce.inf", unFSMagicNumber );
  1716. // If the magic number is found in the perforce.inf then we are running from Perforce
  1717. g_bRunningFromPerforce = ( unFSMagicNumber == 2190015756ull / 2 );
  1718. if ( g_unSteamAppID != k_uAppIdInvalid && ( !g_pFileSystem->IsSteam() || bDedicated || g_bRunningFromPerforce ) )
  1719. {
  1720. // steamclient.dll doesn't know about steam.inf files in mod folder,
  1721. // it excepts a steam_appid.txt in the root directory if the game is
  1722. // not started through Steam. So we create one there containing the
  1723. // current AppID
  1724. FILE *f = fopen( "steam_appid.txt", "wb" );
  1725. if ( f )
  1726. {
  1727. char rgchAppID[256];
  1728. Q_snprintf( rgchAppID, sizeof(rgchAppID), "%u\n", g_unSteamAppID );
  1729. fwrite( rgchAppID, Q_strlen(rgchAppID)+1, 1, f );
  1730. fclose( f );
  1731. }
  1732. }
  1733. #ifdef _WIN32
  1734. else
  1735. {
  1736. AssertMsg( !g_pFileSystem->FileExists( "perforce.inf" ), "<mod dir>\\perforce.inf included in a steam cache, remove it!" );
  1737. }
  1738. #endif // _WIN32
  1739. #endif
  1740. }
  1741. #ifdef ENGINE_MANAGES_VJOBS
  1742. void LoadVjobsModule()
  1743. {
  1744. Assert( !g_pVjobsDllModule );
  1745. g_pVjobsDllModule = g_pFileSystem->LoadModule( "vjobs" DLL_EXT_STRING, "EXECUTABLE_PATH", false );
  1746. if( !g_pVjobsDllModule )
  1747. {
  1748. Sys_Error( "Could not load vjobs library\n" );
  1749. }
  1750. g_pfnVjobsFactory = Sys_GetFactory( g_pVjobsDllModule );
  1751. if( !g_pfnVjobsFactory )
  1752. {
  1753. Sys_Error( "Could not get vjobs factory\n" );
  1754. }
  1755. IVJobs * pVJobs = ( IVJobs* )( *g_pfnVjobsFactory )( VJOBS_INTERFACE_VERSION, NULL );
  1756. Assert( g_pVJobs == pVJobs || !g_pVJobs );
  1757. g_pVJobs = pVJobs;
  1758. }
  1759. void ReloadDlls()
  1760. {
  1761. // if( g_bVjobsTest )
  1762. // {
  1763. // g_pVJobs->SetRunTarget( RUN_TARGET_SATELLITE_CPU );
  1764. // g_pVJobs->StartTest();
  1765. // g_pVJobs->SetRunTarget( RUN_TARGET_MAIN_CPU );
  1766. // g_pVJobs->StartTest();
  1767. // g_bVjobsTest = false;
  1768. // }
  1769. if( g_bVjobsReload )
  1770. {
  1771. g_bVjobsReload = false;
  1772. if( g_pVJobs )
  1773. {
  1774. g_pVJobs->BeforeReload();
  1775. }
  1776. if( g_pVjobsDllModule )
  1777. {
  1778. g_pFileSystem->UnloadModule( g_pVjobsDllModule );
  1779. g_pVjobsDllModule = NULL;
  1780. }
  1781. LoadVjobsModule();
  1782. if( g_pVJobs )
  1783. {
  1784. g_pVJobs->AfterReload();
  1785. }
  1786. }
  1787. }
  1788. #endif
  1789. //-----------------------------------------------------------------------------
  1790. // Instantiate all main libraries
  1791. //-----------------------------------------------------------------------------
  1792. bool CModAppSystemGroup::Create()
  1793. {
  1794. COM_TimestampedLog( "CModAppSystemGroup::Create() - Start" );
  1795. // If we're not running from Perforce check if we need to restart under Steam
  1796. if ( !g_bRunningFromPerforce && g_unSteamAppID != k_uAppIdInvalid && SteamAPI_RestartAppIfNecessary( g_unSteamAppID ) )
  1797. {
  1798. Plat_ExitProcess( EXIT_SUCCESS );
  1799. }
  1800. #ifdef ENGINE_MANAGES_VJOBS
  1801. //////////////////////////////////////////////////////////////////////////
  1802. //
  1803. // Vjobs
  1804. //
  1805. LoadVjobsModule();
  1806. AddSystem( g_pVJobs, VJOBS_INTERFACE_VERSION ); // this is done only once; g_pVJobs doesn't change even after multiple reloads of VJobs.prx
  1807. #endif
  1808. //////////////////////////////////////////////////////////////////////////
  1809. //
  1810. // Matchmaking
  1811. //
  1812. Assert ( !g_pMatchmakingDllModule );
  1813. // Check the signature on the client dll. If this fails we load it anyway but put this client
  1814. // into insecure mode so it won't connect to secure servers and get VAC banned
  1815. if ( !IsServerOnly() && !Host_AllowLoadModule( "matchmaking" DLL_EXT_STRING, "GAMEBIN", false ) )
  1816. {
  1817. // not supposed to load this but we will anyway
  1818. Host_DisallowSecureServers();
  1819. }
  1820. // loads the matchmaking.dll
  1821. g_pMatchmakingDllModule = g_pFileSystem->LoadModule(
  1822. IsServerOnly() ? ( "matchmaking_ds" DLL_EXT_STRING ) : ( "matchmaking" DLL_EXT_STRING ),
  1823. "GAMEBIN", false );
  1824. if ( g_pMatchmakingDllModule )
  1825. {
  1826. g_pfnMatchmakingFactory = Sys_GetFactory( g_pMatchmakingDllModule );
  1827. if ( g_pfnMatchmakingFactory )
  1828. {
  1829. g_pIfaceMatchFramework = ( IMatchFramework * ) g_pfnMatchmakingFactory( IMATCHFRAMEWORK_VERSION_STRING, NULL );
  1830. if ( !g_pIfaceMatchFramework )
  1831. {
  1832. if( IsPS3() )
  1833. return false;
  1834. else
  1835. Sys_Error( "Could not get matchmaking.dll interface from library matchmaking" );
  1836. }
  1837. // matchmaking.dll wasn't loaded by the time tier2 libraries were connecting,
  1838. // set it up in engine now
  1839. g_pMatchFramework = g_pIfaceMatchFramework;
  1840. }
  1841. else
  1842. {
  1843. if( IsPS3() )
  1844. return false;
  1845. else
  1846. Sys_Error( "Could not find factory interface in library matchmaking" );
  1847. }
  1848. }
  1849. else
  1850. {
  1851. // library failed to load
  1852. if( IsPS3() )
  1853. return false;
  1854. else
  1855. Sys_Error( "Could not load library matchmaking" );
  1856. }
  1857. AddSystem( g_pIfaceMatchFramework, IMATCHFRAMEWORK_VERSION_STRING );
  1858. Host_SubscribeForProfileEvents( true );
  1859. //////////////////////////////////////////////////////////////////////////
  1860. //
  1861. // Client/server
  1862. //
  1863. #ifndef DEDICATED
  1864. if ( !IsServerOnly() )
  1865. {
  1866. if ( !ClientDLL_Load() )
  1867. return false;
  1868. ClientDLL_Connect();
  1869. }
  1870. #endif
  1871. if ( !ServerDLL_Load( IsServerOnly() ) )
  1872. {
  1873. #ifndef DEDICATED
  1874. if ( !IsServerOnly() )
  1875. {
  1876. ClientDLL_Disconnect();
  1877. }
  1878. #endif
  1879. return false;
  1880. }
  1881. IClientDLLSharedAppSystems *clientSharedSystems = 0;
  1882. #ifndef DEDICATED
  1883. if ( !IsServerOnly() )
  1884. {
  1885. clientSharedSystems = ( IClientDLLSharedAppSystems * )g_ClientFactory( CLIENT_DLL_SHARED_APPSYSTEMS, NULL );
  1886. if ( !clientSharedSystems )
  1887. return AddLegacySystems();
  1888. }
  1889. #endif
  1890. IServerDLLSharedAppSystems *serverSharedSystems = ( IServerDLLSharedAppSystems * )g_ServerFactory( SERVER_DLL_SHARED_APPSYSTEMS, NULL );
  1891. if ( !serverSharedSystems )
  1892. {
  1893. Assert( !"Expected both game and client .dlls to have or not have shared app systems interfaces!!!" );
  1894. return AddLegacySystems();
  1895. }
  1896. // Load game and client .dlls and build list then
  1897. CUtlVector< AppSystemInfo_t > systems;
  1898. int i;
  1899. int serverCount = serverSharedSystems->Count();
  1900. for ( i = 0 ; i < serverCount; ++i )
  1901. {
  1902. const char *dllName = serverSharedSystems->GetDllName( i );
  1903. const char *interfaceName = serverSharedSystems->GetInterfaceName( i );
  1904. AppSystemInfo_t info;
  1905. info.m_pModuleName = dllName;
  1906. info.m_pInterfaceName = interfaceName;
  1907. systems.AddToTail( info );
  1908. }
  1909. if ( !IsServerOnly() )
  1910. {
  1911. int clientCount = clientSharedSystems->Count();
  1912. for ( i = 0 ; i < clientCount; ++i )
  1913. {
  1914. const char *dllName = clientSharedSystems->GetDllName( i );
  1915. const char *interfaceName = clientSharedSystems->GetInterfaceName( i );
  1916. if ( ModuleAlreadyInList( systems, dllName, interfaceName ) )
  1917. continue;
  1918. AppSystemInfo_t info;
  1919. info.m_pModuleName = dllName;
  1920. info.m_pInterfaceName = interfaceName;
  1921. systems.AddToTail( info );
  1922. }
  1923. }
  1924. AppSystemInfo_t info;
  1925. info.m_pModuleName = "";
  1926. info.m_pInterfaceName = "";
  1927. systems.AddToTail( info );
  1928. if ( !AddSystems( systems.Base() ) )
  1929. return false;
  1930. #if !defined( _LINUX ) && !defined( _GAMECONSOLE )
  1931. // if ( CommandLine()->FindParm( "-tools" ) )
  1932. {
  1933. AppModule_t toolFrameworkModule = LoadModule( "engine" DLL_EXT_STRING );
  1934. if ( !AddSystem( toolFrameworkModule, VTOOLFRAMEWORK_INTERFACE_VERSION ) )
  1935. return false;
  1936. }
  1937. #endif
  1938. COM_TimestampedLog( "CModAppSystemGroup::Create() - Finish" );
  1939. return true;
  1940. }
  1941. //-----------------------------------------------------------------------------
  1942. // Purpose: Fixme, we might need to verify if the interface names differ for the client versus the server
  1943. // Input : list -
  1944. // *moduleName -
  1945. // Output : Returns true on success, false on failure.
  1946. //-----------------------------------------------------------------------------
  1947. bool CModAppSystemGroup::ModuleAlreadyInList( CUtlVector< AppSystemInfo_t >& list, const char *moduleName, const char *interfaceName )
  1948. {
  1949. for ( int i = 0; i < list.Count(); ++i )
  1950. {
  1951. if ( !Q_stricmp( list[ i ].m_pModuleName, moduleName ) )
  1952. {
  1953. if ( Q_stricmp( list[ i ].m_pInterfaceName, interfaceName ) )
  1954. {
  1955. Error( "Game and client .dlls requesting different versions '%s' vs. '%s' from '%s'\n",
  1956. list[ i ].m_pInterfaceName, interfaceName, moduleName );
  1957. }
  1958. return true;
  1959. }
  1960. }
  1961. return false;
  1962. }
  1963. bool CModAppSystemGroup::PreInit()
  1964. {
  1965. return true;
  1966. }
  1967. void SV_ShutdownGameDLL();
  1968. int CModAppSystemGroup::Main()
  1969. {
  1970. int nRunResult = RUN_OK;
  1971. if ( IsServerOnly() )
  1972. {
  1973. // Start up the game engine
  1974. if ( eng->Load( true, host_parms.basedir ) )
  1975. {
  1976. // If we're using STEAM, pass the map cycle list as resource hints...
  1977. #if LATER
  1978. if ( g_pFileSystem->IsSteam() )
  1979. {
  1980. char *hints;
  1981. if ( BuildMapCycleListHints(&hints) )
  1982. {
  1983. g_pFileSystem->HintResourceNeed(hints, true);
  1984. }
  1985. if ( hints )
  1986. {
  1987. free(hints);
  1988. }
  1989. }
  1990. #endif
  1991. // Dedicated server drives frame loop manually
  1992. dedicated->RunServer();
  1993. SV_ShutdownGameDLL();
  1994. }
  1995. }
  1996. else
  1997. {
  1998. eng->SetQuitting( IEngine::QUIT_NOTQUITTING );
  1999. COM_TimestampedLog( "eng->Load" );
  2000. // Start up the game engine
  2001. if ( eng->Load( false, host_parms.basedir ) )
  2002. {
  2003. #if !defined(DEDICATED)
  2004. toolframework->ServerInit( g_ServerFactory );
  2005. if ( s_EngineAPI.MainLoop() )
  2006. {
  2007. nRunResult = RUN_RESTART;
  2008. }
  2009. // unload systems
  2010. eng->Unload();
  2011. toolframework->ServerShutdown();
  2012. #endif
  2013. SV_ShutdownGameDLL();
  2014. }
  2015. }
  2016. return nRunResult;
  2017. }
  2018. void CModAppSystemGroup::PostShutdown()
  2019. {
  2020. }
  2021. void CModAppSystemGroup::Destroy()
  2022. {
  2023. if ( g_pMatchFramework )
  2024. {
  2025. TRACESHUTDOWN( g_pMatchFramework->Shutdown() );
  2026. g_pMatchFramework = NULL;
  2027. }
  2028. // unload game and client .dlls
  2029. ServerDLL_Unload();
  2030. #ifndef DEDICATED
  2031. if ( !IsServerOnly() )
  2032. {
  2033. ClientDLL_Unload();
  2034. }
  2035. #endif
  2036. /// Matchmaking
  2037. Host_SubscribeForProfileEvents( false );
  2038. FileSystem_UnloadModule( g_pMatchmakingDllModule );
  2039. g_pIfaceMatchFramework = NULL;
  2040. g_pMatchmakingDllModule = NULL;
  2041. g_pfnMatchmakingFactory = NULL;
  2042. g_pMatchFramework = NULL;
  2043. /// vjobs
  2044. #ifdef ENGINE_MANAGES_VJOBS
  2045. if( g_pVjobsDllModule )
  2046. {
  2047. g_pFileSystem->UnloadModule( g_pVjobsDllModule );
  2048. g_pVjobsDllModule = NULL;
  2049. g_pfnVjobsFactory = NULL;
  2050. g_pVJobs = NULL;
  2051. }
  2052. #endif
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. // Console command to toggle back and forth between the engine running or not
  2056. //-----------------------------------------------------------------------------
  2057. #ifndef DEDICATED
  2058. void EditorToggle_f()
  2059. {
  2060. // Will switch back to the editor
  2061. bool bActive = (eng->GetState() != IEngine::DLL_PAUSED);
  2062. s_EngineAPI.ActivateSimulation( !bActive );
  2063. }
  2064. #endif // DEDICATED
  2065. //-----------------------------------------------------------------------------
  2066. //
  2067. // Purpose: Expose engine interface to launcher for dedicated servers
  2068. //
  2069. //-----------------------------------------------------------------------------
  2070. class CDedicatedServerAPI : public CTier3AppSystem< IDedicatedServerAPI >
  2071. {
  2072. typedef CTier3AppSystem< IDedicatedServerAPI > BaseClass;
  2073. public:
  2074. CDedicatedServerAPI() :
  2075. m_pDedicatedServer( 0 )
  2076. {
  2077. }
  2078. virtual bool Connect( CreateInterfaceFn factory );
  2079. virtual void Disconnect();
  2080. virtual void *QueryInterface( const char *pInterfaceName );
  2081. virtual bool ModInit( ModInfo_t &info );
  2082. virtual void ModShutdown( void );
  2083. virtual bool RunFrame( void );
  2084. virtual void AddConsoleText( char *text );
  2085. virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen );
  2086. virtual void UpdateHostname(char *pszHostname, int maxlen);
  2087. virtual void SetSubProcessID( int nID, int nChildSocketHandle );
  2088. static void PreMinidumpCallback( void *pvContext );
  2089. void PreMinidumpCallbackImpl();
  2090. private:
  2091. int BuildMapCycleListHints( char **hints );
  2092. CModAppSystemGroup *m_pDedicatedServer;
  2093. };
  2094. void CDedicatedServerAPI::SetSubProcessID( int nId, int nChildSocketHandle )
  2095. {
  2096. g_nForkID = nId;
  2097. g_nSocketToParentProcess = nChildSocketHandle;
  2098. }
  2099. // Static method
  2100. void CDedicatedServerAPI::PreMinidumpCallback( void *pvContext )
  2101. {
  2102. if ( !pvContext )
  2103. {
  2104. return;
  2105. }
  2106. ((CDedicatedServerAPI *)pvContext)->PreMinidumpCallbackImpl();
  2107. }
  2108. void CDedicatedServerAPI::PreMinidumpCallbackImpl()
  2109. {
  2110. EndWatchdogTimer(); // Uploading the dump can take a while, turn off our watchdog
  2111. // Win32 dedicated servers build a minidump comment in the exception handler itself
  2112. #if defined( LINUX )
  2113. fprintf( stderr, "PreMinidumpCallback: updating dump comment\n" );
  2114. BuildMinidumpComment( NULL );
  2115. #endif
  2116. }
  2117. //-----------------------------------------------------------------------------
  2118. // Singleton
  2119. //-----------------------------------------------------------------------------
  2120. EXPOSE_SINGLE_INTERFACE( CDedicatedServerAPI, IDedicatedServerAPI, VENGINE_HLDS_API_VERSION );
  2121. bool g_bIsVGuiBasedDedicatedServer = false; // Assume use convar
  2122. //-----------------------------------------------------------------------------
  2123. // Connect, disconnect
  2124. //-----------------------------------------------------------------------------
  2125. bool CDedicatedServerAPI::Connect( CreateInterfaceFn factory )
  2126. {
  2127. if ( CommandLine()->FindParm( "-sv_benchmark" ) != 0 )
  2128. {
  2129. Plat_SetBenchmarkMode( true );
  2130. }
  2131. // Store off the app system factory...
  2132. g_AppSystemFactory = factory;
  2133. if ( !BaseClass::Connect( factory ) )
  2134. return false;
  2135. dedicated = ( IDedicatedExports * )factory( VENGINE_DEDICATEDEXPORTS_API_VERSION, NULL );
  2136. if ( !dedicated )
  2137. return false;
  2138. g_pFileSystem = g_pFullFileSystem;
  2139. #ifndef DBGFLAG_STRINGS_STRIP
  2140. g_pFileSystem->SetWarningFunc( Warning );
  2141. #endif
  2142. if ( !Shader_Connect( false ) )
  2143. return false;
  2144. if ( !g_pStudioRender )
  2145. {
  2146. Sys_Error( "Unable to init studio render system version %s\n", STUDIO_RENDER_INTERFACE_VERSION );
  2147. return false;
  2148. }
  2149. g_pPhysics = (IPhysics*)factory( VPHYSICS_INTERFACE_VERSION, NULL );
  2150. g_pSoundEmitterSystem = (ISoundEmitterSystemBase*)factory( SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL);
  2151. #if defined( DEDICATED )
  2152. if ( !g_pDataCache || !g_pPhysics || !g_pMDLCache )
  2153. #else
  2154. if ( !g_pDataCache || !g_pPhysics || !g_pMDLCache || !g_pSoundEmitterSystem)
  2155. #endif
  2156. {
  2157. Warning( "Engine wasn't able to acquire required interfaces!\n" );
  2158. return false;
  2159. }
  2160. ConnectMDLCacheNotify();
  2161. #ifndef DEDICATED
  2162. splitscreen->Init();
  2163. #endif
  2164. return true;
  2165. }
  2166. void CDedicatedServerAPI::Disconnect()
  2167. {
  2168. #ifndef DEDICATED
  2169. splitscreen->Shutdown();
  2170. #endif
  2171. DisconnectMDLCacheNotify();
  2172. g_pPhysics = NULL;
  2173. g_pSoundEmitterSystem = NULL;
  2174. Shader_Disconnect();
  2175. g_pFileSystem = NULL;
  2176. ConVar_Unregister();
  2177. dedicated = NULL;
  2178. BaseClass::Disconnect();
  2179. g_AppSystemFactory = NULL;
  2180. }
  2181. //-----------------------------------------------------------------------------
  2182. // Query interface
  2183. //-----------------------------------------------------------------------------
  2184. void *CDedicatedServerAPI::QueryInterface( const char *pInterfaceName )
  2185. {
  2186. // Loading the engine DLL mounts *all* engine interfaces
  2187. CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary
  2188. return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing.
  2189. }
  2190. //-----------------------------------------------------------------------------
  2191. // Creates the hint list for a multiplayer map rotation from the map cycle.
  2192. // The map cycle message is a text string with CR/CRLF separated lines.
  2193. // -removes comments
  2194. // -removes arguments
  2195. //-----------------------------------------------------------------------------
  2196. const char *szCommonPreloads = "MP_Preloads";
  2197. const char *szReslistsBaseDir = "reslists2";
  2198. const char *szReslistsExt = ".lst";
  2199. int CDedicatedServerAPI::BuildMapCycleListHints(char **hints)
  2200. {
  2201. char szMap[ MAX_OSPATH + 2 ]; // room for one path plus <CR><LF>
  2202. unsigned int length;
  2203. char szMod[MAX_OSPATH];
  2204. // Determine the mod directory.
  2205. Q_FileBase(com_gamedir, szMod, sizeof( szMod ) );
  2206. // Open mapcycle.txt
  2207. char cszMapCycleTxtFile[MAX_OSPATH];
  2208. Q_snprintf(cszMapCycleTxtFile, sizeof( cszMapCycleTxtFile ), "%s\\mapcycle.txt", szMod);
  2209. FileHandle_t pFile = g_pFileSystem->Open(cszMapCycleTxtFile, "rb");
  2210. if ( pFile == FILESYSTEM_INVALID_HANDLE )
  2211. {
  2212. ConMsg("Unable to open %s", cszMapCycleTxtFile);
  2213. return 0;
  2214. }
  2215. // Start off with the common preloads.
  2216. Q_snprintf(szMap, sizeof( szMap ), "%s\\%s\\%s%s\r\n", szReslistsBaseDir, szMod, szCommonPreloads, szReslistsExt);
  2217. int hintsSize = strlen(szMap) + 1;
  2218. *hints = (char*)malloc( hintsSize );
  2219. if ( *hints == NULL )
  2220. {
  2221. ConMsg("Unable to allocate memory for map cycle hints list");
  2222. g_pFileSystem->Close( pFile );
  2223. return 0;
  2224. }
  2225. Q_strncpy( *hints, szMap, hintsSize );
  2226. // Read in and parse mapcycle.txt
  2227. length = g_pFileSystem->Size(pFile);
  2228. if ( length )
  2229. {
  2230. char *pStart = (char *)malloc(length);
  2231. if ( pStart && ( 1 == g_pFileSystem->Read(pStart, length, pFile) )
  2232. )
  2233. {
  2234. const char *pFileList = pStart;
  2235. while ( 1 )
  2236. {
  2237. pFileList = COM_Parse( pFileList );
  2238. if ( strlen( com_token ) <= 0 )
  2239. break;
  2240. Q_strncpy(szMap, com_token, sizeof(szMap));
  2241. // Any more tokens on this line?
  2242. if ( COM_TokenWaiting( pFileList ) )
  2243. {
  2244. pFileList = COM_Parse( pFileList );
  2245. }
  2246. char mapLine[sizeof(szMap)];
  2247. Q_snprintf(mapLine, sizeof(mapLine), "%s\\%s\\%s%s\r\n", szReslistsBaseDir, szMod, szMap, szReslistsExt);
  2248. *hints = (char*)realloc(*hints, strlen(*hints) + 1 + strlen(mapLine) + 1); // count NULL string terminators
  2249. if ( *hints == NULL )
  2250. {
  2251. ConMsg("Unable to reallocate memory for map cycle hints list");
  2252. g_pFileSystem->Close( pFile );
  2253. return 0;
  2254. }
  2255. Q_strncat(*hints, mapLine, hintsSize, COPY_ALL_CHARACTERS);
  2256. }
  2257. }
  2258. }
  2259. g_pFileSystem->Close(pFile);
  2260. // Tack on <moddir>\mp_maps.txt to the end to make sure we load reslists for all multiplayer maps we know of
  2261. Q_snprintf(szMap, sizeof( szMap ), "%s\\%s\\mp_maps.txt\r\n", szReslistsBaseDir, szMod);
  2262. *hints = (char*)realloc(*hints, strlen(*hints) + 1 + strlen(szMap) + 1); // count NULL string terminators
  2263. Q_strncat( *hints, szMap, hintsSize, COPY_ALL_CHARACTERS );
  2264. return 1;
  2265. }
  2266. //-----------------------------------------------------------------------------
  2267. // Purpose:
  2268. // Input : type - 0 == normal, 1 == dedicated server
  2269. // *instance -
  2270. // *basedir -
  2271. // *cmdline -
  2272. // launcherFactory -
  2273. //-----------------------------------------------------------------------------
  2274. AppId_t g_nDedicatedServerAppIdBreakpad = 0;
  2275. bool CDedicatedServerAPI::ModInit( ModInfo_t &info )
  2276. {
  2277. g_bIsVGuiBasedDedicatedServer = dedicated->IsGuiDedicatedServer();
  2278. s_bIsDedicatedServer = true;
  2279. //
  2280. // Configure breakpad
  2281. // this must be done after mod search path chain is configured
  2282. //
  2283. // Parse AppID from steam.inf file
  2284. Sys_Version( true );
  2285. #if !defined( NO_STEAM ) && !defined( _GAMECONSOLE )
  2286. if ( !CommandLine()->FindParm( "-nobreakpad" ) )
  2287. {
  2288. bool bValveDS = false;
  2289. if ( !CommandLine()->FindParm( "-novalveds" ) )
  2290. {
  2291. char const *szDllFilename = "server_valve" DLL_EXT_STRING;
  2292. if ( g_pFileSystem->FileExists( szDllFilename, "GAMEBIN" ) )
  2293. bValveDS = true;
  2294. }
  2295. // Override reporting AppID based on CS:GO depot mappings
  2296. switch ( g_unSteamAppID )
  2297. {
  2298. case 710: // Trunk / debug (fake appids)
  2299. g_nDedicatedServerAppIdBreakpad = bValveDS ? 712 : 711;
  2300. break;
  2301. case 730: // Rel public / pcbeta
  2302. g_nDedicatedServerAppIdBreakpad = bValveDS ? 741 : 740;
  2303. break;
  2304. case 268440:// Staging
  2305. g_nDedicatedServerAppIdBreakpad = bValveDS ? 268480 : 268460;
  2306. break;
  2307. }
  2308. if ( g_nDedicatedServerAppIdBreakpad ) // Override breakpad AppID
  2309. SteamAPI_SetBreakpadAppID( g_nDedicatedServerAppIdBreakpad );
  2310. // Build a custom version string
  2311. CFmtStr fmtServerVersion( "%d.%d.D%c", GetHostVersion(), GetServerVersion(),
  2312. (bValveDS ? 'V' : 'C')
  2313. );
  2314. Msg( "Using breakpad minidump system %u/%s\n", g_nDedicatedServerAppIdBreakpad ? g_nDedicatedServerAppIdBreakpad : g_unSteamAppID, fmtServerVersion.Access() );
  2315. SteamAPI_UseBreakpadCrashHandler( fmtServerVersion.Access(), __DATE__, __TIME__, false /*full_memory_dumps*/, &__g_CDedicatedServerAPI_singleton, &CDedicatedServerAPI::PreMinidumpCallback );
  2316. if ( g_nDedicatedServerAppIdBreakpad ) // Actually force breakpad interfaces to load
  2317. SteamAPI_SetBreakpadAppID( g_nDedicatedServerAppIdBreakpad );
  2318. }
  2319. #endif // !NO_STEAM && !_GAMECONSOLE
  2320. eng->SetQuitting( IEngine::QUIT_NOTQUITTING );
  2321. // Set up the engineparms_t which contains global information about the mod
  2322. host_parms.basedir = const_cast<char*>(info.m_pBaseDirectory);
  2323. host_parms.mod = const_cast<char*>(GetModDirFromPath(info.m_pInitialMod));
  2324. host_parms.game = const_cast<char*>(info.m_pInitialGame);
  2325. g_bTextMode = info.m_bTextMode;
  2326. TRACEINIT( COM_InitFilesystem( info.m_pInitialMod ), COM_ShutdownFileSystem() );
  2327. // set this up as early as possible, if the server isn't going to run pure, stop CRCing bits as we load them
  2328. // this happens even before the ConCommand's are processed, but we need to be sure to either CRC every file
  2329. // that is loaded, or not bother doing any
  2330. // Note that this mirrors g_sv_pure_mode from sv_main.cpp
  2331. int pure_mode = 1; // default to on, +sv_pure 0 or -sv_pure 0 will turn it off
  2332. if ( CommandLine()->CheckParm("+sv_pure") )
  2333. pure_mode = CommandLine()->ParmValue( "+sv_pure", 1 );
  2334. else if ( CommandLine()->CheckParm("-sv_pure") )
  2335. pure_mode = CommandLine()->ParmValue( "-sv_pure", 1 );
  2336. if ( pure_mode )
  2337. {
  2338. // Mount all compatibility VPKs as well at the tail of the VPK search chain for verifying sv_pure clients
  2339. //
  2340. // See above:
  2341. // CEngineAPI::SetStartupInfo
  2342. // for how clients enable VPK content-shadowing
  2343. //
  2344. char const *szCompatibilityVPKs[] = {
  2345. "lowviolence",
  2346. "perfectworld"
  2347. };
  2348. for ( int j = 0; j < Q_ARRAYSIZE( szCompatibilityVPKs ); ++ j )
  2349. { // Add in same order listed to tail
  2350. g_pFullFileSystem->AddSearchPath( szCompatibilityVPKs[ j ], "COMPAT:GAME", PATH_ADD_TO_TAIL );
  2351. }
  2352. g_pFullFileSystem->EnableWhitelistFileTracking( true, true, CommandLine()->FindParm( "-sv_pure_verify_hashes" ) ? true : false );
  2353. }
  2354. else
  2355. g_pFullFileSystem->EnableWhitelistFileTracking( false, false, false );
  2356. materials->ModInit();
  2357. // Setup the material system config record, CreateGameWindow depends on it
  2358. // (when we're running stand-alone)
  2359. #ifndef DEDICATED
  2360. InitMaterialSystemConfig( true ); // !!should this be called standalone or not?
  2361. #endif
  2362. // Initialize general game stuff and create the main window
  2363. if ( game->Init( NULL ) )
  2364. {
  2365. m_pDedicatedServer = new CModAppSystemGroup( true, info.m_pParentAppSystemGroup );
  2366. // Store off the app system factory...
  2367. g_AppSystemFactory = m_pDedicatedServer->GetFactory();
  2368. m_pDedicatedServer->Run();
  2369. return true;
  2370. }
  2371. return false;
  2372. }
  2373. void CDedicatedServerAPI::ModShutdown( void )
  2374. {
  2375. if ( m_pDedicatedServer )
  2376. {
  2377. delete m_pDedicatedServer;
  2378. m_pDedicatedServer = NULL;
  2379. }
  2380. g_AppSystemFactory = NULL;
  2381. // Unload GL, Sound, etc.
  2382. eng->Unload();
  2383. // Shut down memory, etc.
  2384. game->Shutdown();
  2385. materials->ModShutdown();
  2386. TRACESHUTDOWN( COM_ShutdownFileSystem() );
  2387. }
  2388. bool CDedicatedServerAPI::RunFrame( void )
  2389. {
  2390. // Bail if someone wants to quit.
  2391. if ( eng->GetQuitting() != IEngine::QUIT_NOTQUITTING )
  2392. {
  2393. return false;
  2394. }
  2395. // Run engine frame
  2396. eng->Frame();
  2397. return true;
  2398. }
  2399. void CDedicatedServerAPI::AddConsoleText( char *text )
  2400. {
  2401. Cbuf_AddText( CBUF_SERVER, text );
  2402. }
  2403. void CDedicatedServerAPI::UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen )
  2404. {
  2405. Host_GetHostInfo( fps, nActive, nMaxPlayers, pszMap, maxlen );
  2406. }
  2407. void CDedicatedServerAPI::UpdateHostname(char *pszHostname, int maxlen)
  2408. {
  2409. if ( pszHostname && ( maxlen > 0 ) )
  2410. {
  2411. Q_strncpy( pszHostname, sv.GetName(), maxlen );
  2412. }
  2413. }
  2414. #ifndef DEDICATED
  2415. class CGameUIFuncs : public IGameUIFuncs
  2416. {
  2417. public:
  2418. bool IsKeyDown( const char *keyname, bool& isdown )
  2419. {
  2420. isdown = false;
  2421. if ( !g_ClientDLL )
  2422. return false;
  2423. return g_ClientDLL->IN_IsKeyDown( keyname, isdown );
  2424. }
  2425. const char *GetBindingForButtonCode( ButtonCode_t code )
  2426. {
  2427. return ::Key_BindingForKey( code );
  2428. }
  2429. virtual ButtonCode_t GetButtonCodeForBind( const char *bind, int userId )
  2430. {
  2431. const char *pKeyName = Key_NameForBinding( bind , userId );
  2432. if ( !pKeyName )
  2433. return KEY_NONE;
  2434. return g_pInputSystem->StringToButtonCode( pKeyName ) ;
  2435. }
  2436. void GetVideoModes( struct vmode_s **ppListStart, int *pCount )
  2437. {
  2438. if ( videomode )
  2439. {
  2440. *pCount = videomode->GetModeCount();
  2441. *ppListStart = videomode->GetMode( 0 );
  2442. }
  2443. else
  2444. {
  2445. *pCount = 0;
  2446. *ppListStart = NULL;
  2447. }
  2448. }
  2449. void GetDesktopResolution( int &width, int &height )
  2450. {
  2451. int refreshrate;
  2452. game->GetDesktopInfo( width, height, refreshrate );
  2453. }
  2454. virtual void SetFriendsID( uint friendsID, const char *friendsName )
  2455. {
  2456. GetLocalClient().SetFriendsID( friendsID, friendsName );
  2457. }
  2458. bool IsConnectedToVACSecureServer()
  2459. {
  2460. if ( GetBaseLocalClient().IsConnected() )
  2461. return Steam3Client().BGSSecure();
  2462. return false;
  2463. }
  2464. };
  2465. EXPOSE_SINGLE_INTERFACE( CGameUIFuncs, IGameUIFuncs, VENGINE_GAMEUIFUNCS_VERSION );
  2466. #endif