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.

6642 lines
176 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "tier0/fasttimer.h"
  7. #ifdef _WIN32
  8. #if !defined(_X360)
  9. #include "winlite.h"
  10. #endif
  11. #include "tier0/memdbgon.h" // needed because in release builds crtdbg.h is handled specially if USE_MEM_DEBUG is defined
  12. #include "tier0/memdbgoff.h"
  13. #include <crtdbg.h> // For getting at current heap size
  14. // For maximum compatibility use PSAPI v1
  15. // #define PSAPI_VERSION 1
  16. // #include "psapi.h"
  17. // #pragma comment(lib, "psapi.lib")
  18. #endif
  19. #include "tier1/fmtstr.h"
  20. #include "vstdlib/jobthread.h"
  21. #include "vstdlib/random.h"
  22. #include "server.h"
  23. #include "host_jmp.h"
  24. #include "screen.h"
  25. #include "keys.h"
  26. #include "cdll_int.h"
  27. #include "eiface.h"
  28. #include "sv_main.h"
  29. #include "master.h"
  30. #include "sv_log.h"
  31. #include "shadowmgr.h"
  32. #include "zone.h"
  33. #include "gl_cvars.h"
  34. #include "sv_filter.h"
  35. #include "ivideomode.h"
  36. #include "vprof_engine.h"
  37. #include "iengine.h"
  38. #include "matchmaking/imatchframework.h"
  39. #include "tier2/tier2.h"
  40. #include "enginethreads.h"
  41. #include "steam/steam_api.h"
  42. #include "LoadScreenUpdate.h"
  43. #include "datacache/idatacache.h"
  44. #include "profile.h"
  45. #include "dbginput.h"
  46. #include "filesystem.h"
  47. #include "tier0/microprofiler.h"
  48. #include "checksum_sha1.h"
  49. #if !defined DEDICATED
  50. #include "voice.h"
  51. #include "sound.h"
  52. #include "vaudio/ivaudio.h"
  53. #endif
  54. #include "icvar.h"
  55. #include "sys.h"
  56. #include "client.h"
  57. #include "cl_pred.h"
  58. #include "netconsole.h"
  59. #include "console.h"
  60. #include "view.h"
  61. #include "host.h"
  62. #include "decal.h"
  63. #include "gl_matsysiface.h"
  64. #include "gl_shader.h"
  65. #include "sys_dll.h"
  66. #include "cmodel_engine.h"
  67. #ifndef DEDICATED
  68. #include "con_nprint.h"
  69. #endif
  70. #include "filesystem.h"
  71. #include "filesystem_engine.h"
  72. #include "traceinit.h"
  73. #include "host_saverestore.h"
  74. #include "l_studio.h"
  75. #include "cl_demo.h"
  76. #include "cdll_engine_int.h"
  77. #include "host_cmd.h"
  78. #include "host_state.h"
  79. #include "dt_instrumentation.h"
  80. #include "dt_instrumentation_server.h"
  81. #include "const.h"
  82. #include "bitbuf_errorhandler.h"
  83. #include "soundflags.h"
  84. #include "enginestats.h"
  85. #include "tier1/strtools.h"
  86. #include "testscriptmgr.h"
  87. #include "tmessage.h"
  88. #include "tier0/vprof.h"
  89. #include "tier0/etwprof.h"
  90. #include "tier0/icommandline.h"
  91. #include "materialsystem/imaterialsystemhardwareconfig.h"
  92. #include "MapReslistGenerator.h"
  93. #include "DownloadListGenerator.h"
  94. #include "download.h"
  95. #include "staticpropmgr.h"
  96. #include "GameEventManager.h"
  97. #include "iprediction.h"
  98. #include "netmessages.h"
  99. #include "cl_main.h"
  100. #include "hltvserver.h"
  101. #include "hltvtest.h"
  102. #if defined( REPLAY_ENABLED )
  103. #include "replayserver.h"
  104. #include "replayhistorymanager.h"
  105. #endif
  106. #include "sys_mainwind.h"
  107. #include "host_phonehome.h"
  108. #ifndef DEDICATED
  109. #include "vgui_baseui_interface.h"
  110. #include "cl_steamauth.h"
  111. #endif
  112. #include "sv_remoteaccess.h" // NotifyDedicatedServerUI()
  113. #include "snd_audio_source.h"
  114. #include "sv_steamauth.h"
  115. #include "MapReslistGenerator.h"
  116. #include "DevShotGenerator.h"
  117. #include "sv_plugin.h"
  118. #include "toolframework/itoolframework.h"
  119. #include "ienginetoolinternal.h"
  120. #include "inputsystem/iinputsystem.h"
  121. #include "vgui_askconnectpanel.h"
  122. #include "cvar.h"
  123. #include "saverestoretypes.h"
  124. #include "filesystem/IQueuedLoader.h"
  125. #include "filesystem/IXboxInstaller.h"
  126. #include "soundservice.h"
  127. #include "steam/isteamremotestorage.h"
  128. #include "ConfigManager.h"
  129. #include "materialsystem/idebugtextureinfo.h"
  130. #if defined( _X360 )
  131. #include "xbox/xbox_win32stubs.h"
  132. #endif
  133. #include "engine/ips3frontpanelled.h"
  134. #include "audio_pch.h"
  135. #include "platforminputdevice.h"
  136. #include "status.h"
  137. #ifdef _X360
  138. #include "xbox/xbox_console.h"
  139. #define _XBOX
  140. #include <xtl.h>
  141. #undef _XBOX
  142. #endif
  143. #if defined ( _GAMECONSOLE )
  144. #include "GameUI/IGameUI.h"
  145. #include "vgui_baseui_interface.h"
  146. #endif
  147. #include "matchmaking/mm_helpers.h"
  148. #include "ixboxsystem.h"
  149. #if defined( INCLUDE_SCALEFORM )
  150. #include "scaleformui/scaleformui.h"
  151. #endif
  152. extern IXboxSystem *g_pXboxSystem;
  153. extern ConVar cl_cloud_settings;
  154. #ifndef DEDICATED
  155. extern IVAudio *vaudio;
  156. void *g_pMilesAudioEngineRef;
  157. #endif
  158. #ifdef _PS3
  159. #include "ps3/ps3_helpers.h"
  160. #endif
  161. // memdbgon must be the last include file in a .cpp file!!!
  162. #include "tier0/memdbgon.h"
  163. //-----------------------------------------------------------------------------
  164. // Forward declarations
  165. //-----------------------------------------------------------------------------
  166. void NET_Init( bool bDedicated );
  167. void CL_SetPagedPoolInfo();
  168. extern char *CM_EntityString( void );
  169. bool XBX_SetProfileDefaultSettings( int iController );
  170. extern ConVar host_map;
  171. extern ConVar sv_cheats;
  172. bool g_bDedicatedServerBenchmarkMode = false;
  173. int host_frameticks = 0;
  174. int host_tickcount = 0;
  175. int host_currentframetick = 0;
  176. bool g_bLowViolence = false;
  177. static bool g_bAllowSecureServers = true;
  178. #if defined( INCLUDE_SCALEFORM )
  179. const char g_szDefaultScaleformMovieName[] = "resource/flash/MainUIRootMovie.swf";
  180. const char g_szDefaultScaleformCursorName[] = "resource/flash/Cursor.swf";
  181. #endif
  182. #ifdef USE_SDL
  183. #include "appframework/ilaunchermgr.h"
  184. extern ILauncherMgr *g_pLauncherMgr;
  185. #endif
  186. // Engine player info, no game related infos here
  187. BEGIN_BYTESWAP_DATADESC( player_info_s )
  188. DEFINE_FIELD( version, FIELD_INTEGER64 ),
  189. DEFINE_FIELD( xuid, FIELD_INTEGER64 ),
  190. DEFINE_ARRAY( name, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  191. DEFINE_FIELD( userID, FIELD_INTEGER ),
  192. DEFINE_ARRAY( guid, FIELD_CHARACTER, SIGNED_GUID_LEN + 1 ),
  193. DEFINE_FIELD( friendsID, FIELD_INTEGER ),
  194. DEFINE_ARRAY( friendsName, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  195. DEFINE_FIELD( fakeplayer, FIELD_BOOLEAN ),
  196. DEFINE_FIELD( ishltv, FIELD_BOOLEAN ),
  197. #if defined( REPLAY_ENABLED )
  198. DEFINE_FIELD( isreplay, FIELD_BOOLEAN ),
  199. #endif
  200. DEFINE_ARRAY( customFiles, FIELD_INTEGER, MAX_CUSTOM_FILES ),
  201. DEFINE_FIELD( filesDownloaded, FIELD_INTEGER ),
  202. END_BYTESWAP_DATADESC()
  203. //------------------------------------------
  204. enum
  205. {
  206. FRAME_SEGMENT_INPUT = 0,
  207. FRAME_SEGMENT_CLIENT,
  208. FRAME_SEGMENT_SERVER,
  209. FRAME_SEGMENT_RENDER,
  210. FRAME_SEGMENT_SOUND,
  211. FRAME_SEGMENT_CLDLL,
  212. FRAME_SEGMENT_CMD_EXECUTE,
  213. NUM_FRAME_SEGMENTS,
  214. };
  215. class CFrameTimer
  216. {
  217. public:
  218. void ResetDeltas();
  219. CFrameTimer() : swaptime(0), framestarttime(0), framestarttimeduration(0)
  220. {
  221. m_flFPSVariability = 0;
  222. m_flFPSStdDeviationSeconds = 0;
  223. m_flFPSStdDeviationFrameStartTimeSeconds = 0;
  224. ResetDeltas();
  225. }
  226. void MarkFrameStartTime()
  227. {
  228. double newframestarttime = Sys_FloatTime();
  229. framestarttimeduration = framestarttime ? ( newframestarttime - framestarttime ) : 0.0;
  230. framestarttime = newframestarttime;
  231. }
  232. void MarkFrame();
  233. void StartFrameSegment( int i )
  234. {
  235. starttime[i] = Sys_FloatTime();
  236. }
  237. void EndFrameSegment( int i )
  238. {
  239. double dt = Sys_FloatTime() - starttime[i];
  240. deltas[ i ] += dt;
  241. }
  242. void MarkSwapTime( )
  243. {
  244. double newswaptime = Sys_FloatTime();
  245. frametime = newswaptime - swaptime;
  246. swaptime = newswaptime;
  247. ComputeFrameVariability();
  248. g_EngineStats.SetFrameTime( frametime );
  249. g_EngineStats.SetFPSVariability( m_flFPSVariability );
  250. host_frametime_stddeviation = m_flFPSStdDeviationSeconds;
  251. host_framestarttime_stddeviation = m_flFPSStdDeviationFrameStartTimeSeconds;
  252. host_frameendtime_computationduration = newswaptime - framestarttime;
  253. }
  254. float GetServerSimulationFrameTime()
  255. {
  256. return m_flLastServerTime;
  257. }
  258. private:
  259. enum
  260. {
  261. FRAME_HISTORY_COUNT = 50
  262. };
  263. friend void Host_Speeds();
  264. void ComputeFrameVariability();
  265. double time_base;
  266. double times[9];
  267. double swaptime;
  268. double framestarttime;
  269. double framestarttimeduration;
  270. double frametime;
  271. double m_flFPSVariability;
  272. double m_flFPSStdDeviationSeconds;
  273. double m_flFPSStdDeviationFrameStartTimeSeconds;
  274. double starttime[NUM_FRAME_SEGMENTS];
  275. double deltas[NUM_FRAME_SEGMENTS];
  276. float m_flLastServerTime;
  277. float m_pFrameStartTimeHistory[FRAME_HISTORY_COUNT];
  278. float m_pFrameTimeHistory[FRAME_HISTORY_COUNT];
  279. int m_nFrameTimeHistoryIndex;
  280. };
  281. static CFrameTimer g_HostTimes;
  282. float Host_GetServerSimulationFrameTime()
  283. {
  284. return g_HostTimes.GetServerSimulationFrameTime();
  285. }
  286. //------------------------------------------
  287. float host_time = 0.0;
  288. static ConVar violence_hblood( "violence_hblood","1", 0, "Draw human blood" );
  289. static ConVar violence_hgibs( "violence_hgibs","1", 0, "Show human gib entities" );
  290. static ConVar violence_ablood( "violence_ablood","1", 0, "Draw alien blood" );
  291. static ConVar violence_agibs( "violence_agibs","1", 0, "Show alien gib entities" );
  292. static bool GetDefaultSubtitlesState()
  293. {
  294. return XBX_IsLocalized() && !XBX_IsAudioLocalized();
  295. }
  296. // Marked as FCVAR_USERINFO so that the server can cull CC messages before networking them down to us!!!
  297. ConVar closecaption( "closecaption", GetDefaultSubtitlesState() ? "1" : "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE, "Enable close captioning." );
  298. ConVar cl_configversion( "cl_configversion", "8", FCVAR_DEVELOPMENTONLY, "Configuration layout version. Bump this to force a reset of the PS3 save game / settings." );
  299. extern ConVar sv_unlockedchapters;
  300. void Snd_Restart_f()
  301. {
  302. #ifndef DEDICATED
  303. extern bool snd_firsttime;
  304. CUtlVector<musicsave_t> music;
  305. // Ask sound system for current music tracks
  306. S_GetCurrentlyPlayingMusic( music );
  307. S_Shutdown();
  308. snd_firsttime = true;
  309. GetBaseLocalClient().ClearSounds();
  310. S_Init();
  311. for ( int i = 0; i < music.Count(); i++ )
  312. {
  313. S_RestartSong( &music[i] );
  314. }
  315. // Do this or else it won't have anything in the cache.
  316. if ( audiosourcecache && sv.GetMapName()[0] )
  317. {
  318. audiosourcecache->LevelInit( sv.GetMapName() );
  319. }
  320. // Flush soundscapes so they don't stop. We don't insert text in the buffer here because
  321. // cl_soundscape_flush is normally cheat-protected.
  322. ConCommand *pCommand = (ConCommand*)dynamic_cast< const ConCommand* >( g_pCVar->FindCommand( "cl_soundscape_flush" ) );
  323. if ( pCommand )
  324. {
  325. char const *argv[ 1 ] = { "cl_soundscape_flush" };
  326. CCommand cmd( 1, argv, kCommandSrcCode );
  327. pCommand->Dispatch( cmd );
  328. }
  329. #ifndef NO_VOICE
  330. Voice_ForceInit();
  331. #endif // NO_VOICE
  332. #endif
  333. }
  334. void Snd_Restart_Cmd()
  335. {
  336. if( !sv_cheats.GetBool() )
  337. {
  338. Msg("Warning: The console command \"snd_restart\" will not work with sv_cheats 0\n");
  339. return;
  340. }
  341. Snd_Restart_f();
  342. }
  343. static ConCommand snd_restart( "snd_restart", Snd_Restart_Cmd, "Restart sound system." );
  344. // In other C files.
  345. void Shader_Shutdown( void );
  346. void R_Shutdown( void );
  347. bool g_bAbortServerSet = false;
  348. #ifdef _WIN32
  349. static bool s_bInitPME = false;
  350. #endif
  351. static ConVar mem_test_quiet( "mem_test_quiet", "0", 0, "Don't print stats when memtesting" );
  352. static ConVar mem_test_each_frame( "mem_test_each_frame", "0", 0, "Run heap check at end of every frame\n" );
  353. extern void Host_PrintMemoryStatus( const char *mapname );
  354. const char *GetMapName( void )
  355. {
  356. static char mapname[ 256 ];
  357. const char *pTest = sv.GetMapName();
  358. if ( !pTest || !pTest[0] )
  359. {
  360. // possibly at menu
  361. pTest = "nomap";
  362. }
  363. Q_FileBase( pTest, mapname, sizeof( mapname ) );
  364. return mapname;
  365. }
  366. CON_COMMAND( mem_dump, "Dump memory stats to text file." )
  367. {
  368. ConMsg("Writing memory stats to file memstats.txt\n");
  369. const char *mapname = GetMapName();
  370. Host_PrintMemoryStatus( mapname );
  371. g_pMemAlloc->DumpStatsFileBase( mapname );
  372. // Dump memory about other memory, chiefly from CMemoryStack.
  373. DumpMemoryInfoStats();
  374. }
  375. CON_COMMAND( mem_verify, "Verify the validity of the heap" )
  376. {
  377. g_pMemAlloc->heapchk();
  378. }
  379. CON_COMMAND( mem_compact, "" )
  380. {
  381. g_pMemAlloc->CompactHeap();
  382. }
  383. CON_COMMAND( mem_incremental_compact, "" )
  384. {
  385. g_pMemAlloc->CompactIncremental();
  386. }
  387. CON_COMMAND( mem_eat, "" )
  388. {
  389. MemAlloc_Alloc( 1024*1024 );
  390. }
  391. ConVar mem_incremental_compact_rate( "mem_incremental_compact_rate", ".5", FCVAR_CHEAT, "Rate at which to attempt internal heap compation" );
  392. static bool MemTest()
  393. {
  394. bool verbose = ( !mem_test_quiet.GetBool() && !mem_test_each_frame.GetBool() );
  395. if ( verbose )
  396. {
  397. Msg( "\nBegin mem_test\n" );
  398. Host_PrintMemoryStatus( GetMapName() );
  399. }
  400. bool result = g_pMemAlloc->CrtCheckMemory() ? true : false;
  401. if ( verbose )
  402. {
  403. Msg( "\nEnd mem_test\n" );
  404. }
  405. return result;
  406. }
  407. CON_COMMAND( mem_test, "" )
  408. {
  409. MemTest();
  410. }
  411. static ConVar mem_test_every_n_seconds( "mem_test_every_n_seconds", "0", 0, "Run heap check at a specified interval\n" );
  412. static ConVar singlestep( "singlestep", "0", FCVAR_CHEAT, "Run engine in single step mode ( set next to 1 to advance a frame )" );
  413. static ConVar next( "next", "0", FCVAR_CHEAT, "Set to 1 to advance to next frame ( when singlestep == 1 )" );
  414. // Print a debug message when the client or server cache is missed
  415. ConVar host_showcachemiss( "host_showcachemiss", "0", 0, "Print a debug message when the client or server cache is missed." );
  416. static ConVar mem_dumpstats( "mem_dumpstats", "0", 0, "Dump current and max heap usage info to console at end of frame ( set to 2 for continuous output )\n" );
  417. static ConVar host_ShowIPCCallCount( "host_ShowIPCCallCount", "0", 0, "Print # of IPC calls this number of times per second. If set to -1, the # of IPC calls is shown every frame." );
  418. ConVar vprof_server_spike_threshold( "vprof_server_spike_threshold", "999.0" );
  419. ConVar vprof_server_thread( "vprof_server_thread", "0" );
  420. #if defined( RAD_TELEMETRY_ENABLED )
  421. static void OnChangeTelemetryPause ( IConVar *var, const char *pOldValue, float flOldValue )
  422. {
  423. TM_PAUSE( TELEMETRY_LEVEL0, 1 );
  424. }
  425. static void OnChangeTelemetryResume ( IConVar *var, const char *pOldValue, float flOldValue )
  426. {
  427. TM_PAUSE( TELEMETRY_LEVEL0, 0 );
  428. }
  429. static void OnChangeTelemetryLevel ( IConVar *var, const char *pOldValue, float flOldValue )
  430. {
  431. char* pIEnd;
  432. const char *pLevel = (( ConVar* )var)->GetString();
  433. TelemetrySetLevel( strtoul( pLevel, &pIEnd, 0 ) );
  434. }
  435. static void OnChangeTelemetryFrameCount ( IConVar *var, const char *pOldValue, float flOldValue )
  436. {
  437. char* pIEnd;
  438. const char *pFrameCount = (( ConVar* )var)->GetString();
  439. g_Telemetry.FrameCount = strtoul( pFrameCount, &pIEnd, 0 );
  440. Msg( " TELEMETRY: Setting Telemetry FrameCount: '%d'\n", g_Telemetry.FrameCount );
  441. }
  442. static void OnChangeTelemetryServer ( IConVar *var, const char *pOldValue, float flOldValue )
  443. {
  444. const char *pServerAddress = (( ConVar* )var)->GetString();
  445. Q_strncpy( g_Telemetry.ServerAddress, pServerAddress, ARRAYSIZE( g_Telemetry.ServerAddress ) );
  446. Msg( " TELEMETRY: Setting Telemetry server: '%s'\n", pServerAddress );
  447. }
  448. static void OnChangeTelemetryZoneFilterVal ( IConVar *var, const char *pOldValue, float flOldValue )
  449. {
  450. char* pIEnd;
  451. const char *pFilterValue = (( ConVar* )var)->GetString();
  452. g_Telemetry.ZoneFilterVal = strtoul( pFilterValue, &pIEnd, 0 );
  453. Msg( " TELEMETRY: Setting Telemetry ZoneFilterVal: '%d'\n", g_Telemetry.ZoneFilterVal );
  454. }
  455. static void OnChangeTelemetryDemoStart ( IConVar *var, const char *pOldValue, float flOldValue )
  456. {
  457. char* pIEnd;
  458. const char *pVal = (( ConVar* )var)->GetString();
  459. g_Telemetry.DemoTickStart = strtoul( pVal, &pIEnd, 0 );
  460. if( g_Telemetry.DemoTickStart > 2000 )
  461. {
  462. char cmd[ 256 ];
  463. // If we're far away from the start of the demo file, then jump to ~1000 ticks before.
  464. Q_snprintf( cmd, sizeof( cmd ), "demo_gototick %d", g_Telemetry.DemoTickStart - 1000 );
  465. Cbuf_AddText( Cbuf_GetCurrentPlayer(), cmd, kCommandSrcCode, 100 );
  466. }
  467. Msg( " TELEMETRY: Setting Telemetry DemoTickStart: '%d'\n", g_Telemetry.DemoTickStart );
  468. }
  469. static void OnChangeTelemetryDemoEnd ( IConVar *var, const char *pOldValue, float flOldValue )
  470. {
  471. char* pIEnd;
  472. const char *pVal = (( ConVar* )var)->GetString();
  473. g_Telemetry.DemoTickEnd = strtoul( pVal, &pIEnd, 0 );
  474. Msg( " TELEMETRY: Setting Telemetry DemoTickEnd: '%d'\n", g_Telemetry.DemoTickEnd );
  475. }
  476. ConVar telemetry_pause( "telemetry_pause", "0", FCVAR_RELEASE, "Pause Telemetry", OnChangeTelemetryPause );
  477. ConVar telemetry_resume( "telemetry_resume", "0", FCVAR_RELEASE, "Resume Telemetry", OnChangeTelemetryResume );
  478. ConVar telemetry_filtervalue( "telemetry_filtervalue", "500", FCVAR_RELEASE, "Set Telemetry ZoneFilterVal (MicroSeconds)", OnChangeTelemetryZoneFilterVal );
  479. ConVar telemetry_framecount( "telemetry_framecount", "0", 0, "Set Telemetry count of frames to capture", OnChangeTelemetryFrameCount );
  480. ConVar telemetry_level( "telemetry_level", "0", FCVAR_RELEASE, "Set Telemetry profile level: 0 being off. Hight bit set for mask: 0x8#######", OnChangeTelemetryLevel );
  481. ConVar telemetry_server( "telemetry_server", "localhost", FCVAR_RELEASE, "Set Telemetry server", OnChangeTelemetryServer );
  482. ConVar telemetry_demostart( "telemetry_demostart", "0", 0, "When playing demo, start telemetry on tick #", OnChangeTelemetryDemoStart );
  483. ConVar telemetry_demoend( "telemetry_demoend", "0", 0, "When playing demo, stop telemetry on tick #", OnChangeTelemetryDemoEnd );
  484. #endif
  485. static unsigned g_MainThreadId = ThreadGetCurrentId();
  486. extern bool gfBackground;
  487. static bool host_checkheap = false;
  488. CCommonHostState host_state;
  489. //-----------------------------------------------------------------------------
  490. #if defined(_X360)
  491. static bool g_bGimped = false;
  492. static int64 *g_pRange1 = NULL;
  493. static int64 *g_pRange2 = NULL;
  494. CON_COMMAND(cache_gimp, "Gimp the cache")
  495. {
  496. if ( g_bGimped )
  497. {
  498. XUnlockL2( XLOCKL2_INDEX_XPS );
  499. XUnlockL2( XLOCKL2_INDEX_TITLE );
  500. XPhysicalFree( g_pRange1 );
  501. XPhysicalFree( g_pRange2 );
  502. g_pRange1 = g_pRange2 = NULL;
  503. g_bGimped = false;
  504. }
  505. else
  506. {
  507. g_pRange1 = ( int64* )XPhysicalAlloc( XLOCKL2_LOCK_SIZE_2_WAYS, MAXULONG_PTR, XLOCKL2_LOCK_SIZE_2_WAYS, PAGE_READWRITE | MEM_LARGE_PAGES );
  508. g_pRange2 = ( int64* )XPhysicalAlloc( XLOCKL2_LOCK_SIZE_2_WAYS, MAXULONG_PTR, XLOCKL2_LOCK_SIZE_2_WAYS, PAGE_READWRITE | MEM_LARGE_PAGES );
  509. g_bGimped = true;
  510. XLockL2( XLOCKL2_INDEX_XPS, g_pRange1, XLOCKL2_LOCK_SIZE_2_WAYS, XLOCKL2_LOCK_SIZE_2_WAYS, 0 );
  511. XLockL2( XLOCKL2_INDEX_TITLE, g_pRange2, XLOCKL2_LOCK_SIZE_2_WAYS, XLOCKL2_LOCK_SIZE_2_WAYS, 0 );
  512. for ( int i = 0; i < XLOCKL2_LOCK_SIZE_2_WAYS/8; i++ )
  513. {
  514. g_pRange1[i] = 0;
  515. g_pRange2[i] = 0;
  516. }
  517. }
  518. }
  519. #endif
  520. //-----------------------------------------------------------------------------
  521. enum HostThreadMode
  522. {
  523. HTM_DISABLED,
  524. HTM_DEFAULT,
  525. HTM_FORCED,
  526. };
  527. // On the PS3, we want host_thead_mode and threaded_sound off.
  528. ConVar host_thread_mode( "host_thread_mode", ( IsPlatformX360() || IsPlatformPS3() ) ? "1" : "0", FCVAR_DEVELOPMENTONLY, "Run the host in threaded mode, (0 == off, 1 == if multicore, 2 == force)" );
  529. ConVar host_threaded_sound( "host_threaded_sound", ( IsPlatformX360() || IsPlatformPS3()) ? "1" : "0", 0, "Run the sound on a thread (independent of mix)" );
  530. ConVar host_threaded_sound_simplethread( "host_threaded_sound_simplethread", ( IsPlatformPS3()) ? "1" : "0", 0, "Run the sound on a simple thread not a jobthread" );
  531. extern ConVar threadpool_affinity;
  532. void OnChangeThreadAffinity( IConVar *var, const char *pOldValue, float flOldValue )
  533. {
  534. if ( g_pThreadPool->NumThreads() )
  535. {
  536. g_pThreadPool->Distribute( threadpool_affinity.GetBool() );
  537. }
  538. }
  539. ConVar threadpool_affinity( "threadpool_affinity", "1", 0, "Enable setting affinity", 0, 0, 0, 0, &OnChangeThreadAffinity );
  540. extern ConVar threadpool_reserve;
  541. CThreadEvent g_ReleaseThreadReservation( true );
  542. CInterlockedInt g_NumReservedThreads;
  543. void ThreadPoolReserverFunction()
  544. {
  545. g_ReleaseThreadReservation.Wait();
  546. --g_NumReservedThreads;
  547. }
  548. void ReserveThreads( int nToReserve )
  549. {
  550. nToReserve = clamp( nToReserve, 0, g_pThreadPool->NumThreads() );
  551. g_ReleaseThreadReservation.Set();
  552. while ( g_NumReservedThreads != 0 )
  553. {
  554. ThreadSleep( 0 );
  555. }
  556. g_ReleaseThreadReservation.Reset();
  557. while ( nToReserve-- )
  558. {
  559. g_NumReservedThreads++;
  560. g_pThreadPool->QueueCall( &ThreadPoolReserverFunction )->Release();
  561. }
  562. Msg( "%d threads being reserved\n", (int)g_NumReservedThreads );
  563. }
  564. void OnChangeThreadReserve( IConVar *var, const char *pOldValue, float flOldValue )
  565. {
  566. ReserveThreads( threadpool_reserve.GetInt() );
  567. }
  568. ConVar threadpool_reserve( "threadpool_reserve", "0", 0, "Consume the specified number of threads in the thread pool", 0, 0, 0, 0, &OnChangeThreadReserve );
  569. CON_COMMAND( threadpool_cycle_reserve, "Cycles threadpool reservation by powers of 2" )
  570. {
  571. int nCores = g_pThreadPool->NumThreads() + 1;
  572. int nAvailableCores = nCores - g_NumReservedThreads;
  573. Assert( nAvailableCores );
  574. int ratio = nCores / nAvailableCores;
  575. ratio *= 2;
  576. if ( ratio > nCores )
  577. {
  578. ReserveThreads( 0 );
  579. }
  580. else
  581. {
  582. ReserveThreads( nCores - nCores / ratio );
  583. }
  584. }
  585. CON_COMMAND( thread_test_tslist, "" )
  586. {
  587. int nLengthList = ( args.ArgC() == 1 ) ? 1 : atoi( args.Arg( 1 ) );
  588. int nTests = ( args.ArgC() == 2 ) ? 1 : atoi( args.Arg( 2 ) );
  589. RunTSListTests( nLengthList, nTests );
  590. }
  591. CON_COMMAND( thread_test_tsqueue, "" )
  592. {
  593. int nLengthList = ( args.ArgC() < 2 ) ? 10000 : atoi( args.Arg( 1 ) );
  594. int nTests = ( args.ArgC() < 3 ) ? 1 : atoi( args.Arg( 2 ) );
  595. RunTSQueueTests( nLengthList, nTests );
  596. }
  597. CON_COMMAND( threadpool_run_tests, "" )
  598. {
  599. int nTests = ( args.ArgC() == 1 ) ? 1 : atoi( args.Arg( 1 ) );
  600. for ( int i = 0; i < nTests; i++ )
  601. {
  602. RunThreadPoolTests();
  603. }
  604. }
  605. //-----------------------------------------------------------------------------
  606. /*
  607. A server can always be started, even if the system started out as a client
  608. to a remote system.
  609. A client can NOT be started if the system started as a dedicated server.
  610. Memory is cleared / released when a server or client begins, not when they end.
  611. */
  612. // Ear position + orientation
  613. #ifndef DEDICATED
  614. CAudioState s_AudioState;
  615. bool CAudioState::IsAnyPlayerUnderwater() const
  616. {
  617. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  618. {
  619. ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
  620. if ( GetPerUser().m_bIsUnderwater )
  621. return true;
  622. }
  623. return false;
  624. }
  625. AudioState_t &CAudioState::GetPerUser( int nSlot /*= -1*/ )
  626. {
  627. if ( nSlot == -1 )
  628. {
  629. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  630. return m_PerUser[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  631. }
  632. return m_PerUser[ nSlot ];
  633. }
  634. const AudioState_t &CAudioState::GetPerUser( int nSlot /*= -1*/ ) const
  635. {
  636. if ( nSlot == -1 )
  637. {
  638. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  639. return m_PerUser[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
  640. }
  641. return m_PerUser[ nSlot ];
  642. }
  643. #endif // DEDICATED
  644. engineparms_t host_parms;
  645. bool host_initialized = false; // true if into command execution
  646. float host_frametime = 0.0f;
  647. float host_frametime_unbounded = 0.0f;
  648. float host_frametime_stddeviation = 0.0f;
  649. float host_framestarttime_stddeviation = 0.0f;
  650. float host_frameendtime_computationduration = 0.0f;
  651. float host_frametime_unscaled = 0.0f;
  652. double realtime = 0; // without any filtering or bounding
  653. double host_idealtime = 0; // "ideal" server time assuming perfect tick rate
  654. float host_nexttick = 0; // next server tick in this many ms
  655. float host_jitterhistory[128] = { 0 };
  656. unsigned int host_jitterhistorypos = 0;
  657. int host_framecount;
  658. static int host_hunklevel;
  659. CGameClient *host_client; // current client
  660. jmp_buf host_abortserver;
  661. jmp_buf host_enddemo;
  662. static ConVar host_profile( "host_profile","0" );
  663. ConVar skill( "skill","1", FCVAR_ARCHIVE, "Game skill level (1-3).", true, 1, true, 3 ); // 1 - 3
  664. ConVar host_timescale( "host_timescale","1.0", FCVAR_REPLICATED | FCVAR_CHEAT, "Prescale the clock by this amount." );
  665. ConVar host_limitlocal( "host_limitlocal", "0", 0, "Apply cl_cmdrate and cl_updaterate to loopback connection" );
  666. ConVar host_framerate( "host_framerate","0", FCVAR_REPLICATED | FCVAR_CHEAT, "Set to lock per-frame time elapse." );
  667. ConVar host_speeds( "host_speeds","0", 0, "Show general system running times." ); // set for running times
  668. ConVar developer( "developer", "0", FCVAR_RELEASE, "Set developer message level");
  669. ConVar deathmatch( "deathmatch","0", FCVAR_NOTIFY, "Running a deathmatch server." ); // 0, 1, or 2
  670. ConVar coop( "coop","0", FCVAR_NOTIFY, "Cooperative play." ); // 0 or 1
  671. ConVar r_ForceRestore( "r_ForceRestore", "0", 0 );
  672. CON_COMMAND_F( display_elapsedtime, "Displays how much time has elapsed since the game started", FCVAR_CHEAT )
  673. {
  674. Msg( "Elapsed time: %.2f\n", realtime );
  675. }
  676. CON_COMMAND( host_timer_report, "Spew CPU timer jitter for the last 128 frames in microseconds (dedicated only)" )
  677. {
  678. if ( sv.IsDedicated() )
  679. {
  680. for (int i = 1; i <= ARRAYSIZE( host_jitterhistory ); ++i)
  681. {
  682. unsigned int slot = ( i + host_jitterhistorypos ) % ARRAYSIZE( host_jitterhistory );
  683. Msg( "%7d\n", ( int ) ( host_jitterhistory[ slot ] * 1000000 ) );
  684. }
  685. }
  686. }
  687. ConVar host_runframe_input_parcelremainder( "host_runframe_input_parcelremainder", "1" ); //putting this on a ConVar only because we're shipping so soon
  688. #ifndef DEDICATED
  689. void CL_CheckToDisplayStartupMenus(); // in cl_main.cpp
  690. #endif
  691. bool GetFileFromRemoteStorage( ISteamRemoteStorage *pRemoteStorage, const char *pszRemoteFileName, const char *pszLocalFileName, char const *pathID )
  692. {
  693. bool bSuccess = false;
  694. // check if file exists in Steam Cloud first
  695. int32 nFileSize = pRemoteStorage->GetFileSize( pszRemoteFileName );
  696. if ( nFileSize > 0 )
  697. {
  698. CUtlMemory<char> buf( 0, nFileSize );
  699. if ( pRemoteStorage->FileRead( pszRemoteFileName, buf.Base(), nFileSize ) == nFileSize )
  700. {
  701. FileHandle_t hFile = g_pFileSystem->Open( pszLocalFileName, "wb", pathID );
  702. if( hFile )
  703. {
  704. bSuccess = g_pFileSystem->Write( buf.Base(), nFileSize, hFile ) == nFileSize;
  705. g_pFileSystem->Close( hFile );
  706. if ( bSuccess )
  707. {
  708. DevMsg( "[Cloud]: SUCCEESS retrieved %s from remote storage into %s\n", pszRemoteFileName, pszLocalFileName );
  709. }
  710. else
  711. {
  712. DevMsg( "[Cloud]: FAILED retrieved %s from remote storage into %s\n", pszRemoteFileName, pszLocalFileName );
  713. }
  714. }
  715. }
  716. }
  717. return bSuccess;
  718. }
  719. void CCommonHostState::SetWorldModel( model_t *pModel )
  720. {
  721. if ( worldmodel == pModel )
  722. return;
  723. worldmodel = pModel;
  724. if ( pModel )
  725. {
  726. worldbrush = pModel->brush.pShared;
  727. }
  728. else
  729. {
  730. worldbrush = NULL;
  731. }
  732. }
  733. #ifndef DEDICATED
  734. void Host_SetAudioState( const AudioState_t &audioState )
  735. {
  736. memcpy( &s_AudioState.GetPerUser(), &audioState, sizeof(AudioState_t) );
  737. }
  738. #endif
  739. bool Host_IsLocalServer()
  740. {
  741. return sv.IsActive();
  742. }
  743. bool Host_IsSinglePlayerGame( void )
  744. {
  745. if ( sv.IsActive() )
  746. {
  747. return !sv.IsMultiplayer();
  748. }
  749. else
  750. {
  751. #ifdef DEDICATED
  752. return false;
  753. #else
  754. return GetBaseLocalClient().m_nMaxClients == 1;
  755. #endif
  756. }
  757. }
  758. /*
  759. ================
  760. Host_EndGame
  761. ================
  762. */
  763. void Host_EndGame (bool bShowMainMenu, const char *message, ...)
  764. {
  765. va_list argptr;
  766. char string[1024];
  767. va_start (argptr,message);
  768. Q_vsnprintf (string,sizeof(string),message,argptr);
  769. va_end (argptr);
  770. ConMsg ("Host_EndGame: %s\n",string);
  771. #ifndef DEDICATED
  772. scr_disabled_for_loading = true;
  773. int oldn = GetBaseLocalClient().demonum;
  774. GetBaseLocalClient().demonum = -1;
  775. #endif
  776. Host_Disconnect(bShowMainMenu);
  777. #ifndef DEDICATED
  778. GetBaseLocalClient().demonum = oldn;
  779. #endif
  780. if ( sv.IsDedicated() )
  781. {
  782. Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit
  783. return;
  784. }
  785. bool bDemoEnd = false;
  786. #ifndef DEDICATED
  787. if (GetBaseLocalClient().demonum != -1)
  788. {
  789. bDemoEnd = true;
  790. }
  791. #endif
  792. if ( bDemoEnd )
  793. {
  794. #ifndef DEDICATED
  795. CL_NextDemo ();
  796. #endif
  797. longjmp (host_enddemo, 1);
  798. }
  799. else
  800. {
  801. #ifndef DEDICATED
  802. scr_disabled_for_loading = false;
  803. #endif
  804. if ( g_bAbortServerSet )
  805. {
  806. longjmp (host_abortserver, 1);
  807. }
  808. }
  809. }
  810. /*
  811. ================
  812. Host_Error
  813. This shuts down both the client and server
  814. ================
  815. */
  816. void Host_Error (const char *error, ...)
  817. {
  818. va_list argptr;
  819. char string[1024];
  820. static bool inerror = false;
  821. if (inerror)
  822. {
  823. Sys_Error ("Host_Error: recursively entered");
  824. }
  825. inerror = true;
  826. #ifndef DEDICATED
  827. // CL_WriteMessageHistory(); TODO must be done by network layer
  828. #endif
  829. va_start (argptr,error);
  830. Q_vsnprintf(string,sizeof(string),error,argptr);
  831. va_end (argptr);
  832. if ( sv.IsDedicated() )
  833. {
  834. // dedicated servers just exit
  835. Sys_Error( "Host_Error: %s\n", string );
  836. return;
  837. }
  838. #ifndef DEDICATED
  839. // Reenable screen updates
  840. SCR_EndLoadingPlaque ();
  841. #endif
  842. ConMsg( "\nHost_Error: %s\n\n", string );
  843. Host_Disconnect(true);
  844. #ifndef DEDICATED
  845. GetBaseLocalClient().demonum = -1;
  846. #endif
  847. inerror = false;
  848. if ( g_bAbortServerSet )
  849. {
  850. longjmp (host_abortserver, 1);
  851. }
  852. }
  853. #ifndef DEDICATED
  854. class CHostSubscribeForProfileEvents : public IMatchEventsSink
  855. {
  856. public:
  857. CHostSubscribeForProfileEvents() : m_bSubscribed( false ) {}
  858. public:
  859. void Subscribe( bool bSubscribe );
  860. virtual void OnEvent( KeyValues *pEvent );
  861. public:
  862. bool m_bSubscribed;
  863. };
  864. void CHostSubscribeForProfileEvents::Subscribe( bool bSubscribe )
  865. {
  866. if ( bSubscribe == m_bSubscribed )
  867. return;
  868. if ( !g_pMatchFramework )
  869. return;
  870. if ( bSubscribe )
  871. g_pMatchFramework->GetEventsSubscription()->Subscribe( this );
  872. else
  873. g_pMatchFramework->GetEventsSubscription()->Unsubscribe( this );
  874. m_bSubscribed = bSubscribe;
  875. }
  876. void CHostSubscribeForProfileEvents::OnEvent( KeyValues *pEvent )
  877. {
  878. char const *szEvent = pEvent->GetName();
  879. if ( !Q_stricmp( szEvent, "OnProfileDataLoaded" ) )
  880. {
  881. int iController = pEvent->GetInt( "iController" );
  882. Host_ReadConfiguration( iController, false );
  883. }
  884. if ( !Q_stricmp( szEvent, "OnProfileDataLoadFailed" ) )
  885. {
  886. #if defined ( _X360 )
  887. int iController = pEvent->GetInt( "iController" );
  888. int iSlot = XBX_GetSlotByUserId( iController );
  889. ECommandMsgBoxSlot slot = CMB_SLOT_FULL_SCREEN;
  890. char cmdLine[80];
  891. if ( iSlot == 0 )
  892. {
  893. sprintf( cmdLine, "boot_to_start_and_reset_config 0" );
  894. slot = CMB_SLOT_PLAYER_0;
  895. }
  896. else
  897. {
  898. sprintf( cmdLine, "boot_to_start_and_reset_config 1" );
  899. slot = CMB_SLOT_PLAYER_1;
  900. }
  901. if ( !GetGameUI()->IsInLevel() )
  902. {
  903. slot = CMB_SLOT_FULL_SCREEN;
  904. }
  905. if ( !g_pXboxSystem->IsArcadeTitleUnlocked() )
  906. {
  907. GetGameUI()->CreateCommandMsgBoxInSlot(
  908. slot,
  909. "#SFUI_GameUI_ProfileDataLoadFailedTitle",
  910. "#SFUI_GameUI_ProfileDataLoadFailedTrialMsg",
  911. true,
  912. false,
  913. "boot_to_start",
  914. NULL,
  915. NULL,
  916. NULL );
  917. return;
  918. }
  919. GetGameUI()->CreateCommandMsgBoxInSlot(
  920. slot,
  921. "#SFUI_GameUI_ProfileDataLoadFailedTitle",
  922. "#SFUI_GameUI_ProfileDataLoadFailedMsg",
  923. true,
  924. true,
  925. cmdLine,
  926. "boot_to_start",
  927. NULL,
  928. NULL );
  929. #endif
  930. }
  931. if ( !Q_stricmp( szEvent, "OnProfileDataWriteFailed" ) )
  932. {
  933. #if defined ( _X360 )
  934. int iController = pEvent->GetInt( "iController" );
  935. int iSlot = XBX_GetSlotByUserId( iController );
  936. ECommandMsgBoxSlot slot = CMB_SLOT_FULL_SCREEN;
  937. if ( GetGameUI()->IsInLevel() )
  938. {
  939. if ( iSlot == 0 )
  940. {
  941. slot = CMB_SLOT_PLAYER_0;
  942. }
  943. else
  944. {
  945. slot = CMB_SLOT_PLAYER_1;
  946. }
  947. }
  948. // are we in trial mode?
  949. if ( !g_pXboxSystem->IsArcadeTitleUnlocked() )
  950. {
  951. GetGameUI()->CreateCommandMsgBoxInSlot(
  952. slot,
  953. "#SFUI_TrialMUPullTitle",
  954. "#SFUI_TrialMUPullMsg",
  955. true,
  956. false,
  957. "boot_to_start",
  958. NULL,
  959. NULL,
  960. NULL );
  961. return;
  962. }
  963. GetGameUI()->CreateCommandMsgBoxInSlot(
  964. slot,
  965. "#SFUI_GameUI_ProfileDataWriteFailedTitle",
  966. "#SFUI_GameUI_ProfileDataWriteFailedMsg",
  967. true,
  968. false,
  969. NULL,
  970. NULL,
  971. NULL,
  972. NULL );
  973. #endif
  974. }
  975. #if defined ( _X360 )
  976. else if ( !Q_stricmp( szEvent, "OnProfilesChanged" ) )
  977. {
  978. // $TODO(hpe) this needs reworked for split screen; currently, will reset configs for all players when one active player signs out
  979. Host_ResetGlobalConfiguration();
  980. for ( DWORD iSplitscreenSlot = 0; iSplitscreenSlot < XBX_GetNumGameUsers(); ++ iSplitscreenSlot )
  981. {
  982. Host_ResetConfiguration( XBX_GetUserId( iSplitscreenSlot ) );
  983. }
  984. }
  985. #endif
  986. #if defined ( _PS3 )
  987. else if ( !Q_stricmp( szEvent, "ResetConfiguration" ) )
  988. {
  989. int iController = pEvent->GetInt( "iController" );
  990. // $TODO(hpe) this needs reworked for split screen; currently, will reset configs for all players when one active player signs out
  991. Host_ResetGlobalConfiguration();
  992. Host_ResetConfiguration( iController );
  993. Host_WriteConfiguration( iController, "" );
  994. }
  995. #endif
  996. }
  997. #endif
  998. #ifdef _GAMECONSOLE
  999. void Console_UpdateNotificationPosition()
  1000. {
  1001. static ConVarRef closecaption( "closecaption" );
  1002. static ConVarRef cc_subtitles( "cc_subtitles" );
  1003. bool bSubtitled = ( ( closecaption.IsValid() && closecaption.GetBool() ) ||
  1004. ( cc_subtitles.IsValid() && cc_subtitles.GetBool() ) );
  1005. #ifdef _X360
  1006. XNotifyPositionUI( bSubtitled ? XNOTIFYUI_POS_TOPRIGHT : XNOTIFYUI_POS_BOTTOMCENTER );
  1007. Msg( "XNotifyPositionUI: %s\n", bSubtitled ? "TOPRIGHT" : "BOTTOMCENTER" );
  1008. #endif
  1009. }
  1010. #endif
  1011. void Host_SubscribeForProfileEvents( bool bSubscribe )
  1012. {
  1013. #ifndef DEDICATED
  1014. static CHostSubscribeForProfileEvents s_HostSubscribeForProfileEvents;
  1015. s_HostSubscribeForProfileEvents.Subscribe( bSubscribe );
  1016. #endif
  1017. }
  1018. #ifndef DEDICATED
  1019. //******************************************
  1020. // UseDefuaultBinding
  1021. //
  1022. // If the config.cfg file is not present, this
  1023. // function is called to set the default key
  1024. // bindings to match those defined in kb_def.lst
  1025. //******************************************
  1026. void UseDefaultBindings( void )
  1027. {
  1028. FileHandle_t f;
  1029. char szFileName[ _MAX_PATH ];
  1030. char token[ 1024 ];
  1031. char szKeyName[ 256 ];
  1032. // read kb_def file to get default key binds
  1033. Q_snprintf( szFileName, sizeof( szFileName ), "%skb_def.lst", SCRIPT_DIR );
  1034. f = g_pFileSystem->Open( szFileName, "r");
  1035. if ( !f )
  1036. {
  1037. ConMsg( "Couldn't open kb_def.lst\n" );
  1038. return;
  1039. }
  1040. // read file into memory
  1041. int size = g_pFileSystem->Size(f);
  1042. char *startbuf = new char[ size ];
  1043. g_pFileSystem->Read( startbuf, size, f );
  1044. g_pFileSystem->Close( f );
  1045. const char *buf = startbuf;
  1046. while ( 1 )
  1047. {
  1048. buf = COM_ParseFile( buf, token, sizeof( token ) );
  1049. if ( strlen( token ) <= 0 )
  1050. break;
  1051. Q_strncpy ( szKeyName, token, sizeof( szKeyName ) );
  1052. buf = COM_ParseFile( buf, token, sizeof( token ) );
  1053. if ( strlen( token ) <= 0 ) // Error
  1054. break;
  1055. // finally, bind key
  1056. Key_SetBinding ( g_pInputSystem->StringToButtonCode( szKeyName ), token );
  1057. }
  1058. delete [] startbuf; // cleanup on the way out
  1059. }
  1060. static bool g_bConfigCfgExecuted[MAX_SPLITSCREEN_CLIENTS];
  1061. enum SyncCvarValueWithPlayerTitleDataPolicy_t
  1062. {
  1063. CVARWRITETD,
  1064. CVARREADTD
  1065. };
  1066. static void SyncCvarValueWithPlayerTitleData( IPlayerLocal *pPlayer, ConVar *cv, TitleDataFieldsDescription_t const *pField, SyncCvarValueWithPlayerTitleDataPolicy_t eCV )
  1067. {
  1068. switch( pField->m_eDataType )
  1069. {
  1070. case TitleDataFieldsDescription_t::DT_float:
  1071. if ( eCV == CVARWRITETD )
  1072. TitleDataFieldsDescriptionSetValue<float>( pField, pPlayer, cv->GetFloat() );
  1073. else if ( eCV == CVARREADTD )
  1074. cv->SetValue( TitleDataFieldsDescriptionGetValue<float>( pField, pPlayer ) );
  1075. break;
  1076. case TitleDataFieldsDescription_t::DT_uint32:
  1077. if ( eCV == CVARWRITETD )
  1078. TitleDataFieldsDescriptionSetValue<int32>( pField, pPlayer, cv->GetInt() );
  1079. else if ( eCV == CVARREADTD )
  1080. cv->SetValue( TitleDataFieldsDescriptionGetValue<int32>( pField, pPlayer ) );
  1081. break;
  1082. case TitleDataFieldsDescription_t::DT_uint16:
  1083. if ( eCV == CVARWRITETD )
  1084. TitleDataFieldsDescriptionSetValue<int16>( pField, pPlayer, cv->GetInt() );
  1085. else if ( eCV == CVARREADTD )
  1086. cv->SetValue( TitleDataFieldsDescriptionGetValue<int16>( pField, pPlayer ) );
  1087. break;
  1088. case TitleDataFieldsDescription_t::DT_uint8:
  1089. if ( eCV == CVARWRITETD )
  1090. TitleDataFieldsDescriptionSetValue<int8>( pField, pPlayer, cv->GetInt() );
  1091. else if ( eCV == CVARREADTD )
  1092. cv->SetValue( TitleDataFieldsDescriptionGetValue<int8>( pField, pPlayer ) );
  1093. break;
  1094. case TitleDataFieldsDescription_t::DT_BITFIELD:
  1095. if ( eCV == CVARWRITETD )
  1096. TitleDataFieldsDescriptionSetBit( pField, pPlayer, cv->GetBool() );
  1097. else if ( eCV == CVARREADTD )
  1098. cv->SetValue( !!TitleDataFieldsDescriptionGetBit( pField, pPlayer ) );
  1099. break;
  1100. }
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose: Write out our 360 exclusive settings to internal storage
  1104. //-----------------------------------------------------------------------------
  1105. void Host_WriteConfiguration_Console( const int iController, bool bVideoConfig )
  1106. {
  1107. // sb: FIXME(hpe) only write if we had a valid read so we don't accidentally wipe out valid data
  1108. #ifdef _GAMECONSOLE
  1109. DevMsg( "Host_WriteConfiguration_Console for ctrlr%d (%s)\n", iController, bVideoConfig ? "video" : "controls" );
  1110. if ( iController < 0 )
  1111. return;
  1112. if ( !g_pMatchFramework || !g_pMatchFramework->GetMatchTitle() )
  1113. return;
  1114. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController );
  1115. if ( !pPlayer )
  1116. return;
  1117. #if defined ( _X360 )
  1118. if ( !pPlayer->IsTitleDataValid() )
  1119. return;
  1120. #endif
  1121. #ifndef GAME_DLL
  1122. if ( g_pXboxSystem->IsArcadeTitleUnlocked() )
  1123. {
  1124. IGameEvent *event = g_GameEventManager.CreateEvent( "write_game_titledata" );
  1125. if ( event )
  1126. {
  1127. event->SetInt( "controllerId", iController );
  1128. g_GameEventManager.FireEventClientSide( event );
  1129. }
  1130. }
  1131. #endif
  1132. int iSlot = XBX_GetSlotByUserId( iController );
  1133. // check version number for title data block 3
  1134. TitleDataFieldsDescription_t const *fields = g_pMatchFramework->GetMatchTitle()->DescribeTitleDataStorage();
  1135. if ( !fields )
  1136. return;
  1137. #if defined ( _X360 )
  1138. TitleDataFieldsDescription_t const *versionField = TitleDataFieldsDescriptionFindByString( fields, "TITLEDATA.BLOCK3.VERSION" );
  1139. if ( !versionField || versionField->m_eDataType != TitleDataFieldsDescription_t::DT_uint16)
  1140. {
  1141. Warning( "Host_WriteConfiguration_Console missing or incorrect type TITLEDATA.BLOCK3.VERSION\n" );
  1142. return;
  1143. }
  1144. ConVarRef cl_titledataversionblock3 ( "cl_titledataversionblock3" );
  1145. TitleDataFieldsDescriptionSetValue<uint16>( versionField, pPlayer, cl_titledataversionblock3.GetInt() );
  1146. #endif
  1147. // On consoles - store guest user's convars in primary user's profile data
  1148. char const *szUsrField = "";
  1149. if ( XBX_GetUserIsGuest( iSlot ) && !bVideoConfig )
  1150. {
  1151. IPlayerLocal *pPlayerPrimary = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( XBX_GetPrimaryUserId() );
  1152. if ( pPlayerPrimary )
  1153. {
  1154. if ( TitleDataFieldsDescription_t const *pOffset = TitleDataFieldsDescriptionFindByString( fields, TITLE_DATA_PREFIX "CFG.usrSS.version" ) )
  1155. {
  1156. pPlayer = pPlayerPrimary;
  1157. szUsrField = "SS";
  1158. }
  1159. }
  1160. }
  1161. int numLoops = 1;
  1162. #if defined (CSTRIKE15)
  1163. // Console CStrike15 we want to always save both usr and sys Convars
  1164. numLoops = 2;
  1165. #endif
  1166. for ( int loopCount=0; loopCount<numLoops; ++loopCount )
  1167. {
  1168. // second pass toggle bVideoConfig to go from sys to usr or vice versa
  1169. if ( loopCount == 1 )
  1170. bVideoConfig = !bVideoConfig;
  1171. CUtlVector< ConVar * > arrCVars;
  1172. cv->WriteVariables( NULL, iSlot, !bVideoConfig, &arrCVars );
  1173. for ( int k = 0; k < arrCVars.Count(); ++ k )
  1174. {
  1175. ConVar *cvSave = arrCVars[k];
  1176. char const *cvSaveName = cvSave->GetBaseName();
  1177. CFmtStr sFieldLookup( TITLE_DATA_PREFIX "CFG.%s%s.%s", bVideoConfig ? "sys" : "usr", szUsrField, cvSaveName );
  1178. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( fields, sFieldLookup );
  1179. if ( !pField )
  1180. {
  1181. Warning( "Host_WriteConfiguration_Console (%s#%d) - cannot save cvar %s\n", bVideoConfig ? "video" : "ctrlr", iController, cvSaveName );
  1182. continue;
  1183. }
  1184. SyncCvarValueWithPlayerTitleData( pPlayer, cvSave, pField, CVARWRITETD );
  1185. }
  1186. // reset the input parameter
  1187. if ( loopCount == 1 )
  1188. bVideoConfig = !bVideoConfig;
  1189. }
  1190. // Update the version number for the settings. This is the main version number for PS3.
  1191. if ( TitleDataFieldsDescription_t const *pVersion = TitleDataFieldsDescriptionFindByString( fields, TITLE_DATA_PREFIX "CFG.sys.version" ) )
  1192. {
  1193. TitleDataFieldsDescriptionSetValue<int32>( pVersion, pPlayer, cl_configversion.GetInt() );
  1194. }
  1195. // Let the player manager save the user data
  1196. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnProfilesWriteOpportunity", "reason", "settings" ) );
  1197. // Update notifications position
  1198. Console_UpdateNotificationPosition();
  1199. #endif // #ifdef _GAMECONSOLE
  1200. }
  1201. bool Host_WasConfigCfgExecuted( const int iController )
  1202. {
  1203. int iIndex = iController;
  1204. if ( iIndex < 0 )
  1205. iIndex = 0;
  1206. Assert( iIndex >= 0 && iIndex < MAX_SPLITSCREEN_CLIENTS );
  1207. return g_bConfigCfgExecuted[iIndex];
  1208. }
  1209. void Host_SetConfigCfgExecuted( const int iController, bool bExecuted = true )
  1210. {
  1211. int iIndex = iController;
  1212. if ( iIndex < 0 )
  1213. iIndex = 0;
  1214. Assert( iIndex >= 0 && iIndex < MAX_SPLITSCREEN_CLIENTS );
  1215. g_bConfigCfgExecuted[iIndex] = bExecuted;
  1216. }
  1217. void Host_ResetGlobalConfiguration()
  1218. {
  1219. #ifdef _GAMECONSOLE
  1220. ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
  1221. #endif
  1222. #ifndef _GAMECONSOLE
  1223. // We exec our global default configuration for non-consoles
  1224. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec config.global" PLATFORM_EXT ".cfg game\n" );
  1225. Cbuf_Execute();
  1226. #else
  1227. CUtlVector< ConVar * > arrCVars;
  1228. cv->WriteVariables( NULL, 0, false, &arrCVars );
  1229. for ( int k = 0; k < arrCVars.Count(); ++ k )
  1230. {
  1231. ConVar *cvSave = arrCVars[k];
  1232. cvSave->Revert();
  1233. DevMsg( "Console reset global configuration: %s = \"%s\"\n", cvSave->GetName(), cvSave->GetString() );
  1234. }
  1235. #endif
  1236. #ifdef _GAMECONSOLE
  1237. // Update notifications position
  1238. Console_UpdateNotificationPosition();
  1239. #endif
  1240. }
  1241. void Host_ResetConfiguration( const int iController )
  1242. {
  1243. #if defined ( _GAMECONSOLE )
  1244. #ifndef SPLIT_SCREEN_STUBS
  1245. int iSlot = XBX_GetSlotByUserId( iController );
  1246. ACTIVE_SPLITSCREEN_PLAYER_GUARD( iSlot );
  1247. #endif
  1248. // First, we exec our default configuration
  1249. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec config" PLATFORM_EXT ".cfg game\n" );
  1250. Cbuf_Execute();
  1251. #if defined ( _X360 )
  1252. // This will wipe out all achievement and stats but they'll be loaded from the xlast title data sync.
  1253. IGameEvent *event = g_GameEventManager.CreateEvent( "reset_game_titledata" );
  1254. if ( event )
  1255. {
  1256. event->SetInt( "controllerId", iController );
  1257. g_GameEventManager.FireEventClientSide( event );
  1258. }
  1259. // Get and set all our default setting we care about from the Xbox
  1260. XBX_SetProfileDefaultSettings( iController );
  1261. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController );
  1262. if ( pPlayer )
  1263. {
  1264. pPlayer->SetIsTitleDataValid( true );
  1265. }
  1266. #else
  1267. #if defined( _PS3 )
  1268. char szScratch[MAX_PATH];
  1269. int iAllDevices = -1;
  1270. Q_snprintf( szScratch, sizeof(szScratch), "cl_reset_ps3_bindings %d %d", iController, iAllDevices );
  1271. Cbuf_AddText( Cbuf_GetCurrentPlayer(), szScratch );
  1272. Cbuf_Execute();
  1273. #endif // _PS3
  1274. // Get and set all our default setting we care about.
  1275. XBX_SetProfileDefaultSettings( iController );
  1276. #endif // _X360
  1277. #endif // _GAMECONSOLE
  1278. }
  1279. /*
  1280. ===============
  1281. Host_WriteConfiguration
  1282. Writes key bindings and archived cvars to config.cfg
  1283. ===============
  1284. */
  1285. void Host_WriteConfiguration( const int iController, const char *filename )
  1286. {
  1287. // Set the joystick being force disabled just as we write the config
  1288. // This allows us to chose this option in the menu with a controller without accidentally disabling our only mode of input
  1289. static ConVarRef joystick_force_disabled( "joystick_force_disabled" );
  1290. static ConVarRef joystick_force_disabled_set_from_options( "joystick_force_disabled_set_from_options" );
  1291. if ( joystick_force_disabled.IsValid() && joystick_force_disabled_set_from_options.IsValid() )
  1292. {
  1293. if ( joystick_force_disabled.GetBool() != joystick_force_disabled_set_from_options.GetBool() )
  1294. {
  1295. joystick_force_disabled.SetValue( joystick_force_disabled_set_from_options.GetBool() );
  1296. }
  1297. }
  1298. if ( !filename )
  1299. filename = "config.cfg";
  1300. // Write to internal storage on the 360
  1301. if ( IsGameConsole() )
  1302. {
  1303. Host_WriteConfiguration_Console( iController, false );
  1304. return;
  1305. }
  1306. if ( !host_initialized )
  1307. {
  1308. return;
  1309. }
  1310. if ( Host_WasConfigCfgExecuted( iController ) == false )
  1311. {
  1312. return;
  1313. }
  1314. // If in map editing mode don't save configuration
  1315. if (g_bInEditMode)
  1316. {
  1317. ConMsg( "skipping %s output when in map edit mode\n", filename );
  1318. return;
  1319. }
  1320. // dedicated servers initialize the host but don't parse and set the
  1321. // config.cfg cvars
  1322. if ( !sv.IsDedicated() )
  1323. {
  1324. if ( IsPC() && Key_CountBindings() <= 1 )
  1325. {
  1326. ConMsg( "skipping %s output, no keys bound\n", filename );
  1327. return;
  1328. }
  1329. // force any queued convar changes to flush before reading/writing them
  1330. UpdateMaterialSystemConfig();
  1331. // Generate a new .cfg file.
  1332. char szFileName[MAX_PATH];
  1333. CUtlBuffer configBuff( 0, 0, CUtlBuffer::TEXT_BUFFER);
  1334. Q_snprintf( szFileName, sizeof(szFileName), "cfg/%s", filename );
  1335. g_pFileSystem->CreateDirHierarchy( "cfg", "USRLOCAL" );
  1336. if ( g_pFileSystem->FileExists( szFileName, "USRLOCAL" ) && !g_pFileSystem->IsFileWritable( szFileName, "USRLOCAL" ) )
  1337. {
  1338. ConMsg( "Config file %s is read-only!!\n", szFileName );
  1339. return;
  1340. }
  1341. // Always throw away all keys that are left over.
  1342. configBuff.Printf( "unbindall\n" );
  1343. Key_WriteBindings( configBuff );
  1344. ConVarUtilities->WriteVariables( &configBuff );
  1345. #if !defined( DEDICATED )
  1346. bool down;
  1347. for ( int hh = 0; hh < host_state.max_splitscreen_players; ++hh )
  1348. {
  1349. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  1350. if ( g_ClientDLL->IN_IsKeyDown( "in_jlook", down ) && down )
  1351. {
  1352. configBuff.Printf( "cmd%d +jlook\n", hh+1 );
  1353. }
  1354. }
  1355. #endif // DEDICATED
  1356. if ( !configBuff.TellMaxPut() )
  1357. {
  1358. // nothing to write
  1359. return;
  1360. }
  1361. #if defined(NO_STEAM)
  1362. AssertMsg( false, "SteamCloud not available on Xbox 360. Badger Martin to fix this." );
  1363. #else
  1364. ISteamRemoteStorage *pRemoteStorage =
  1365. #ifdef _PS3
  1366. ::SteamRemoteStorage();
  1367. #else
  1368. Steam3Client().SteamClient() ? (ISteamRemoteStorage *) Steam3Client().SteamClient()->GetISteamGenericInterface(
  1369. SteamAPI_GetHSteamUser(), SteamAPI_GetHSteamPipe(), STEAMREMOTESTORAGE_INTERFACE_VERSION ):NULL;
  1370. #endif
  1371. if ( pRemoteStorage )
  1372. {
  1373. int32 availableBytes, totalBytes = 0;
  1374. if ( pRemoteStorage->GetQuota( &totalBytes, &availableBytes ) )
  1375. {
  1376. if ( totalBytes > 0 )
  1377. {
  1378. if ( cl_cloud_settings.GetInt() != -1 && ( cl_cloud_settings.GetInt() & STEAMREMOTESTORAGE_CLOUD_CONFIG ) )
  1379. {
  1380. // TODO put MOD dir in pathname
  1381. if ( pRemoteStorage->FileWrite( szFileName, configBuff.Base(), configBuff.TellMaxPut() ) )
  1382. {
  1383. // Refresh local copy so that on next game boot Host_ReadPreStartupConfiguration() will avoid loading the stale config.cfg
  1384. // which will only get downloaded & refreshed later during Host_ReadConfiguration()
  1385. GetFileFromRemoteStorage( pRemoteStorage, "cfg/config.cfg", "cfg/config.cfg", "USRLOCAL" );
  1386. DevMsg( "[Cloud]: SUCCEESS saving %s in remote storage\n", szFileName );
  1387. }
  1388. else
  1389. {
  1390. // probably a quota issue. TODO what to do ?
  1391. DevMsg( "[Cloud]: FAILED saving %s in remote storage\n", szFileName );
  1392. }
  1393. }
  1394. }
  1395. }
  1396. // even if SteamCloud worked we still safe the same file locally
  1397. }
  1398. #endif
  1399. // make a persistent copy that async will use and free
  1400. char *tempBlock = new char[configBuff.TellMaxPut()];
  1401. Q_memcpy( tempBlock, configBuff.Base(), configBuff.TellMaxPut() );
  1402. // async write the buffer, and then free it
  1403. char szFileNameToWriteLocal[MAX_PATH] = {};
  1404. g_pFileSystem->GetSearchPath( "USRLOCAL", false, szFileNameToWriteLocal, sizeof( szFileNameToWriteLocal ) );
  1405. V_strcat_safe( szFileNameToWriteLocal, szFileName );
  1406. g_pFileSystem->AsyncWrite( szFileNameToWriteLocal, tempBlock, configBuff.TellMaxPut(), true );
  1407. ConMsg( "Host_WriteConfiguration: Wrote %s\n", szFileName );
  1408. }
  1409. }
  1410. //-----------------------------------------------------------------------------
  1411. // Purpose: Retrieve and set any defaults from the user's gamer profile
  1412. //-----------------------------------------------------------------------------
  1413. bool XBX_SetProfileDefaultSettings( int iController )
  1414. {
  1415. // These defined values can't play nicely with the PC, so we need to ignore them for that build target
  1416. #ifdef _GAMECONSOLE
  1417. UserProfileData upd = {0};
  1418. if ( IPlayerLocal *pPlayerLocal = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController ) )
  1419. {
  1420. upd = pPlayerLocal->GetPlayerProfileData();
  1421. }
  1422. //
  1423. // Skill
  1424. //
  1425. int nSkillSetting = upd.difficulty;
  1426. int nResultSkill = 2;
  1427. #ifdef _X360
  1428. switch( nSkillSetting )
  1429. {
  1430. case XPROFILE_GAMER_DIFFICULTY_HARD:
  1431. nResultSkill = 3;
  1432. break;
  1433. case XPROFILE_GAMER_DIFFICULTY_EASY:
  1434. default:
  1435. nResultSkill = 1;
  1436. break;
  1437. }
  1438. #endif
  1439. // If the mod has no difficulty setting, only easy is allowed
  1440. KeyValues *modinfo = new KeyValues("ModInfo");
  1441. if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) )
  1442. {
  1443. if ( stricmp(modinfo->GetString("nodifficulty", "0"), "1") == 0 )
  1444. nResultSkill = 1;
  1445. }
  1446. modinfo->deleteThis();
  1447. char szScratch[MAX_PATH];
  1448. Q_snprintf( szScratch, sizeof(szScratch), "skill %d", nResultSkill );
  1449. Cbuf_AddText( Cbuf_GetCurrentPlayer(), szScratch );
  1450. //
  1451. // Movement control
  1452. //
  1453. int nMovementControl = !!upd.action_movementcontrol;
  1454. Q_snprintf( szScratch, sizeof(szScratch), "joy_movement_stick %d", nMovementControl );
  1455. Cbuf_AddText( Cbuf_GetCurrentPlayer(), szScratch );
  1456. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "joyadvancedupdate" );
  1457. //
  1458. // Y-Inversion
  1459. //
  1460. int nYinvert = !!upd.yaxis;
  1461. Q_snprintf( szScratch, sizeof(szScratch), "joy_inverty %d", nYinvert );
  1462. Cbuf_AddText( Cbuf_GetCurrentPlayer(), szScratch );
  1463. //
  1464. // Vibration control
  1465. //
  1466. int nVibration = !!upd.vibration;
  1467. Q_snprintf( szScratch, sizeof(szScratch), "cl_rumblescale %d", nVibration );
  1468. Cbuf_AddText( Cbuf_GetCurrentPlayer(), szScratch );
  1469. // Execute all commands we've queued up
  1470. Cbuf_Execute();
  1471. #endif // _GAMECONSOLE
  1472. return true;
  1473. }
  1474. //-----------------------------------------------------------------------------
  1475. // Purpose: Read our configuration from the 360, filling in defaults on our first run
  1476. //-----------------------------------------------------------------------------
  1477. void Host_ReadConfiguration_Console( const int iController )
  1478. {
  1479. #ifdef _GAMECONSOLE
  1480. if ( iController < 0 )
  1481. return;
  1482. int iSlot = XBX_GetSlotByUserId( iController );
  1483. DevMsg( "Host_ReadConfiguration_Console maps ctrlr%d to slot%d\n", iController, iSlot );
  1484. if ( !g_pMatchFramework || !g_pMatchFramework->GetMatchTitle() )
  1485. return;
  1486. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController );
  1487. if ( !pPlayer )
  1488. return;
  1489. TitleDataFieldsDescription_t const *fields = g_pMatchFramework->GetMatchTitle()->DescribeTitleDataStorage();
  1490. if ( !fields )
  1491. return;
  1492. #if defined( _X360 )
  1493. Host_ResetConfiguration( iController );
  1494. // dont read any config info if the load was not valid
  1495. if ( !pPlayer->IsTitleDataValid() )
  1496. return;
  1497. // if the trial block is fresh, reset the trial timer to clear out any previous signed in players time
  1498. if ( !pPlayer->IsTitleDataBlockValid( 2 ) )
  1499. {
  1500. SplitScreenConVarRef xbox_arcade_remaining_trial_time("xbox_arcade_remaining_trial_time");
  1501. xbox_arcade_remaining_trial_time.SetValue( iSlot, xbox_arcade_remaining_trial_time.GetDefault() );
  1502. }
  1503. if ( pPlayer->IsFreshPlayerProfile() )
  1504. return;
  1505. #ifndef GAME_DLL
  1506. if ( pPlayer->IsTitleDataBlockValid( 0 ) && pPlayer->IsTitleDataBlockValid( 1 ) )
  1507. {
  1508. IGameEvent *event = g_GameEventManager.CreateEvent( "read_game_titledata" );
  1509. if ( event )
  1510. {
  1511. event->SetInt( "controllerId", iController );
  1512. g_GameEventManager.FireEventClientSide( event );
  1513. }
  1514. }
  1515. #endif //GAME_DLL
  1516. // check version numbers
  1517. ConVarRef cl_titledataversionblock3 ( "cl_titledataversionblock3" );
  1518. TitleDataFieldsDescription_t const *versionField3 = TitleDataFieldsDescriptionFindByString( fields, "TITLEDATA.BLOCK3.VERSION" );
  1519. #if !defined( _CERT )
  1520. // check to see if profile versions match; reset if not
  1521. ConVarRef cl_titledataversionblock1 ( "cl_titledataversionblock1" );
  1522. ConVarRef cl_titledataversionblock2 ( "cl_titledataversionblock2" );
  1523. TitleDataFieldsDescription_t const *versionField1 = TitleDataFieldsDescriptionFindByString( fields, "TITLEDATA.BLOCK1.VERSION" );
  1524. if ( !versionField1 || versionField1->m_eDataType != TitleDataFieldsDescription_t::DT_uint16)
  1525. {
  1526. Warning( "Host_ReadConfiguration_Console missing or incorrect type TITLEDATA.BLOCK1.VERSION\n" );
  1527. return;
  1528. }
  1529. TitleDataFieldsDescription_t const *versionField2 = TitleDataFieldsDescriptionFindByString( fields, "TITLEDATA.BLOCK2.VERSION" );
  1530. if ( !versionField2 || versionField2->m_eDataType != TitleDataFieldsDescription_t::DT_uint16)
  1531. {
  1532. Warning( "Host_ReadConfiguration_Console missing or incorrect type TITLEDATA.BLOCK2.VERSION\n" );
  1533. return;
  1534. }
  1535. bool versionValid = true;
  1536. if ( g_pXboxSystem->IsArcadeTitleUnlocked() )
  1537. {
  1538. if ( ( pPlayer->IsTitleDataBlockValid( 0 ) && cl_titledataversionblock1.GetInt() != TitleDataFieldsDescriptionGetValue<uint16>( versionField1, pPlayer ) ) ||
  1539. ( pPlayer->IsTitleDataBlockValid( 1 ) && cl_titledataversionblock2.GetInt() != TitleDataFieldsDescriptionGetValue<uint16>( versionField2, pPlayer ) ) ||
  1540. ( pPlayer->IsTitleDataBlockValid( 2 ) && cl_titledataversionblock3.GetInt() != TitleDataFieldsDescriptionGetValue<uint16>( versionField3, pPlayer ) ) )
  1541. {
  1542. versionValid = false;
  1543. }
  1544. }
  1545. else
  1546. {
  1547. if ( pPlayer->IsTitleDataBlockValid( 2 ) && cl_titledataversionblock3.GetInt() != TitleDataFieldsDescriptionGetValue<uint16>( versionField3, pPlayer ) )
  1548. {
  1549. versionValid = false;
  1550. }
  1551. }
  1552. if ( !versionValid )
  1553. {
  1554. Warning( "ProfileVersion is out of date; your profile has been reset\n" );
  1555. // zero out title data buffer to remove any stale data since we are basically nuking this profile data
  1556. IPlayerLocal *pPlayer = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( iController );
  1557. if ( pPlayer )
  1558. {
  1559. pPlayer->ClearBufTitleData();
  1560. }
  1561. Host_ResetConfiguration( iController );
  1562. Host_WriteConfiguration( iController, "" );
  1563. GetGameUI()->ShowMessageDialog( "Your profile version was out of date; the profile has been reset.", "Profile Version Mismatch" );
  1564. return;
  1565. }
  1566. #endif // !_CERT
  1567. if ( !versionField3 || versionField3->m_eDataType != TitleDataFieldsDescription_t::DT_uint16)
  1568. {
  1569. Warning( "Host_ReadConfiguration_Console missing or incorrect type TITLEDATA.BLOCK3.VERSION\n" );
  1570. return;
  1571. }
  1572. if ( cl_titledataversionblock3.GetInt() != TitleDataFieldsDescriptionGetValue<uint16>( versionField3, pPlayer ) )
  1573. {
  1574. Warning( "Host_ReadConfiguration_Console wrong version number for TITLEDATA.BLOCK3.VERSION; expected %d, got %d\n",
  1575. cl_titledataversionblock3.GetInt(), TitleDataFieldsDescriptionGetValue<uint16>( versionField3, pPlayer ) );
  1576. return;
  1577. }
  1578. #else
  1579. // If not on 360, we read the game title data reguardless.
  1580. IGameEvent *event = g_GameEventManager.CreateEvent( "read_game_titledata" );
  1581. if ( event )
  1582. {
  1583. event->SetInt( "controllerId", iController );
  1584. g_GameEventManager.FireEventClientSide( event );
  1585. }
  1586. #endif // _X360
  1587. // usr data
  1588. {
  1589. bool bVideoConfig = false;
  1590. char const *szUsrField = "";
  1591. if ( XBX_GetUserIsGuest( iSlot ) && !bVideoConfig )
  1592. {
  1593. IPlayerLocal *pPlayerPrimary = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( XBX_GetPrimaryUserId() );
  1594. if ( pPlayerPrimary )
  1595. {
  1596. if ( TitleDataFieldsDescription_t const *pOffset = TitleDataFieldsDescriptionFindByString( fields, TITLE_DATA_PREFIX "CFG.usrSS.version" ) )
  1597. {
  1598. pPlayer = pPlayerPrimary;
  1599. szUsrField = "SS";
  1600. }
  1601. }
  1602. }
  1603. bool bConfigVersionValid = true;
  1604. CUtlVector< ConVar * > arrCVars;
  1605. cv->WriteVariables( NULL, iSlot, !bVideoConfig, &arrCVars );
  1606. if ( bConfigVersionValid )
  1607. {
  1608. for ( int k = 0; k < arrCVars.Count(); ++ k )
  1609. {
  1610. ConVar *cvSave = arrCVars[k];
  1611. char const *cvSaveName = cvSave->GetBaseName();
  1612. CFmtStr sFieldLookup( TITLE_DATA_PREFIX "CFG.%s%s.%s", bVideoConfig ? "sys" : "usr", szUsrField, cvSaveName );
  1613. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( fields, sFieldLookup );
  1614. if ( !pField )
  1615. {
  1616. Warning( "Host_ReadConfiguration_Console (%s#%d) - cannot read cvar %s\n", bVideoConfig ? "video" : "ctrlr", iController, cvSaveName );
  1617. continue;
  1618. }
  1619. SyncCvarValueWithPlayerTitleData( pPlayer, cvSave, pField, CVARREADTD );
  1620. if ( !Q_stricmp( cvSaveName, "joy_cfg_preset" ) ) // special code to handle joystick config presets
  1621. {
  1622. Cbuf_AddText( Cbuf_GetCurrentPlayer(), CFmtStr( "cmd%d exec joy_preset_%d" PLATFORM_EXT ".cfg\n", iSlot + 1, cvSave->GetInt() ) );
  1623. }
  1624. }
  1625. }
  1626. }
  1627. // sys data
  1628. if ( !XBX_GetUserIsGuest( iSlot ) && ( XBX_GetPrimaryUserId() == iController ) )
  1629. {
  1630. bool bVideoConfig = true;
  1631. char const *szUsrField = "";
  1632. bool bConfigVersionValid = true;
  1633. CUtlVector< ConVar * > arrCVars;
  1634. cv->WriteVariables( NULL, iSlot, !bVideoConfig, &arrCVars );
  1635. if ( bConfigVersionValid )
  1636. {
  1637. for ( int k = 0; k < arrCVars.Count(); ++ k )
  1638. {
  1639. ConVar *cvSave = arrCVars[k];
  1640. char const *cvSaveName = cvSave->GetBaseName();
  1641. CFmtStr sFieldLookup( TITLE_DATA_PREFIX "CFG.%s%s.%s", bVideoConfig ? "sys" : "usr", szUsrField, cvSaveName );
  1642. TitleDataFieldsDescription_t const *pField = TitleDataFieldsDescriptionFindByString( fields, sFieldLookup );
  1643. if ( !pField )
  1644. {
  1645. Warning( "Host_ReadConfiguration_Console (%s#%d) - cannot read cvar %s\n", bVideoConfig ? "video" : "ctrlr", iController, cvSaveName );
  1646. continue;
  1647. }
  1648. SyncCvarValueWithPlayerTitleData( pPlayer, cvSave, pField, CVARREADTD );
  1649. }
  1650. }
  1651. }
  1652. // Update notifications position
  1653. Console_UpdateNotificationPosition();
  1654. #endif // _GAMECONSOLE
  1655. }
  1656. //-----------------------------------------------------------------------------
  1657. // Purpose:
  1658. // Input : false -
  1659. //-----------------------------------------------------------------------------
  1660. void Host_ReadConfiguration( const int iController, const bool readDefault )
  1661. {
  1662. if ( sv.IsDedicated() )
  1663. return;
  1664. // Rebind keys and set cvars
  1665. if ( !g_pFileSystem )
  1666. {
  1667. Sys_Error( "Host_ReadConfiguration: g_pFileSystem == NULL\n" );
  1668. }
  1669. // Handle the console case
  1670. #ifdef _GAMECONSOLE
  1671. {
  1672. Host_ReadConfiguration_Console( iController );
  1673. return;
  1674. }
  1675. #else
  1676. bool saveconfig = false;
  1677. ISteamRemoteStorage *pRemoteStorage = Steam3Client().SteamClient() ? (ISteamRemoteStorage *)Steam3Client().SteamClient()->GetISteamGenericInterface(
  1678. SteamAPI_GetHSteamUser(), SteamAPI_GetHSteamPipe(), STEAMREMOTESTORAGE_INTERFACE_VERSION ):NULL;
  1679. if ( pRemoteStorage )
  1680. {
  1681. // if cloud settings is default but remote storage does not exist yet, set it to sync all because this is the first
  1682. // computer the game is run on--default to copying everything to the cloud
  1683. if ( cl_cloud_settings.GetInt() == -1 && !pRemoteStorage->FileExists( "cfg/config.cfg" ) )
  1684. {
  1685. DevMsg( "[Cloud]: Default setting with remote data non-existent, sync all\n" );
  1686. cl_cloud_settings.SetValue( STEAMREMOTESTORAGE_CLOUD_ALL );
  1687. }
  1688. if ( cl_cloud_settings.GetInt() != -1 && ( cl_cloud_settings.GetInt() & STEAMREMOTESTORAGE_CLOUD_CONFIG ) )
  1689. {
  1690. // config files are run through the exec command which got pretty complicated with all the splitscreen
  1691. // stuff. Steam UFS doens't support split screen well (2 users ?)
  1692. GetFileFromRemoteStorage( pRemoteStorage, "cfg/config.cfg", "cfg/config.cfg", "USRLOCAL" );
  1693. }
  1694. }
  1695. if ( g_pFileSystem->FileExists( "//usrlocal/cfg/config.cfg" ) )
  1696. {
  1697. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec config.cfg usrlocal\n" );
  1698. }
  1699. else if ( g_pFileSystem->FileExists( "//mod/cfg/config.cfg" ) )
  1700. {
  1701. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec config.cfg mod\n" );
  1702. }
  1703. else
  1704. {
  1705. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec config_default.cfg\n" );
  1706. saveconfig = true;
  1707. }
  1708. Cbuf_Execute();
  1709. // check to see if we actually set any keys, if not, load defaults from kb_def.lst
  1710. // so we at least have basics setup.
  1711. int nNumBinds = Key_CountBindings();
  1712. if ( nNumBinds == 0 )
  1713. {
  1714. UseDefaultBindings();
  1715. }
  1716. Key_SetBinding( KEY_ESCAPE, "cancelselect" );
  1717. // Make sure that something is always bound to console
  1718. if (NULL == Key_NameForBinding("toggleconsole"))
  1719. {
  1720. // If nothing is bound to it then bind it to '
  1721. Key_SetBinding( KEY_BACKQUOTE, "toggleconsole" );
  1722. }
  1723. SetupDefaultAskConnectAcceptKey();
  1724. Host_SetConfigCfgExecuted( iController );
  1725. if ( saveconfig )
  1726. {
  1727. // An ugly hack, but we can probably save this safely
  1728. bool saveinit = host_initialized;
  1729. host_initialized = true;
  1730. Host_WriteConfiguration( iController, "config.cfg" );
  1731. host_initialized = saveinit;
  1732. }
  1733. #endif
  1734. }
  1735. CON_COMMAND( host_writeconfig, "Store current settings to config.cfg (or specified .cfg file)." )
  1736. {
  1737. if ( args.ArgC() > 2 )
  1738. {
  1739. ConMsg( "Usage: writeconfig <filename.cfg>\n" );
  1740. return;
  1741. }
  1742. if ( args.ArgC() == 2 )
  1743. {
  1744. char const *filename = args[ 1 ];
  1745. if ( !filename || !filename[ 0 ] )
  1746. {
  1747. return;
  1748. }
  1749. char outfile[ MAX_QPATH ];
  1750. // Strip path and extension from filename
  1751. Q_FileBase( filename, outfile, sizeof( outfile ) );
  1752. Host_WriteConfiguration( -1, va( "%s.cfg", outfile ) );
  1753. }
  1754. else
  1755. {
  1756. Host_WriteConfiguration( -1, "config.cfg" );
  1757. }
  1758. }
  1759. CON_COMMAND( host_writeconfig_ss, "Store current settings to config.cfg (or specified .cfg file) with first param as splitscreen index." )
  1760. {
  1761. if ( args.ArgC() <= 1 || args.ArgC() > 3)
  1762. {
  1763. ConMsg( "Usage: writeconfig <controller index> <filename.cfg>\n" );
  1764. return;
  1765. }
  1766. if ( args.ArgC() == 3 )
  1767. {
  1768. char const *filename = args[ 2 ];
  1769. if ( !filename || !filename[ 0 ] )
  1770. {
  1771. return;
  1772. }
  1773. char outfile[ MAX_QPATH ];
  1774. // Strip path and extension from filename
  1775. Q_FileBase( filename, outfile, sizeof( outfile ) );
  1776. int controller = atoi( args[1] );
  1777. Host_WriteConfiguration( controller, va( "%s.cfg", outfile ) );
  1778. }
  1779. else if ( args.ArgC() == 2 )
  1780. {
  1781. int controller = atoi( args[1] );
  1782. Host_WriteConfiguration( controller, "config.cfg" );
  1783. }
  1784. else
  1785. {
  1786. Host_WriteConfiguration( -1, "config.cfg" );
  1787. }
  1788. }
  1789. CON_COMMAND( host_reset_config, "reset config (for testing) with param as splitscreen index." )
  1790. {
  1791. if ( args.ArgC() <= 1 || args.ArgC() > 2)
  1792. {
  1793. ConMsg( "Usage: host_reset_config <controller index>\n" );
  1794. return;
  1795. }
  1796. else if ( args.ArgC() == 2 )
  1797. {
  1798. int controller = atoi( args[1] );
  1799. Host_ResetConfiguration( controller );
  1800. }
  1801. }
  1802. #ifdef _GAMECONSOLE
  1803. CON_COMMAND( host_writeconfig_video_ss, "Store current video settings to config.cfg (or specified .cfg file) with first param as controller index." )
  1804. {
  1805. if ( args.ArgC() != 2 )
  1806. {
  1807. ConMsg( "Usage: writeconfig <controller index>\n" );
  1808. return;
  1809. }
  1810. int controller = atoi( args[1] );
  1811. Host_WriteConfiguration_Console( controller, true );
  1812. }
  1813. #endif
  1814. #endif
  1815. //-----------------------------------------------------------------------------
  1816. // Purpose: Does a quick parse of the config.cfg to read cvars that
  1817. // need to be read before any games systems are initialized
  1818. // assumes only cvars and filesystem are initialized
  1819. //-----------------------------------------------------------------------------
  1820. void Host_ReadPreStartupConfiguration()
  1821. {
  1822. FileHandle_t f = NULL;
  1823. if ( IsGameConsole() )
  1824. {
  1825. // 360 config is less restrictive and can be anywhere in the game path
  1826. f = g_pFileSystem->Open( "//game/cfg/config" PLATFORM_EXT ".cfg", "rt" );
  1827. }
  1828. else
  1829. {
  1830. f = g_pFileSystem->Open( "//usrlocal/cfg/config.cfg", "rt" );
  1831. if ( !f )
  1832. f = g_pFileSystem->Open( "//mod/cfg/config.cfg", "rt" );
  1833. }
  1834. if ( !f )
  1835. return;
  1836. // read file into memory
  1837. int size = g_pFileSystem->Size(f);
  1838. char *configBuffer = new char[ size + 1 ];
  1839. g_pFileSystem->Read( configBuffer, size, f );
  1840. configBuffer[size] = 0;
  1841. g_pFileSystem->Close( f );
  1842. // parse out file
  1843. static const char *s_PreStartupConfigConVars[] =
  1844. {
  1845. "sv_unlockedchapters", // needed to display the startup graphic while loading
  1846. "snd_legacy_surround", // needed to init the sound system
  1847. "gameui_xbox", // needed to initialize the correct UI
  1848. "save_in_memory", // needed to preread data from the correct location in UI
  1849. #if defined( USE_SDL )
  1850. "sdl_displayindex" // needed to set multimonitor displayindex for SDL
  1851. #endif
  1852. };
  1853. // loop through looking for all the cvars to apply
  1854. for (int i = 0; i < ARRAYSIZE(s_PreStartupConfigConVars); i++)
  1855. {
  1856. const char *search = Q_stristr(configBuffer, s_PreStartupConfigConVars[i]);
  1857. if (search)
  1858. {
  1859. // read over the token
  1860. search = COM_Parse(search);
  1861. // read the value
  1862. COM_Parse(search);
  1863. // apply the value
  1864. ConVar *var = (ConVar *)g_pCVar->FindVar( s_PreStartupConfigConVars[i] );
  1865. if ( var )
  1866. {
  1867. var->SetValue( com_token );
  1868. }
  1869. }
  1870. }
  1871. // free
  1872. delete [] configBuffer;
  1873. }
  1874. void Host_RecomputeSpeed_f( void )
  1875. {
  1876. ConMsg( "Recomputing clock speed...\n" );
  1877. CClockSpeedInit::Init();
  1878. ConMsg( "Clock speed: %.0f Mhz\n", CFastTimer::GetClockSpeed() / 1000000.0 );
  1879. }
  1880. static ConCommand recompute_speed( "recompute_speed", Host_RecomputeSpeed_f, "Recomputes clock speed (for debugging purposes).", FCVAR_CHEAT );
  1881. void DTI_Flush_f()
  1882. {
  1883. DTI_Flush();
  1884. ServerDTI_Flush();
  1885. FlushDeltaBitsTrackingData();
  1886. }
  1887. static ConCommand dti_flush( "dti_flush", DTI_Flush_f, "Write out the datatable instrumentation files (you must run with -dti for this to work)." );
  1888. /*
  1889. ==================
  1890. Host_ShutdownServer
  1891. This only happens at the end of a game, not between levels
  1892. ==================
  1893. */
  1894. void Host_ShutdownServer( void )
  1895. {
  1896. if ( !sv.IsActive() )
  1897. return;
  1898. if ( IGameEvent *event = g_GameEventManager.CreateEvent( "server_pre_shutdown" ) )
  1899. {
  1900. event->SetString( "reason", "restart" );
  1901. g_GameEventManager.FireEvent( event );
  1902. }
  1903. // clear structures
  1904. #if !defined( DEDICATED )
  1905. g_pShadowMgr->LevelShutdown();
  1906. #endif
  1907. StaticPropMgr()->LevelShutdown();
  1908. Host_FreeStateAndWorld( true );
  1909. sv.Shutdown();// sv.Shutdown() references some heap memory, so run it before Host_FreeToLowMark()
  1910. Host_FreeToLowMark( true );
  1911. #if defined( REPLAY_ENABLED )
  1912. if ( g_pServerReplayHistoryManager )
  1913. {
  1914. g_pServerReplayHistoryManager->Shutdown();
  1915. g_pServerReplayHistoryManager = NULL;
  1916. }
  1917. #endif
  1918. if ( IGameEvent *event = g_GameEventManager.CreateEvent( "server_shutdown" ) )
  1919. {
  1920. event->SetString( "reason", "restart" );
  1921. g_GameEventManager.FireEvent( event );
  1922. }
  1923. g_Log.Close();
  1924. }
  1925. //-----------------------------------------------------------------------------
  1926. // Purpose:
  1927. // Input : time -
  1928. // Output : bool
  1929. //-----------------------------------------------------------------------------
  1930. void Host_AccumulateTime( float dt )
  1931. {
  1932. // Accumulate some time
  1933. realtime += dt;
  1934. bool bUseNormalTickTime = true;
  1935. #if !defined(DEDICATED)
  1936. if ( demoplayer->IsPlayingTimeDemo() )
  1937. bUseNormalTickTime = false;
  1938. #endif
  1939. if ( g_bDedicatedServerBenchmarkMode )
  1940. bUseNormalTickTime = false;
  1941. if ( bUseNormalTickTime )
  1942. {
  1943. host_frametime = dt;
  1944. }
  1945. else
  1946. {
  1947. // Used to help increase reproducibility of timedemos
  1948. host_frametime = host_state.interval_per_tick;
  1949. }
  1950. extern bool g_bReplayLoadedTools;
  1951. float flHostTimescale = 1.0f;
  1952. float flGameTimescale = 1.0f;
  1953. if ( host_timescale.GetFloat() > 0.0f
  1954. #if !defined(DEDICATED)
  1955. && CanCheat()
  1956. #endif
  1957. )
  1958. {
  1959. // We are allowed to modify this convar!
  1960. flHostTimescale = host_timescale.GetFloat();
  1961. }
  1962. if ( flGameTimescale > 0.0f )
  1963. {
  1964. flGameTimescale = sv.GetTimescale();
  1965. }
  1966. float fullscale = flHostTimescale * flGameTimescale;
  1967. #if !defined(DEDICATED)
  1968. if ( demoplayer->IsPlayingBack() )
  1969. {
  1970. // adjust time scale if playing back demo
  1971. fullscale *= demoplayer->GetPlaybackTimeScale();
  1972. }
  1973. #endif
  1974. #if 1
  1975. if ( host_framerate.GetFloat() != 0
  1976. #if !defined(DEDICATED)
  1977. && ( CanCheat() || demoplayer->IsPlayingBack() )
  1978. #endif
  1979. )
  1980. {
  1981. float fps = host_framerate.GetFloat();
  1982. if ( fps > 1 )
  1983. {
  1984. fps = 1.0f/fps;
  1985. }
  1986. else if ( fps < -1 )
  1987. {
  1988. fps = 1.0f/fabsf(fps);
  1989. if ( fps > dt )
  1990. {
  1991. fps = dt;
  1992. }
  1993. }
  1994. host_frametime = fps;
  1995. host_frametime_unbounded = host_frametime;
  1996. host_frametime_unscaled = host_frametime;
  1997. }
  1998. else if ( fullscale != 1.0f )
  1999. {
  2000. host_frametime_unscaled = host_frametime;
  2001. host_frametime *= fullscale;
  2002. host_frametime_unbounded = host_frametime;
  2003. #ifndef NO_TOOLFRAMEWORK
  2004. if ( CommandLine()->CheckParm( "-tools" ) == NULL && !g_bReplayLoadedTools )
  2005. {
  2006. #endif // !NO_TOOLFRAMEWORK
  2007. host_frametime = MIN( host_frametime, MAX_FRAMETIME * fullscale);
  2008. host_frametime_unscaled = MIN( host_frametime_unscaled, MAX_FRAMETIME );
  2009. host_frametime_unscaled = MAX( host_frametime_unscaled, MIN_FRAMETIME );
  2010. #ifndef NO_TOOLFRAMEWORK
  2011. }
  2012. else
  2013. {
  2014. host_frametime = MIN( host_frametime, MAX_TOOLS_FRAMETIME * fullscale);
  2015. host_frametime_unscaled = MIN( host_frametime_unscaled, MAX_TOOLS_FRAMETIME );
  2016. host_frametime_unscaled = MAX( host_frametime_unscaled, MIN_TOOLS_FRAMETIME );
  2017. }
  2018. #endif // !NO_TOOLFRAMEWORK
  2019. }
  2020. else
  2021. #ifndef NO_TOOLFRAMEWORK
  2022. if ( CommandLine()->CheckParm( "-tools" ) != NULL && !g_bReplayLoadedTools )
  2023. {
  2024. host_frametime_unbounded = host_frametime;
  2025. host_frametime = MIN( host_frametime, MAX_TOOLS_FRAMETIME );
  2026. host_frametime = MAX( host_frametime, MIN_TOOLS_FRAMETIME );
  2027. host_frametime_unscaled = host_frametime;
  2028. }
  2029. else
  2030. #endif // !NO_TOOLFRAMEWORK
  2031. { // don't allow really long or short frames
  2032. host_frametime_unbounded = host_frametime;
  2033. host_frametime = MIN( host_frametime, MAX_FRAMETIME );
  2034. host_frametime = MAX( host_frametime, MIN_FRAMETIME );
  2035. host_frametime_unscaled = host_frametime;
  2036. }
  2037. #endif // 1
  2038. // Adjust the client clock very slightly to keep it in line with the server clock.
  2039. #ifndef DEDICATED
  2040. float adj = GetBaseLocalClient().GetClockDriftMgr().AdjustFrameTime( host_frametime ) - host_frametime;
  2041. host_frametime += adj;
  2042. host_frametime_unbounded += adj;
  2043. host_frametime_unscaled += adj;
  2044. #endif
  2045. if ( g_pSoundServices ) // not present on linux server
  2046. g_pSoundServices->SetSoundFrametime(dt, host_frametime);
  2047. }
  2048. #define FPS_AVG_FRAC 0.9f
  2049. float g_fFramesPerSecond = 0.0f;
  2050. // temporarily a constant until I bother to hook it to a cvar
  2051. inline static bool cl_ps3ledframerate() // should i make the front LEDs show the framerate (divided by two)
  2052. {
  2053. #ifdef _PS3
  2054. return (CPS3FrontPanelLED::GetSwitches() & CPS3FrontPanelLED::kPS3SWITCH3) == 0;
  2055. #else
  2056. return false;
  2057. #endif
  2058. }
  2059. /*
  2060. ==================
  2061. Host_PostFrameRate
  2062. ==================
  2063. */
  2064. void Host_PostFrameRate( float frameTime )
  2065. {
  2066. extern int r_framecount;
  2067. frameTime = clamp( frameTime, 0.0001f, 1.0f );
  2068. float fps = 1.0f / frameTime;
  2069. g_fFramesPerSecond = g_fFramesPerSecond * FPS_AVG_FRAC + ( 1.0f - FPS_AVG_FRAC ) * fps;
  2070. if ( IsPS3() && !IsCert() )
  2071. {
  2072. if ( cl_ps3ledframerate() )
  2073. {
  2074. uint64 switches = CPS3FrontPanelLED::GetSwitches();
  2075. int framerate = RoundFloatToInt( g_fFramesPerSecond * 0.5f );
  2076. // two modes -- with DIP 0 set to zero,
  2077. if (( switches & CPS3FrontPanelLED::kPS3SWITCH0 ))
  2078. {
  2079. // make the front LEDs display the framerate divided by two in binary code
  2080. // (ie to scale it so that 0..31 fits into 0..15)
  2081. framerate = framerate > 31 ? 31 : framerate ;
  2082. CPS3FrontPanelLED::SetLEDs( framerate >> 1 );
  2083. }
  2084. else // without DIP0 set on, do a snazzy KNIGHT RIDER effect
  2085. {
  2086. static CPS3FrontPanelLED::eLEDIndex_t kitt[6] = { CPS3FrontPanelLED::kPS3LED0, CPS3FrontPanelLED::kPS3LED1, CPS3FrontPanelLED::kPS3LED2, // CPS3FrontPanelLED::kPS3LED3,
  2087. CPS3FrontPanelLED::kPS3LED3, CPS3FrontPanelLED::kPS3LED2, CPS3FrontPanelLED::kPS3LED1 // , CPS3FrontPanelLED::kPS3LED0
  2088. };
  2089. CPS3FrontPanelLED::SetLEDs( kitt[ ( host_framecount >> 4 ) % 6] );
  2090. }
  2091. }
  2092. else
  2093. {
  2094. CPS3FrontPanelLED::SetLEDs( 0 );
  2095. }
  2096. }
  2097. }
  2098. /*
  2099. ==================
  2100. Host_GetHostInfo
  2101. ==================
  2102. */
  2103. void Host_GetHostInfo(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen )
  2104. {
  2105. // Count clients, report
  2106. int clients = sv.GetNumClients();
  2107. *fps = g_fFramesPerSecond;
  2108. *nActive = clients;
  2109. if (pszMap)
  2110. {
  2111. if (sv.m_szMapname && sv.m_szMapname[0])
  2112. Q_strncpy(pszMap, sv.m_szMapname, maxlen );
  2113. else
  2114. pszMap[0] = '\0';
  2115. }
  2116. *nMaxPlayers = sv.GetMaxClients();
  2117. }
  2118. static bool AppearsNumeric( char const *in )
  2119. {
  2120. char const *p = in;
  2121. int special[ 3 ];
  2122. Q_memset( special, 0, sizeof( special ) );
  2123. for ( ; *p; p++ )
  2124. {
  2125. if ( *p == '-' )
  2126. {
  2127. special[0]++;
  2128. continue;
  2129. }
  2130. if ( *p == '+' )
  2131. {
  2132. special[1]++;
  2133. continue;
  2134. }
  2135. if ( *p >= '0' && *p <= '9' )
  2136. {
  2137. continue;
  2138. }
  2139. if ( *p == '.' )
  2140. {
  2141. special[2]++;
  2142. continue;
  2143. }
  2144. return false;
  2145. }
  2146. // Can't have multiple +, -, or decimals
  2147. for ( int i = 0; i < 3; i++ )
  2148. {
  2149. if ( special[ i ] > 1 )
  2150. return false;
  2151. }
  2152. // can't be + and - at same time
  2153. if ( special[ 0 ] && special[ 1 ] )
  2154. return false;
  2155. return true;
  2156. }
  2157. //-----------------------------------------------------------------------------
  2158. // Purpose: If the value is numeric, remove unnecessary trailing zeros
  2159. // Input : *invalue -
  2160. // Output : char const
  2161. //-----------------------------------------------------------------------------
  2162. char const * Host_CleanupConVarStringValue( char const *invalue )
  2163. {
  2164. static char clean[ 256 ];
  2165. Q_snprintf( clean, sizeof( clean ), "%s", invalue );
  2166. // Don't mess with empty string
  2167. // Otherwise, if it appears numeric and has a decimal, try to strip all zeroes after decimal
  2168. if ( Q_strlen( clean ) >= 1 && AppearsNumeric( clean ) && Q_strstr( clean, "." ) )
  2169. {
  2170. char *end = clean + strlen( clean ) - 1;
  2171. while ( *end && end >= clean )
  2172. {
  2173. // Removing trailing zeros
  2174. if ( *end != '0' )
  2175. {
  2176. // Remove decimal, zoo
  2177. if ( *end == '.' )
  2178. {
  2179. if ( end == clean )
  2180. {
  2181. *end = '0';
  2182. }
  2183. else
  2184. {
  2185. *end = 0;
  2186. }
  2187. }
  2188. break;
  2189. }
  2190. *end-- = 0;
  2191. }
  2192. }
  2193. return clean;
  2194. }
  2195. int Host_CountVariablesWithFlags( int flags, bool nonDefault )
  2196. {
  2197. int c = 0;
  2198. ICvar::Iterator iter( g_pCVar );
  2199. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  2200. {
  2201. ConCommandBase *var = iter.Get();
  2202. if ( var->IsCommand() )
  2203. continue;
  2204. const ConVar *pthiscvar = ( const ConVar * )var;
  2205. if ( !pthiscvar->IsFlagSet( flags ) )
  2206. continue;
  2207. // It's == to the default value, don't count
  2208. if ( nonDefault && !Q_strcasecmp( pthiscvar->GetDefault(), pthiscvar->GetString() ) )
  2209. continue;
  2210. ++c;
  2211. }
  2212. return c;
  2213. }
  2214. //-----------------------------------------------------------------------------
  2215. // Purpose:
  2216. // Input : msg -
  2217. //-----------------------------------------------------------------------------
  2218. void Host_BuildUserInfoUpdateMessage( int nSplitScreenSlot, CMsg_CVars *rCvarList, bool nonDefault )
  2219. {
  2220. // Slot 0 does the easy version, all userinfo, except _ADDED ones
  2221. int nRequiredFlags = FCVAR_USERINFO;
  2222. int nDisallowedFlags = FCVAR_SS_ADDED;
  2223. if ( nSplitScreenSlot != 0 )
  2224. {
  2225. // Slot one only looks at added ones
  2226. nDisallowedFlags = FCVAR_SS;
  2227. nRequiredFlags = FCVAR_USERINFO | FCVAR_SS_ADDED;
  2228. }
  2229. int count = Host_CountVariablesWithFlags( nRequiredFlags, nonDefault );
  2230. // Nothing to send
  2231. if ( count <= 0 )
  2232. return;
  2233. #if !defined( _GAMECONSOLE ) && !defined( DEDICATED )
  2234. // Add local user SteamID
  2235. if ( Steam3Client().SteamUser() && Steam3Client().SteamUser()->GetSteamID().GetAccountID() )
  2236. {
  2237. ++ count;
  2238. NetMsgSetCVarUsingDictionary( rCvarList->add_cvars(), "accountid",
  2239. CFmtStr( "%u", Steam3Client().SteamUser()->GetSteamID().GetAccountID() ) );
  2240. }
  2241. #endif
  2242. ICvar::Iterator iter( g_pCVar );
  2243. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  2244. {
  2245. ConCommandBase *var = iter.Get();
  2246. if ( var->IsCommand() )
  2247. continue;
  2248. const ConVar *pthiscvar = ( const ConVar * )var;
  2249. if ( !pthiscvar->IsFlagSet( nRequiredFlags ) || pthiscvar->IsFlagSet( nDisallowedFlags ) )
  2250. continue;
  2251. // It's == to the default value, don't count
  2252. if ( nonDefault && !Q_strcasecmp( pthiscvar->GetDefault(), pthiscvar->GetString() ) )
  2253. continue;
  2254. if ( pthiscvar->GetSplitScreenPlayerSlot() != nSplitScreenSlot )
  2255. continue;
  2256. NetMsgSetCVarUsingDictionary( rCvarList->add_cvars(), pthiscvar->GetBaseName(),
  2257. Host_CleanupConVarStringValue( pthiscvar->GetString() ) );
  2258. }
  2259. // Too many to send, error out and have mod author get a clue.
  2260. if ( rCvarList->cvars_size() > 255 )
  2261. {
  2262. Sys_Error( "Engine only supports 255 ConVars marked %i\n", FCVAR_USERINFO );
  2263. return;
  2264. }
  2265. // Make sure this count matches original one
  2266. Assert( rCvarList->cvars_size() <= count );
  2267. }
  2268. //-----------------------------------------------------------------------------
  2269. // Purpose:
  2270. // Input : msg -
  2271. //-----------------------------------------------------------------------------
  2272. void Host_BuildConVarUpdateMessage( CMsg_CVars *rCvarList, int flags, bool nonDefault )
  2273. {
  2274. int count = Host_CountVariablesWithFlags( flags, nonDefault );
  2275. // Nothing to send
  2276. if ( count <= 0 )
  2277. return;
  2278. // Too many to send, error out and have mod author get a clue.
  2279. if ( count > 255 )
  2280. {
  2281. Sys_Error( "Engine only supports 255 ConVars marked %i\n", flags );
  2282. return;
  2283. }
  2284. ICvar::Iterator iter( g_pCVar );
  2285. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  2286. {
  2287. ConCommandBase *var = iter.Get();
  2288. if ( var->IsCommand() )
  2289. continue;
  2290. const ConVar *pthiscvar = ( const ConVar * )var;
  2291. if ( !pthiscvar->IsFlagSet( flags ) )
  2292. continue;
  2293. // It's == to the default value, don't count
  2294. if ( nonDefault && !Q_strcasecmp( pthiscvar->GetDefault(), pthiscvar->GetString() ) )
  2295. continue;
  2296. NetMsgSetCVarUsingDictionary( rCvarList->add_cvars(), pthiscvar->GetName(),
  2297. Host_CleanupConVarStringValue( pthiscvar->GetString() ) );
  2298. }
  2299. }
  2300. #if !defined( DEDICATED )
  2301. // FIXME: move me somewhere more appropriate
  2302. extern IVEngineClient *engineClient;
  2303. void CL_SendVoicePacket(bool bFinal)
  2304. {
  2305. #if !defined( NO_VOICE )
  2306. if ( !Voice_IsRecording() )
  2307. return;
  2308. // Get whatever compressed data there is and and send it.
  2309. char uchVoiceData[8192];
  2310. VoiceFormat_t format;
  2311. uint8 nSectionNumber;
  2312. uint32 nSectionSequenceNumber;
  2313. uint32 nUncompressedSampleOffset;
  2314. int nLength = Voice_GetCompressedData( uchVoiceData, sizeof( uchVoiceData ), bFinal, &format, &nSectionNumber, &nSectionSequenceNumber, &nUncompressedSampleOffset );
  2315. if( nLength && GetBaseLocalClient().IsActive() )
  2316. {
  2317. CCLCMsg_VoiceData_t voiceMsg;
  2318. voiceMsg.set_data( uchVoiceData, nLength );
  2319. if ( format == VoiceFormat_Steam )
  2320. {
  2321. voiceMsg.set_format( VOICEDATA_FORMAT_STEAM );
  2322. }
  2323. else
  2324. {
  2325. voiceMsg.set_format( VOICEDATA_FORMAT_ENGINE );
  2326. }
  2327. player_info_t playerInfo;
  2328. if ( engineClient->GetPlayerInfo( engineClient->GetLocalPlayer(), &playerInfo ) )
  2329. {
  2330. voiceMsg.set_xuid( playerInfo.xuid );
  2331. }
  2332. voiceMsg.set_section_number( nSectionNumber );
  2333. voiceMsg.set_sequence_bytes( nSectionSequenceNumber );
  2334. voiceMsg.set_uncompressed_sample_offset( nUncompressedSampleOffset );
  2335. GetBaseLocalClient().m_NetChannel->SendNetMsg( voiceMsg );
  2336. }
  2337. #endif
  2338. }
  2339. #if defined ( _GAMECONSOLE )
  2340. void CL_ProcessGameConsoleVoiceData()
  2341. {
  2342. if ( g_pMatchFramework && !(g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_VOICE_INGAME) )
  2343. return; // Title plays voice via lobby system
  2344. #if defined( _PS3 ) && defined( CLIENT_DLL )
  2345. bool restrictedFromChat = engine->PS3_IsUserRestrictedFromChat( );
  2346. if ( restrictedFromChat )
  2347. return;
  2348. #endif
  2349. if ( Audio_GetXVoice() == NULL )
  2350. return;
  2351. for ( int k = 0; k < XBX_GetNumGameUsers(); ++ k )
  2352. {
  2353. int iCtrlr = XBX_GetUserId( k );
  2354. ACTIVE_SPLITSCREEN_PLAYER_GUARD( k );
  2355. if ( Audio_GetXVoice()->VoiceUpdateData( iCtrlr ) )
  2356. {
  2357. if ( GetLocalClient( k ).IsActive() )
  2358. {
  2359. Audio_GetXVoice()->VoiceSendData( iCtrlr, GetLocalClient( k ).m_NetChannel );
  2360. }
  2361. }
  2362. }
  2363. }
  2364. #endif
  2365. void CL_ProcessVoiceData()
  2366. {
  2367. VPROF_BUDGET( "CL_ProcessVoiceData", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  2368. #if !defined( NO_VOICE )
  2369. if ( Voice_Idle( host_state.interval_per_tick ) )
  2370. {
  2371. CL_SendVoicePacket( false );
  2372. }
  2373. #endif
  2374. #if defined ( _GAMECONSOLE )
  2375. CL_ProcessGameConsoleVoiceData();
  2376. #endif
  2377. }
  2378. #endif
  2379. /*
  2380. =====================
  2381. Host_UpdateScreen
  2382. Refresh the screen
  2383. =====================
  2384. */
  2385. void Host_UpdateScreen( void )
  2386. {
  2387. #ifndef DEDICATED
  2388. if( r_ForceRestore.GetInt() )
  2389. {
  2390. ForceMatSysRestore();
  2391. r_ForceRestore.SetValue(0);
  2392. }
  2393. // Refresh the screen
  2394. SCR_UpdateScreen ();
  2395. #endif
  2396. }
  2397. /*
  2398. ====================
  2399. Host_UpdateSounds
  2400. Update sound subsystem and cd audio
  2401. ====================
  2402. */
  2403. void Host_UpdateSounds( void )
  2404. {
  2405. SNPROF("Host_UpdateSounds");
  2406. #if !defined( DEDICATED )
  2407. MDLCACHE_COARSE_LOCK_(g_pMDLCache);
  2408. // update audio
  2409. if ( GetBaseLocalClient().IsActive() )
  2410. {
  2411. S_Update( &s_AudioState );
  2412. }
  2413. else
  2414. {
  2415. S_Update( NULL );
  2416. }
  2417. #endif
  2418. }
  2419. /*
  2420. ==============================
  2421. Host_Speeds
  2422. ==============================
  2423. */
  2424. void CFrameTimer::ResetDeltas()
  2425. {
  2426. for ( int i = 0; i < NUM_FRAME_SEGMENTS; i++ )
  2427. {
  2428. deltas[ i ] = 0.0f;
  2429. }
  2430. }
  2431. void CFrameTimer::MarkFrame()
  2432. {
  2433. double frameTime;
  2434. double fps;
  2435. // ConDMsg("%f %f %f\n", time1, time2, time3 );
  2436. float fs_input = (deltas[FRAME_SEGMENT_INPUT])*1000.0;
  2437. float fs_client = (deltas[FRAME_SEGMENT_CLIENT])*1000.0;
  2438. float fs_server = (deltas[FRAME_SEGMENT_SERVER])*1000.0;
  2439. float fs_render = (deltas[FRAME_SEGMENT_RENDER])*1000.0;
  2440. float fs_sound = (deltas[FRAME_SEGMENT_SOUND])*1000.0;
  2441. float fs_cldll = (deltas[FRAME_SEGMENT_CLDLL])*1000.0;
  2442. float fs_exec = (deltas[FRAME_SEGMENT_CMD_EXECUTE])*1000.0;
  2443. m_flLastServerTime = fs_server;
  2444. ResetDeltas();
  2445. frameTime = host_frametime;
  2446. //frameTime /= 1000.0;
  2447. if ( frameTime < 0.0001 )
  2448. {
  2449. fps = 999.0;
  2450. }
  2451. else
  2452. {
  2453. fps = 1.0 / frameTime;
  2454. }
  2455. if (host_speeds.GetInt())
  2456. {
  2457. int ent_count = 0;
  2458. int i;
  2459. static int last_host_tickcount;
  2460. int ticks = host_tickcount - last_host_tickcount;
  2461. last_host_tickcount = host_tickcount;
  2462. // count used entities
  2463. for (i=0 ; i<sv.num_edicts ; i++)
  2464. {
  2465. if (!sv.edicts[i].IsFree())
  2466. ent_count++;
  2467. }
  2468. char sz[ 256 ];
  2469. Q_snprintf( sz, sizeof( sz ),
  2470. "%3i fps -- inp(%3.1f) sv(%3.1f) cl(%3.1f) render(%3.1f) snd(%3.1f) cl_dll(%3.1f) exec(%3.1f) ents(%d) ticks(%d)",
  2471. (int)fps,
  2472. fs_input,
  2473. fs_server,
  2474. fs_client,
  2475. fs_render,
  2476. fs_sound,
  2477. fs_cldll,
  2478. fs_exec,
  2479. ent_count,
  2480. ticks );
  2481. #ifndef DEDICATED
  2482. if ( host_speeds.GetInt() >= 2 )
  2483. {
  2484. Con_NPrintf ( 0, sz );
  2485. }
  2486. else
  2487. {
  2488. ConDMsg ( "%s\n", sz );
  2489. }
  2490. #endif
  2491. }
  2492. }
  2493. #define FRAME_TIME_FILTER_TIME 0.5f
  2494. void CFrameTimer::ComputeFrameVariability()
  2495. {
  2496. m_pFrameTimeHistory[m_nFrameTimeHistoryIndex] = frametime;
  2497. m_pFrameStartTimeHistory[m_nFrameTimeHistoryIndex] = framestarttimeduration;
  2498. if ( ++m_nFrameTimeHistoryIndex >= FRAME_HISTORY_COUNT )
  2499. {
  2500. m_nFrameTimeHistoryIndex = 0;
  2501. }
  2502. // Compute a low-pass filter of the frame time over the last half-second
  2503. // Count the number of samples that live within the last half-second
  2504. int i = m_nFrameTimeHistoryIndex;
  2505. int nMaxSamples = 0;
  2506. float flTotalTime = 0.0f;
  2507. while( (nMaxSamples < FRAME_HISTORY_COUNT) && (flTotalTime <= FRAME_TIME_FILTER_TIME) )
  2508. {
  2509. if ( --i < 0 )
  2510. {
  2511. i = FRAME_HISTORY_COUNT - 1;
  2512. }
  2513. if ( m_pFrameTimeHistory[i] == 0.0f )
  2514. break;
  2515. flTotalTime += m_pFrameTimeHistory[i];
  2516. ++nMaxSamples;
  2517. }
  2518. if ( nMaxSamples == 0 )
  2519. {
  2520. m_flFPSVariability = 0.0f;
  2521. m_flFPSStdDeviationSeconds = 0.0f;
  2522. m_flFPSStdDeviationFrameStartTimeSeconds = 0.0f;
  2523. return;
  2524. }
  2525. float flExponent = -2.0f / (int)nMaxSamples;
  2526. i = m_nFrameTimeHistoryIndex;
  2527. float flAverageTime = 0.0f;
  2528. float flExpCurveArea = 0.0f;
  2529. int n = 0;
  2530. while( n < nMaxSamples )
  2531. {
  2532. if ( --i < 0 )
  2533. {
  2534. i = FRAME_HISTORY_COUNT - 1;
  2535. }
  2536. flExpCurveArea += exp( flExponent * n );
  2537. flAverageTime += m_pFrameTimeHistory[i] * exp( flExponent * n );
  2538. ++n;
  2539. }
  2540. flAverageTime /= flExpCurveArea;
  2541. float flAveFPS = 0.0f;
  2542. if ( flAverageTime != 0.0f )
  2543. {
  2544. flAveFPS = 1.0f / flAverageTime;
  2545. }
  2546. float flCurrentFPS = 0.0f;
  2547. if ( frametime != 0.0f )
  2548. {
  2549. flCurrentFPS = 1.0f / frametime;
  2550. }
  2551. // Now subtract out the current fps to get variability in FPS
  2552. m_flFPSVariability = fabs( flCurrentFPS - flAveFPS );
  2553. // Now compute variance/stddeviation
  2554. double sumFrameTime = 0.0f, sumFrameStartTime = 0.0f;
  2555. int count = 0;
  2556. for ( int ii1 = 0; ii1 < FRAME_HISTORY_COUNT; ++ii1 )
  2557. {
  2558. if ( m_pFrameTimeHistory[ ii1 ] == 0.0f )
  2559. continue;
  2560. double ft = MIN( m_pFrameTimeHistory[ ii1 ], 0.25 );
  2561. sumFrameTime += ft;
  2562. ft = MIN( m_pFrameStartTimeHistory[ ii1 ], 0.25 );
  2563. sumFrameStartTime += ft;
  2564. ++count;
  2565. }
  2566. if ( count <= 1 )
  2567. {
  2568. return;
  2569. }
  2570. double avgFrameTime = sumFrameTime / (double)count;
  2571. double devSquaredFrameTime = 0.0f;
  2572. double avgFrameStartTime = sumFrameStartTime / ( double ) count;
  2573. double devSquaredFrameStartTime = 0.0f;
  2574. for ( int ii2 = 0; ii2 < FRAME_HISTORY_COUNT; ++ii2 )
  2575. {
  2576. if ( m_pFrameTimeHistory[ ii2 ] == 0.0f )
  2577. continue;
  2578. double ft = MIN( m_pFrameTimeHistory[ ii2 ], 0.25 );
  2579. double dt = ft - avgFrameTime;
  2580. devSquaredFrameTime += ( dt * dt );
  2581. ft = MIN( m_pFrameStartTimeHistory[ ii2 ], 0.25 );
  2582. dt = ft - avgFrameStartTime;
  2583. devSquaredFrameStartTime += ( dt * dt );
  2584. }
  2585. double variance = devSquaredFrameTime / (double)( count );
  2586. m_flFPSStdDeviationSeconds = sqrt( variance );
  2587. variance = devSquaredFrameStartTime / ( double ) ( count );
  2588. m_flFPSStdDeviationFrameStartTimeSeconds = sqrt( variance );
  2589. tmPlot( TELEMETRY_LEVEL0, TMPT_NONE, 0, m_flFPSStdDeviationSeconds * 1000.0f, "m_flFPSStdDeviationSeconds(ms)" );
  2590. tmPlot( TELEMETRY_LEVEL0, TMPT_NONE, 0, m_flFPSStdDeviationFrameStartTimeSeconds * 1000.0f, "m_flFPSStdDeviationFrameStartTimeMS(ms)" );
  2591. // printf("var: %.2f avg:%.6f frametime:%f\n", m_flFPSStdDeviationSeconds * 1000.0f, avg, frametime);
  2592. }
  2593. void Host_Speeds()
  2594. {
  2595. g_HostTimes.MarkFrame();
  2596. #if !defined(DEDICATED)
  2597. g_pClientDemoPlayer->MarkFrame( g_HostTimes.m_flFPSVariability );
  2598. #endif
  2599. }
  2600. //-----------------------------------------------------------------------------
  2601. // Purpose: When singlestep == 1, then you must set next == 1 to run to the
  2602. // next frame.
  2603. // Output : Returns true on success, false on failure.
  2604. //-----------------------------------------------------------------------------
  2605. bool Host_ShouldRun( void )
  2606. {
  2607. static int current_tick = -1;
  2608. // See if we are single stepping
  2609. if ( !singlestep.GetInt() )
  2610. {
  2611. return true;
  2612. }
  2613. // Did user set "next" to 1?
  2614. if ( next.GetInt() )
  2615. {
  2616. // Did we finally finish this frame ( Host_ShouldRun is called in 3 spots to pause
  2617. // three different things ).
  2618. if ( current_tick != (host_tickcount-1) )
  2619. {
  2620. // Okay, time to reset to halt execution again
  2621. next.SetValue( 0 );
  2622. return false;
  2623. }
  2624. // Otherwise, keep running this one frame since we are still finishing this frame
  2625. return true;
  2626. }
  2627. else
  2628. {
  2629. // Remember last frame without "next" being reset ( time is locked )
  2630. current_tick = host_tickcount;
  2631. // Time is locked
  2632. return false;
  2633. }
  2634. }
  2635. static ConVar mem_periodicdumps( "mem_periodicdumps", "0", 0, "Write periodic memstats dumps every n seconds." );
  2636. static double g_flLastPeriodicMemDump = -1.0f;
  2637. //-----------------------------------------------------------------------------
  2638. // Purpose:
  2639. //-----------------------------------------------------------------------------
  2640. static float g_TimeLastMemTest;
  2641. void Host_CheckDumpMemoryStats( void )
  2642. {
  2643. if ( mem_test_each_frame.GetBool() )
  2644. {
  2645. if ( !MemTest() )
  2646. {
  2647. DebuggerBreakIfDebugging();
  2648. Error( "Heap is corrupt\n" );
  2649. }
  2650. }
  2651. else if ( mem_test_every_n_seconds.GetInt() > 0 )
  2652. {
  2653. float now = Plat_FloatTime();
  2654. if ( now - g_TimeLastMemTest > mem_test_every_n_seconds.GetInt() )
  2655. {
  2656. g_TimeLastMemTest = now;
  2657. if ( !MemTest() )
  2658. {
  2659. DebuggerBreakIfDebugging();
  2660. Error( "Heap is corrupt\n" );
  2661. }
  2662. }
  2663. }
  2664. if ( mem_periodicdumps.GetFloat() > 0.0f )
  2665. {
  2666. double curtime = Plat_FloatTime();
  2667. if ( curtime - g_flLastPeriodicMemDump > mem_periodicdumps.GetFloat() )
  2668. {
  2669. const char *mapname = GetMapName();
  2670. Host_PrintMemoryStatus( mapname );
  2671. g_pMemAlloc->DumpStatsFileBase( mapname );
  2672. g_flLastPeriodicMemDump = curtime;
  2673. }
  2674. }
  2675. #if defined(_WIN32)
  2676. if ( mem_dumpstats.GetInt() <= 0 )
  2677. return;
  2678. if ( mem_dumpstats.GetInt() == 1 )
  2679. mem_dumpstats.SetValue( 0 ); // reset cvar, dump stats only once
  2680. _CrtMemState state;
  2681. Q_memset( &state, 0, sizeof( state ) );
  2682. _CrtMemCheckpoint( &state );
  2683. unsigned int size = 0;
  2684. for ( int use = 0; use < _MAX_BLOCKS; use++)
  2685. {
  2686. size += state.lSizes[ use ];
  2687. }
  2688. Msg("MEMORY: Run-time Heap\n------------------------------------\n");
  2689. Msg( "\tHigh water %s\n", Q_pretifymem( state.lHighWaterCount,4 ) );
  2690. Msg( "\tCurrent mem %s\n", Q_pretifymem( size,4 ) );
  2691. Msg("------------------------------------\n");
  2692. int hunk = Hunk_MallocSize();
  2693. Msg("\tAllocated outside hunk: %s\n", Q_pretifymem( size - hunk ) );
  2694. #endif
  2695. }
  2696. //-----------------------------------------------------------------------------
  2697. // Purpose:
  2698. //-----------------------------------------------------------------------------
  2699. void _Host_SetGlobalTime()
  2700. {
  2701. // Server
  2702. g_ServerGlobalVariables.realtime = realtime;
  2703. g_ServerGlobalVariables.framecount = host_framecount;
  2704. g_ServerGlobalVariables.absoluteframetime = host_frametime;
  2705. g_ServerGlobalVariables.absoluteframestarttimestddev = host_framestarttime_stddeviation;
  2706. g_ServerGlobalVariables.interval_per_tick = host_state.interval_per_tick;
  2707. g_ServerGlobalVariables.serverCount = Host_GetServerCount();
  2708. #ifndef DEDICATED
  2709. // Client
  2710. g_ClientGlobalVariables.realtime = realtime;
  2711. g_ClientGlobalVariables.framecount = host_framecount;
  2712. g_ClientGlobalVariables.absoluteframetime = host_frametime;
  2713. g_ClientGlobalVariables.absoluteframestarttimestddev = host_framestarttime_stddeviation;
  2714. g_ClientGlobalVariables.interval_per_tick = host_state.interval_per_tick;
  2715. #endif
  2716. }
  2717. /*
  2718. ==================
  2719. _Host_RunFrame
  2720. Runs all active servers
  2721. ==================
  2722. */
  2723. void _Host_RunFrame_Input( float accumulated_extra_samples, bool bFinalTick )
  2724. {
  2725. VPROF_BUDGET( "_Host_RunFrame_Input", _T("Input") );
  2726. // Run a test script?
  2727. static bool bFirstFrame = true;
  2728. if ( bFirstFrame )
  2729. {
  2730. bFirstFrame = false;
  2731. const char *pScriptFilename = CommandLine()->ParmValue( "-testscript" );
  2732. if ( pScriptFilename && pScriptFilename[0] )
  2733. {
  2734. GetTestScriptMgr()->StartTestScript( pScriptFilename );
  2735. }
  2736. // init the net console if we haven't yet
  2737. InitNetConsole();
  2738. NET_InitPostFork();
  2739. }
  2740. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_INPUT );
  2741. #ifndef DEDICATED
  2742. // Client can process input
  2743. ClientDLL_ProcessInput( );
  2744. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2745. // process console commands
  2746. Cbuf_Execute ();
  2747. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2748. // Send any current movement commands to server and flush reliable buffer even if not moving yet.
  2749. CL_Move( accumulated_extra_samples, bFinalTick );
  2750. #endif
  2751. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_INPUT );
  2752. }
  2753. void _Host_ProcessVoice_Server( void )
  2754. {
  2755. VPROF_BUDGET( "_Host_ProcessVoice_Server", VPROF_BUDGETGROUP_GAME );
  2756. SV_ProcessVoice();
  2757. }
  2758. void _Host_RunFrame_Server( bool finaltick )
  2759. {
  2760. VPROF_BUDGET( "_Host_RunFrame_Server", VPROF_BUDGETGROUP_GAME );
  2761. VPROF_INCREMENT_COUNTER( "ticks", 1 );
  2762. VPROF_TEST_SPIKE( vprof_server_spike_threshold.GetFloat() );
  2763. // Run the Server frame ( read, run physics, respond )
  2764. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_SERVER );
  2765. SV_Frame( finaltick );
  2766. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_SERVER );
  2767. // Look for connectionless rcon packets on dedicated servers
  2768. // SV_CheckRcom(); TODO
  2769. }
  2770. void _Host_RunFrame_Server_Async( int numticks )
  2771. {
  2772. #ifdef VPROF_ENABLED
  2773. if ( vprof_server_thread.GetBool() )
  2774. {
  2775. if ( g_VProfTargetThread != ThreadGetCurrentId() )
  2776. {
  2777. g_VProfTargetThread = ThreadGetCurrentId();
  2778. }
  2779. }
  2780. else
  2781. {
  2782. if ( g_VProfTargetThread == ThreadGetCurrentId() )
  2783. {
  2784. g_VProfTargetThread = g_MainThreadId;
  2785. }
  2786. }
  2787. #endif
  2788. MDLCACHE_COARSE_LOCK_(g_pMDLCache);
  2789. for ( int tick = 0; tick < numticks; tick++ )
  2790. {
  2791. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2792. g_ServerGlobalVariables.simTicksThisFrame = numticks - tick;
  2793. bool bFinalTick = ( tick == (numticks - 1) );
  2794. _Host_RunFrame_Server( bFinalTick );
  2795. }
  2796. }
  2797. void _Host_RunFrame_Client( bool framefinished )
  2798. {
  2799. #ifndef DEDICATED
  2800. VPROF( "_Host_RunFrame_Client" );
  2801. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CLIENT );
  2802. // Get any current state update from server, etc.
  2803. CL_ReadPackets( framefinished );
  2804. GetBaseLocalClient().CheckUpdatingSteamResources();
  2805. GetBaseLocalClient().CheckFileCRCsWithServer();
  2806. // Resend connection request if needed.
  2807. GetBaseLocalClient().RunFrame();
  2808. if ( CL_IsHL2Demo() || CL_IsPortalDemo() ) // don't need sv.IsDedicated() because ded servers don't run this
  2809. {
  2810. void CL_DemoCheckGameUIRevealTime();
  2811. CL_DemoCheckGameUIRevealTime();
  2812. }
  2813. Steam3Client().RunFrame();
  2814. #if defined( _DEBUG )
  2815. // Debug!!! FireGameEvent
  2816. g_GameEventManager.VerifyListenerList();
  2817. #endif
  2818. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CLIENT );
  2819. // This takes 1 usec, so it's pretty cheap...
  2820. CL_SetPagedPoolInfo();
  2821. #endif
  2822. }
  2823. //-----------------------------------------------------------------------------
  2824. // Purpose: Used to set limits on certain convars in multiplayer/sv_cheats mode.
  2825. // Returns true if it was called recursively and it early-outed.
  2826. //-----------------------------------------------------------------------------
  2827. bool CheckVarRange_Generic( ConVar *pVar, int minVal, int maxVal )
  2828. {
  2829. // Don't reenter (resetting the variable when we're checking the range might cause us to reenter here).
  2830. static bool bInFunction = false;
  2831. if ( bInFunction )
  2832. return true;
  2833. bInFunction = true;
  2834. if ( !CanCheat() && !Host_IsSinglePlayerGame() )
  2835. {
  2836. int clampedValue = clamp( pVar->GetInt(), minVal, maxVal );
  2837. if ( clampedValue != pVar->GetInt() )
  2838. {
  2839. Warning( "sv_cheats=0 prevented changing %s outside of the range [0,2] (was %d).\n", pVar->GetName(), pVar->GetInt() );
  2840. pVar->SetValue( clampedValue );
  2841. }
  2842. }
  2843. bInFunction = false;
  2844. return false;
  2845. }
  2846. void CheckSpecialCheatVars()
  2847. {
  2848. static ConVar *mat_picmip = NULL;
  2849. if ( !mat_picmip )
  2850. mat_picmip = g_pCVar->FindVar( "mat_picmip" );
  2851. // In multiplayer, don't allow them to set mat_picmip > 2.
  2852. if ( mat_picmip )
  2853. CheckVarRange_Generic( mat_picmip, -10, 2 );
  2854. CheckVarRange_r_rootlod();
  2855. CheckVarRange_r_lod();
  2856. }
  2857. void _Host_RunFrame_Render()
  2858. {
  2859. #ifndef DEDICATED
  2860. VPROF( "_Host_RunFrame_Render" );
  2861. CheckSpecialCheatVars();
  2862. int nOrgNoRendering = mat_norendering.GetInt();
  2863. if ( cl_takesnapshot )
  2864. {
  2865. // turn off no-rendering mode, if taking screenshot
  2866. mat_norendering.SetValue( 0 );
  2867. }
  2868. // update video if not running in background
  2869. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_RENDER );
  2870. CL_LatchInterpolationAmount();
  2871. {
  2872. VPROF( "_Host_RunFrame_Render - UpdateScreen" );
  2873. Host_UpdateScreen();
  2874. }
  2875. {
  2876. VPROF( "_Host_RunFrame_Render - CL_DecayLights" );
  2877. CL_DecayLights ();
  2878. }
  2879. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_RENDER );
  2880. saverestore->OnFrameRendered();
  2881. #ifdef USE_SDL
  2882. if ( g_pLauncherMgr )
  2883. {
  2884. g_pLauncherMgr->OnFrameRendered();
  2885. }
  2886. #endif
  2887. mat_norendering.SetValue( nOrgNoRendering );
  2888. #endif
  2889. }
  2890. void CL_FindInterpolatedAddAngle( float t, float& frac, AddAngle **prev, AddAngle **pnextangle )
  2891. {
  2892. #ifndef DEDICATED
  2893. int c = GetLocalClient().addangle.Count();
  2894. *prev = NULL;
  2895. *pnextangle = NULL;
  2896. AddAngle *pentry = NULL;
  2897. for ( int i = 0; i < c; i++ )
  2898. {
  2899. AddAngle *entry = &GetLocalClient().addangle[ i ];
  2900. *pnextangle = entry;
  2901. // Time is earlier
  2902. if ( t < entry->starttime )
  2903. {
  2904. if ( i == 0 )
  2905. {
  2906. *prev = *pnextangle;
  2907. frac = 0.0f;
  2908. return;
  2909. }
  2910. // Avoid div by zero
  2911. if ( entry->starttime == pentry->starttime )
  2912. {
  2913. frac = 0.0f;
  2914. return;
  2915. }
  2916. // Time spans the two entries
  2917. frac = ( t - pentry->starttime ) / ( entry->starttime - pentry->starttime );
  2918. frac = clamp( frac, 0.0f, 1.0f );
  2919. return;
  2920. }
  2921. *prev = *pnextangle;
  2922. pentry = entry;
  2923. }
  2924. #endif
  2925. }
  2926. void CL_DiscardOldAddAngleEntries( float t )
  2927. {
  2928. #ifndef DEDICATED
  2929. float killtime = t - host_state.interval_per_tick - 0.1f;
  2930. for ( int i = 0; i < GetLocalClient().addangle.Count(); i++ )
  2931. {
  2932. AddAngle *p = &GetLocalClient().addangle[ i ];
  2933. if ( p->starttime <= killtime )
  2934. {
  2935. GetLocalClient().addangle.Remove( i );
  2936. --i;
  2937. }
  2938. }
  2939. // It's safe to reset the master counter once all the entries decay
  2940. if ( GetLocalClient().addangle.Count() == 0 )
  2941. {
  2942. GetLocalClient().prevaddangletotal = GetLocalClient().addangletotal = 0.0f;
  2943. }
  2944. #endif
  2945. }
  2946. #ifndef DEDICATED
  2947. void CL_ApplyAddAngle()
  2948. {
  2949. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  2950. {
  2951. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  2952. float curtime = GetBaseLocalClient().GetTime() - host_state.interval_per_tick;
  2953. AddAngle *prev = NULL, *pnextangle = NULL;
  2954. float frac = 0.0f;
  2955. float addangletotal = 0.0f;
  2956. CL_FindInterpolatedAddAngle( curtime, frac, &prev, &pnextangle );
  2957. if ( prev && pnextangle )
  2958. {
  2959. addangletotal = prev->total + frac * ( pnextangle->total - prev->total );
  2960. }
  2961. else
  2962. {
  2963. addangletotal = GetLocalClient().prevaddangletotal;
  2964. }
  2965. float amove = addangletotal - GetLocalClient().prevaddangletotal;
  2966. // Update view angles
  2967. GetLocalClient().viewangles[ 1 ] += amove;
  2968. // Update client .dll view of angles
  2969. g_pClientSidePrediction->SetLocalViewAngles( GetLocalClient().viewangles );
  2970. // Remember last total
  2971. GetLocalClient().prevaddangletotal = addangletotal;
  2972. CL_DiscardOldAddAngleEntries( curtime );
  2973. }
  2974. }
  2975. #endif
  2976. CJob *g_pSoundJob;
  2977. bool g_bAllowThreadedSound;
  2978. void _Host_RunFrame_Sound()
  2979. {
  2980. #ifndef DEDICATED
  2981. if ( g_pSoundJob )
  2982. {
  2983. return;
  2984. }
  2985. VPROF_BUDGET( "_Host_RunFrame_Sound", VPROF_BUDGETGROUP_OTHER_SOUND );
  2986. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_SOUND );
  2987. if ( !host_threaded_sound.GetBool() || !g_bAllowThreadedSound )
  2988. {
  2989. Host_UpdateSounds();
  2990. }
  2991. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_SOUND );
  2992. #endif
  2993. }
  2994. void Host_BeginThreadedSound()
  2995. {
  2996. #ifndef DEDICATED
  2997. #ifdef _PS3
  2998. if (sv.IsActive())
  2999. {
  3000. Host_UpdateSounds();
  3001. g_pSoundJob = NULL;
  3002. return;
  3003. }
  3004. else if(host_threaded_sound_simplethread.GetBool())
  3005. {
  3006. SNPROF("Kick Sound");
  3007. g_pGcmSharedData->RunAudio(Host_UpdateSounds);
  3008. g_pSoundJob = (CJob*)1;
  3009. return;
  3010. }
  3011. #endif
  3012. if ( !host_threaded_sound.GetBool() || !g_bAllowThreadedSound )
  3013. {
  3014. return;
  3015. }
  3016. g_pSoundJob = new CFunctorJob( CreateFunctor( Host_UpdateSounds ) );
  3017. IThreadPool *pSoundThreadPool;
  3018. #ifdef _X360
  3019. pSoundThreadPool = g_pAlternateThreadPool;
  3020. #else
  3021. pSoundThreadPool = g_pThreadPool;
  3022. #endif
  3023. if ( IsX360() )
  3024. {
  3025. g_pSoundJob->SetServiceThread( g_nServerThread );
  3026. }
  3027. pSoundThreadPool->AddJob( g_pSoundJob );
  3028. #endif
  3029. }
  3030. void Host_EndThreadedSound()
  3031. {
  3032. if ( !g_pSoundJob )
  3033. {
  3034. return;
  3035. }
  3036. #ifdef _PS3
  3037. if(host_threaded_sound_simplethread.GetBool())
  3038. {
  3039. SNPROF("Wait for Sound");
  3040. g_pGcmSharedData->WaitForAudio();
  3041. g_pSoundJob = NULL;
  3042. return;
  3043. }
  3044. #endif
  3045. VPROF_BUDGET( "_Host_RunFrame_Sound", VPROF_BUDGETGROUP_OTHER_SOUND );
  3046. g_pSoundJob->WaitForFinishAndRelease();
  3047. g_pSoundJob = NULL;
  3048. }
  3049. float SV_GetSoundDuration( const char *pSample );
  3050. #ifndef DEDICATED
  3051. float AudioSource_GetSoundDuration( CSfxTable *pSfx );
  3052. #endif
  3053. float Host_GetSoundDuration( const char *pSample )
  3054. {
  3055. #ifndef DEDICATED
  3056. // bug 27822 (crash when leaving 360 credits map)
  3057. // If we don't check connected here, then client can be partially through disconnecting (stringtable dictionary wiped, etc)
  3058. // but still have the m_pStringTableDictionary pointer hanging around and then the server, on another thread,
  3059. // calls through this case and tries to read the memory and crashes...
  3060. CClientState &cl = GetBaseLocalClient();
  3061. if ( cl.IsConnected() )
  3062. {
  3063. int index = cl.LookupSoundIndex( pSample );
  3064. if ( index >= 0 )
  3065. {
  3066. CSfxTable *pSfxTable = cl.GetSound( index );
  3067. if ( ( pSfxTable != NULL) && pSfxTable->m_bIsLateLoad )
  3068. {
  3069. DevMsg( " Reason for late load of '%s': Calling Host_GetSoundDuration().\n", pSample );
  3070. }
  3071. return AudioSource_GetSoundDuration( pSfxTable );
  3072. }
  3073. }
  3074. #endif
  3075. return SV_GetSoundDuration( pSample );
  3076. }
  3077. CON_COMMAND( host_runofftime, "Run off some time without rendering/updating sounds\n" )
  3078. {
  3079. if ( args.ArgC() != 2 )
  3080. {
  3081. ConMsg( "Usage: host_runofftime <seconds>\n" );
  3082. return;
  3083. }
  3084. if ( !sv.IsActive() )
  3085. {
  3086. ConMsg( "host_runofftime: must be running a server\n" );
  3087. return;
  3088. }
  3089. if ( sv.IsMultiplayer() )
  3090. {
  3091. ConMsg( "host_runofftime: only valid in single player\n" );
  3092. return;
  3093. }
  3094. float advanceTime = atof( args[1] );
  3095. if ( advanceTime <= 0.0f )
  3096. return;
  3097. // 15 minutes is a _long_ time!!!
  3098. if ( advanceTime > 15.0f * 60.0f )
  3099. {
  3100. ConMsg( "host_runofftime would run off %.2f minutes!!! ignoring\n",
  3101. advanceTime / 60.0f );
  3102. return;
  3103. }
  3104. ConMsg( "Skipping ahead for %f seconds\n", advanceTime );
  3105. SCR_UpdateScreen();
  3106. SCR_UpdateScreen ();
  3107. }
  3108. #if !defined( _GAMECONSOLE )
  3109. S_API int SteamGameServer_GetIPCCallCount();
  3110. #else
  3111. S_API int SteamGameServer_GetIPCCallCount() { return 0; }
  3112. #endif
  3113. void Host_ShowIPCCallCount()
  3114. {
  3115. // If set to 0 then get out.
  3116. if ( host_ShowIPCCallCount.GetInt() == 0 )
  3117. return;
  3118. static float s_flLastTime = 0;
  3119. static int s_nLastTick = host_tickcount;
  3120. static int s_nLastFrame = host_framecount;
  3121. // Figure out how often they want to update.
  3122. double flInterval = 0;
  3123. if ( host_ShowIPCCallCount.GetFloat() > 0 )
  3124. {
  3125. flInterval = 1.0f / host_ShowIPCCallCount.GetFloat();
  3126. }
  3127. // This is called every frame so increment the frame counter.
  3128. double flCurTime = Plat_FloatTime();
  3129. if ( flCurTime - s_flLastTime >= flInterval )
  3130. {
  3131. uint32 callCount = 0;
  3132. #ifndef NO_STEAM
  3133. ISteamClient *pSteamClient =
  3134. #ifdef DEDICATED
  3135. Steam3Server().SteamClient()
  3136. #else
  3137. Steam3Client().SteamClient()
  3138. #endif
  3139. ;
  3140. if ( pSteamClient )
  3141. {
  3142. callCount = pSteamClient->GetIPCCallCount();
  3143. }
  3144. else
  3145. {
  3146. // Ok, we're a dedicated server and we need to use this to get it.
  3147. callCount = (uint32)SteamGameServer_GetIPCCallCount();
  3148. }
  3149. #endif
  3150. // Avoid a divide by zero.
  3151. int frameCount = host_framecount - s_nLastFrame;
  3152. int tickCount = host_tickcount - s_nLastTick;
  3153. if ( frameCount == 0 || tickCount == 0 )
  3154. return;
  3155. Msg( "host_ShowIPCCallCount: %d IPC calls in the past [%d frames, %d ticks] Avg: [%.2f/frame, %.2f/tick]\n",
  3156. callCount, frameCount, tickCount, (float)callCount / frameCount, (float)callCount / tickCount );
  3157. s_flLastTime = flCurTime;
  3158. s_nLastTick = host_tickcount;
  3159. s_nLastFrame = host_framecount;
  3160. }
  3161. }
  3162. void Host_SetClientInSimulation( bool bInSimulation )
  3163. {
  3164. #ifndef DEDICATED
  3165. GetBaseLocalClient().insimulation = bInSimulation;
  3166. // Compute absolute/render time stamp
  3167. g_ClientGlobalVariables.curtime = GetBaseLocalClient().GetTime();
  3168. g_ClientGlobalVariables.frametime = GetBaseLocalClient().GetFrameTime();
  3169. #endif
  3170. }
  3171. static ConVar host_Sleep( "host_sleep", "0", FCVAR_CHEAT, "Force the host to sleep a certain number of milliseconds each frame." );
  3172. extern ConVar sv_alternateticks;
  3173. ConVar host_print_frame_times( "host_print_frame_times", "0" );
  3174. #ifndef DEDICATED
  3175. static void PrintHostFrameTimes( int nNumTicks, float flHostRemainder, float flMinimumTickInterval )
  3176. {
  3177. const int nFrameHistorySize = 100;
  3178. static float flFrameTimes[nFrameHistorySize];
  3179. static int nFrameIndex = 0;
  3180. flFrameTimes[nFrameIndex] = host_frametime;
  3181. nFrameIndex = ( nFrameIndex + 1 ) % nFrameHistorySize;
  3182. float flMinFrameTime = 1.0f;
  3183. float flAvgFrameTime = 0.0f;
  3184. for ( int i = 0; i < nFrameHistorySize; ++ i )
  3185. {
  3186. if ( flFrameTimes[i] < flMinFrameTime )
  3187. {
  3188. flMinFrameTime = flFrameTimes[i];
  3189. }
  3190. flAvgFrameTime += flFrameTimes[i];
  3191. }
  3192. flAvgFrameTime /= (float)nFrameHistorySize;
  3193. con_nprint_t printinfo;
  3194. printinfo.index = 1;
  3195. printinfo.time_to_live = -1;
  3196. printinfo.color[0] = printinfo.color[1] = printinfo.color[2] = 1.0f;
  3197. printinfo.fixed_width_font = true;
  3198. Con_NXPrintf( &printinfo, "ticks: %d, host_remainder: %f, host_frametime: %f, minimum interval: %f\n", nNumTicks, flHostRemainder, host_frametime, flMinimumTickInterval );
  3199. printinfo.index = 2;
  3200. Con_NXPrintf( &printinfo, "Running min frametime: %f, running avg frametime: %f\n", flMinFrameTime, flAvgFrameTime );
  3201. }
  3202. #endif // DEDICATED
  3203. #if !( defined( _CERT ) || defined( DEDICATED ) )
  3204. ConVar fs_enable_stats( "fs_enable_stats", "0" );
  3205. static void PrintFsStats()
  3206. {
  3207. const int nFrameHistorySize = 100;
  3208. const int nStatsSize = 6;
  3209. static int nStats[nStatsSize][nFrameHistorySize] = { 0 };
  3210. static const char * pStatsTitle[] =
  3211. {
  3212. "# of seeks",
  3213. "Time seeking",
  3214. "# of reads",
  3215. "Time reading",
  3216. "Bytes read",
  3217. "# of fopen",
  3218. };
  3219. enum Mode
  3220. {
  3221. NORMAL,
  3222. IN_MS,
  3223. IN_BYTES,
  3224. SKIPPED,
  3225. };
  3226. static const Mode nModes[] =
  3227. {
  3228. NORMAL,
  3229. IN_MS,
  3230. NORMAL,
  3231. IN_MS,
  3232. IN_BYTES,
  3233. SKIPPED, // In the Source1 engine, there is a very strong correlation between fopen, seeks and reads. Don't display this one.
  3234. };
  3235. static int nFrameIndex = 0;
  3236. IIoStats *pIoStats = g_pFileSystem->GetIoStats();
  3237. if ( pIoStats == NULL )
  3238. {
  3239. con_nprint_t printinfo;
  3240. printinfo.index = 1;
  3241. printinfo.time_to_live = -1;
  3242. printinfo.color[0] = printinfo.color[1] = printinfo.color[2] = 1.0f;
  3243. printinfo.fixed_width_font = true;
  3244. Con_NXPrintf( &printinfo, "IO stats is disabled.\n" );
  3245. return;
  3246. }
  3247. nStats[0][nFrameIndex] = pIoStats->GetNumberOfFileSeeks();
  3248. nStats[1][nFrameIndex] = pIoStats->GetTimeInFileSeek();
  3249. nStats[2][nFrameIndex] = pIoStats->GetNumberOfFileReads();
  3250. nStats[3][nFrameIndex] = pIoStats->GetTimeInFileReads();
  3251. nStats[4][nFrameIndex] = pIoStats->GetFileReadTotalSize();
  3252. nStats[5][nFrameIndex] = pIoStats->GetNumberOfFileOpens();
  3253. pIoStats->Reset();
  3254. nFrameIndex = ( nFrameIndex + 1 ) % nFrameHistorySize;
  3255. int nMinStats[nStatsSize], nMaxStats[nStatsSize], nAvgStats[nStatsSize];
  3256. for (int i = 0 ; i < nStatsSize ; ++i )
  3257. {
  3258. if ( nModes[i] == SKIPPED )
  3259. {
  3260. continue; // Skip this one
  3261. }
  3262. nMinStats[i] = INT_MAX;
  3263. nMaxStats[i] = INT_MIN;
  3264. nAvgStats[i] = 0;
  3265. for ( int j = 0; j < nFrameHistorySize; ++j )
  3266. {
  3267. if ( nStats[i][j] < nMinStats[i] )
  3268. {
  3269. nMinStats[i] = nStats[i][j];
  3270. }
  3271. else if ( nStats[i][j] > nMaxStats[i] )
  3272. {
  3273. nMaxStats[i] = nStats[i][j];
  3274. }
  3275. nAvgStats[i] += nStats[i][j];
  3276. }
  3277. }
  3278. con_nprint_t printinfo;
  3279. printinfo.index = 1;
  3280. printinfo.time_to_live = -1;
  3281. printinfo.color[0] = printinfo.color[1] = printinfo.color[2] = 1.0f;
  3282. printinfo.fixed_width_font = true;
  3283. Con_NXPrintf( &printinfo, "IO stats from the last %d frames.\n", nFrameHistorySize );
  3284. int nPos = 3;
  3285. for ( int i = 0 ; i < nStatsSize ; ++i )
  3286. {
  3287. if ( nModes[i] == SKIPPED )
  3288. {
  3289. continue; // Skip this stat, not interesting...
  3290. }
  3291. printinfo.index = nPos++;
  3292. float flAverage = ( float )( nAvgStats[i] ) / ( float )( nFrameHistorySize );
  3293. const float flFrameRate = 30.0f; // Hardcoded at this moment
  3294. float flAveragePerSec = flAverage * flFrameRate;
  3295. // It seems that %3.1f format is not respected (at least on PS3, switch everything to %d).
  3296. // Also there is no point displaying min, it is pretty much always 0.
  3297. switch ( nModes[i] )
  3298. {
  3299. case NORMAL:
  3300. Con_NXPrintf( &printinfo, "%s - Avg:%5d - Max:%5d -%5d /s\n", pStatsTitle[i], ( int )flAverage, nMaxStats[i], ( int )flAveragePerSec );
  3301. //Con_NXPrintf( &printinfo, "%s - Min:%2d - Avg:% 3.1f - Max:%5d -% 3.1f /s\n", pStatsTitle[i], nMinStats[i], flAverage, nMaxStats[i], flAveragePerSec );
  3302. break;
  3303. case IN_MS:
  3304. Con_NXPrintf( &printinfo, "%s - Avg:%5d ms - Max:%5d ms -%5d ms/s\n", pStatsTitle[i], ( int )flAverage, nMaxStats[i], ( int )flAveragePerSec );
  3305. //Con_NXPrintf( &printinfo, "%s - Min:%2d ms - Avg:% 3.1f ms - Max:%5d ms -% 3.1f ms/s\n", pStatsTitle[i], nMinStats[i], flAverage, nMaxStats[i], flAveragePerSec );
  3306. break;
  3307. case IN_BYTES:
  3308. {
  3309. //int nMin = nMinStats[i] / 1024;
  3310. flAverage /= 1024.f;
  3311. int nMax = nMaxStats[i] / 1024;
  3312. flAveragePerSec /= 1024.f;
  3313. Con_NXPrintf( &printinfo, "%s - Avg:%5d Kb - Max:%5d Kb -%5d Kb/s\n", pStatsTitle[i], ( int )flAverage, nMax, ( int )flAveragePerSec );
  3314. }
  3315. break;
  3316. }
  3317. }
  3318. extern float g_fDelayForChoreo;
  3319. printinfo.index = nPos++;
  3320. Con_NXPrintf( &printinfo, "Delay for choreo: %5d ms\n", ( int )( g_fDelayForChoreo * 1000 ) );
  3321. }
  3322. #endif
  3323. #define LOG_FRAME_OUTPUT 0
  3324. void _Host_RunFrame (float time)
  3325. {
  3326. g_HostTimes.MarkFrameStartTime();
  3327. MDLCACHE_COARSE_LOCK_(g_pMDLCache);
  3328. static double host_remainder = 0.0f;
  3329. double prevremainder;
  3330. bool shouldrender;
  3331. #if defined( RAD_TELEMETRY_ENABLED )
  3332. if( g_Telemetry.DemoTickEnd == ( uint32 )-1 )
  3333. {
  3334. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
  3335. }
  3336. #endif
  3337. #ifndef DEDICATED
  3338. CClientState &cl = GetBaseLocalClient();
  3339. #endif
  3340. int numticks;
  3341. {
  3342. // Profile scope specific to the top of this function, protect from setjmp() problems
  3343. VPROF( "_Host_RunFrame_Upto_MarkFrame" );
  3344. if ( host_checkheap )
  3345. {
  3346. #if defined(_WIN32)
  3347. if ( _heapchk() != _HEAPOK )
  3348. {
  3349. Sys_Error( "_Host_RunFrame (top): _heapchk() != _HEAPOK\n" );
  3350. }
  3351. #endif
  3352. }
  3353. static double timeLastMemCompact;
  3354. if ( mem_incremental_compact_rate.GetFloat() > 0 )
  3355. {
  3356. double curTime = Plat_FloatTime();
  3357. if ( curTime - timeLastMemCompact > (double)mem_incremental_compact_rate.GetFloat() )
  3358. {
  3359. timeLastMemCompact = curTime;
  3360. g_pMemAlloc->CompactIncremental();
  3361. }
  3362. }
  3363. if ( host_Sleep.GetInt() )
  3364. {
  3365. Sys_Sleep( host_Sleep.GetInt() );
  3366. }
  3367. // Slow down the playback?
  3368. if ( g_iVCRPlaybackSleepInterval )
  3369. {
  3370. Sys_Sleep( g_iVCRPlaybackSleepInterval );
  3371. }
  3372. MapReslistGenerator().RunFrame();
  3373. static int lastrunoffsecond = -1;
  3374. if ( setjmp ( host_enddemo ) )
  3375. return; // demo finished.
  3376. // decide the simulation time
  3377. Host_AccumulateTime ( time );
  3378. _Host_SetGlobalTime();
  3379. shouldrender = !sv.IsDedicated();
  3380. // FIXME: Could track remainder as fractional ticks instead of msec
  3381. prevremainder = host_remainder;
  3382. if ( prevremainder < 0 )
  3383. prevremainder = 0;
  3384. #if !defined(DEDICATED)
  3385. if ( !demoplayer->IsPlaybackPaused() )
  3386. #endif
  3387. {
  3388. host_remainder += host_frametime;
  3389. }
  3390. numticks = 0; // how many ticks we will simulate this frame
  3391. // If we're using sv_alternateticks, make sure there are at least 2 ticks worth of host_remainder time to consume
  3392. #if defined( LINUX )
  3393. bool bAlternateTicks = false;
  3394. #else
  3395. bool bAlternateTicks = sv_alternateticks.GetBool() && ( GetBaseLocalClient().m_nMaxClients == 1 );
  3396. #endif
  3397. float flMinimumTickInterval = bAlternateTicks ? host_state.interval_per_tick * 2.0f : host_state.interval_per_tick;
  3398. if ( host_remainder >= flMinimumTickInterval )
  3399. {
  3400. numticks = (int)( floor(host_remainder / host_state.interval_per_tick ) );
  3401. // round to nearest even ending tick in alternate ticks mode so the last
  3402. // tick is always simulated prior to updating the network data
  3403. if ( bAlternateTicks )
  3404. {
  3405. int startTick = g_ServerGlobalVariables.tickcount;
  3406. int endTick = startTick + numticks;
  3407. endTick = endTick & ~(0x1); // an even number of ticks, rounding down
  3408. numticks = endTick - startTick;
  3409. }
  3410. host_remainder -= numticks * host_state.interval_per_tick;
  3411. }
  3412. host_nexttick = host_state.interval_per_tick - host_remainder;
  3413. g_pMDLCache->MarkFrame();
  3414. #if !( defined( _CERT ) || defined( DEDICATED ) )
  3415. if ( host_print_frame_times.GetBool() )
  3416. {
  3417. PrintHostFrameTimes( numticks, host_remainder, flMinimumTickInterval );
  3418. }
  3419. if ( fs_enable_stats.GetBool() )
  3420. {
  3421. PrintFsStats();
  3422. }
  3423. #endif // !_CERT || !DEDICATED
  3424. }
  3425. {
  3426. // Profile scope, protect from setjmp() problems
  3427. VPROF( "_Host_RunFrame" );
  3428. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  3429. // process console commands
  3430. #if defined( _GAMECONSOLE ) && !defined( _CERT )
  3431. static volatile bool s_bMemDebug = !!CommandLine()->FindParm( "-mem_dump_frames" );
  3432. if ( s_bMemDebug )
  3433. Cbuf_AddText( CBUF_FIRST_PLAYER, "mem_dump;\n" );
  3434. static char s_chBufferConCommandHack[256] = {0};
  3435. if ( s_chBufferConCommandHack[0] )
  3436. {
  3437. Cbuf_AddText( CBUF_FIRST_PLAYER, s_chBufferConCommandHack );
  3438. s_chBufferConCommandHack[0] = 0;
  3439. }
  3440. #endif
  3441. Cbuf_Execute ();
  3442. if ( NET_IsDedicatedForXbox() )
  3443. {
  3444. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  3445. {
  3446. NET_SetMultiplayer( true );
  3447. }
  3448. }
  3449. else
  3450. {
  3451. // initialize networking after commandline & autoexec.cfg have been parsed
  3452. NET_Init( NET_IsDedicated() );
  3453. }
  3454. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  3455. // Msg( "Running %i ticks (%f remainder) for frametime %f total %f tick %f delta %f\n", numticks, remainder, host_frametime, host_time );
  3456. g_ServerGlobalVariables.interpolation_amount = 0.0f;
  3457. #ifndef DEDICATED
  3458. g_ClientGlobalVariables.interpolation_amount = 0.0f;
  3459. cl.insimulation = true;
  3460. #endif
  3461. host_frameticks = numticks;
  3462. host_currentframetick = 0;
  3463. #if !defined( DEDICATED )
  3464. // This is to make the tool do both sim + rendering on the initial frame
  3465. // cl.IsActive changes in the loop below, as does scr_nextdrawtick
  3466. // We're just caching off the state here so that we have a consistent return value
  3467. // for enginetool->IsInGame the entire frame
  3468. g_pEngineToolInternal->SetIsInGame( cl.IsActive() && ( scr_nextdrawtick == 0 ) );
  3469. #endif
  3470. CJob *pGameJob = NULL;
  3471. // threaded path only supported in listen server
  3472. #ifndef DEDICATED
  3473. if ( !IsEngineThreaded() )
  3474. #endif
  3475. {
  3476. #ifndef DEDICATED
  3477. if ( g_ClientDLL )
  3478. {
  3479. g_ClientDLL->IN_SetSampleTime(host_frametime);
  3480. }
  3481. g_ClientGlobalVariables.simTicksThisFrame = 1;
  3482. #endif
  3483. #ifndef DEDICATED
  3484. cl.m_tickRemainder = host_remainder;
  3485. cl.SetFrameTime( host_frametime );
  3486. #endif
  3487. g_ServerGlobalVariables.simTicksThisFrame = 1;
  3488. for ( int tick = 0; tick < numticks; tick++ )
  3489. {
  3490. // Emit an ETW event every simulation frame.
  3491. ETWSimFrameMark( sv.IsDedicated() );
  3492. double now = Plat_FloatTime();
  3493. float jitter = now - host_idealtime;
  3494. // Track jitter (delta between ideal time and actual tick execution time)
  3495. host_jitterhistory[ host_jitterhistorypos ] = jitter;
  3496. host_jitterhistorypos = ( host_jitterhistorypos + 1 ) % ARRAYSIZE(host_jitterhistory);
  3497. // Very slowly decay "ideal" towards current wall clock unless delta is large
  3498. if ( fabs( jitter ) > 1.0f )
  3499. {
  3500. host_idealtime = now;
  3501. }
  3502. else
  3503. {
  3504. host_idealtime = 0.99 * host_idealtime + 0.01 * now;
  3505. }
  3506. // process any asynchronous network traffic (TCP), set net_time
  3507. NET_RunFrame( now );
  3508. // Only send updates on final tick so we don't re-encode network data multiple times per frame unnecessarily
  3509. bool bFinalTick = ( tick == (numticks - 1) );
  3510. if ( NET_IsDedicatedForXbox() )
  3511. {
  3512. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  3513. {
  3514. NET_SetMultiplayer( true );
  3515. }
  3516. }
  3517. else
  3518. {
  3519. // initialize networking after commandline & autoexec.cfg have been parsed
  3520. NET_Init( NET_IsDedicated() );
  3521. }
  3522. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  3523. // NOTE: Do we want do this at start or end of this loop?
  3524. ++host_tickcount;
  3525. ++host_currentframetick;
  3526. #ifndef DEDICATED
  3527. g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
  3528. // Make sure state is correct
  3529. CL_CheckClientState();
  3530. #endif
  3531. //-------------------
  3532. // input processing
  3533. //-------------------
  3534. if ( host_runframe_input_parcelremainder.GetBool() )
  3535. {
  3536. //sv_alternateticks creates instances where we're guaranteed to have a first-loop prevremainder of more than a tick, creating negative frame times for input deeper down
  3537. float fParcelRemainder = MIN( prevremainder, host_state.interval_per_tick );
  3538. _Host_RunFrame_Input( fParcelRemainder, bFinalTick );
  3539. prevremainder -= fParcelRemainder;
  3540. }
  3541. else
  3542. {
  3543. _Host_RunFrame_Input( prevremainder, bFinalTick );
  3544. prevremainder = 0;
  3545. }
  3546. //-------------------
  3547. //
  3548. // server operations
  3549. //
  3550. //-------------------
  3551. _Host_RunFrame_Server( bFinalTick );
  3552. // Additional networking ops for SPLITPACKET stuff (99.9% of the time this will be an empty list of work)
  3553. NET_SendQueuedPackets();
  3554. //-------------------
  3555. //
  3556. // client operations
  3557. //
  3558. //-------------------
  3559. #ifndef DEDICATED
  3560. if ( !sv.IsDedicated() )
  3561. {
  3562. _Host_RunFrame_Client( bFinalTick );
  3563. }
  3564. toolframework->Think( bFinalTick );
  3565. #endif
  3566. host_idealtime += host_state.interval_per_tick;
  3567. }
  3568. #if defined( VOICE_OVER_IP ) && !defined( DEDICATED )
  3569. // Send any enqueued voice data to the server
  3570. CL_ProcessVoiceData();
  3571. if ( numticks == 0 )
  3572. {
  3573. _Host_ProcessVoice_Server();
  3574. }
  3575. #endif // VOICE_OVER_IP && !DEDICATED
  3576. // run HLTV (both active, and not yet connected)
  3577. for ( CHltvServerIterator hltv; hltv; hltv.Next() )
  3578. {
  3579. hltv->RunFrame();
  3580. }
  3581. if ( hltvtest )
  3582. {
  3583. hltvtest->RunFrame();
  3584. }
  3585. #if defined( REPLAY_ENABLED )
  3586. // run replay if active
  3587. if ( replay )
  3588. {
  3589. replay->RunFrame();
  3590. if ( g_pServerReplayHistoryManager )
  3591. g_pServerReplayHistoryManager->Update();
  3592. }
  3593. if ( g_pClientReplayHistoryManager && g_pClientReplayHistoryManager->IsInitialized() )
  3594. g_pClientReplayHistoryManager->Update();
  3595. #endif
  3596. #ifndef DEDICATED
  3597. // This is a hack to let timedemo pull messages from the queue faster than every 15 msec
  3598. // Also when demoplayer is skipping packets to a certain tick we should process the queue
  3599. // as quickly as we can.
  3600. if ( numticks == 0 && ( demoplayer->IsPlayingTimeDemo() || demoplayer->IsSkipping() ) )
  3601. {
  3602. _Host_RunFrame_Client( true );
  3603. }
  3604. if ( !sv.IsDedicated() )
  3605. {
  3606. // This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
  3607. Host_SetClientInSimulation( false );
  3608. // Now allow for interpolation on client
  3609. g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
  3610. //-------------------
  3611. // Run prediction if it hasn't been run yet
  3612. //-------------------
  3613. // If we haven't predicted/simulated the player (multiplayer with prediction enabled and
  3614. // not a listen server with zero frame lag, then go ahead and predict now
  3615. CL_RunPrediction( PREDICTION_NORMAL );
  3616. CL_ApplyAddAngle();
  3617. // The mouse is always simulated for the current frame's time
  3618. // This makes updates smooth in every case
  3619. // continuous controllers affecting the view are also simulated this way
  3620. // but they have a cap applied by IN_SetSampleTime() so they are not also
  3621. // simulated during input gathering
  3622. CL_ExtraMouseUpdate( g_ClientGlobalVariables.frametime );
  3623. }
  3624. #endif
  3625. #if LOG_FRAME_OUTPUT
  3626. if ( !cl.IsPaused() || !sv.IsPaused() )
  3627. {
  3628. Msg("=============SIM: CLIENT %5d + %d, SERVER %5d + %d\t REM: %.2f\n", cl.GetClientTickCount(), numticks, sv.m_nTickCount, numticks, host_remainder*1000.0f );
  3629. }
  3630. #endif
  3631. }
  3632. #ifndef DEDICATED
  3633. else
  3634. {
  3635. static int numticks_last_frame = 0;
  3636. static float host_remainder_last_frame = 0, prev_remainder_last_frame = 0, last_frame_time = 0;
  3637. int clientticks;
  3638. int serverticks;
  3639. clientticks = numticks_last_frame;
  3640. cl.m_tickRemainder = host_remainder_last_frame;
  3641. cl.SetFrameTime( last_frame_time );
  3642. if ( g_ClientDLL )
  3643. {
  3644. g_ClientDLL->IN_SetSampleTime(last_frame_time);
  3645. }
  3646. last_frame_time = host_frametime;
  3647. serverticks = numticks;
  3648. g_ClientGlobalVariables.simTicksThisFrame = clientticks;
  3649. g_ServerGlobalVariables.simTicksThisFrame = serverticks;
  3650. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  3651. // THREADED: Run Client
  3652. // -------------------
  3653. for ( int tick = 0; tick < clientticks; tick++ )
  3654. {
  3655. // process any asynchronous network traffic (TCP), set net_time
  3656. NET_RunFrame( Plat_FloatTime() );
  3657. // Only send updates on final tick so we don't re-encode network data multiple times per frame unnecessarily
  3658. bool bFinalTick = ( tick == (clientticks - 1) );
  3659. if ( NET_IsDedicatedForXbox() )
  3660. {
  3661. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  3662. {
  3663. NET_SetMultiplayer( true );
  3664. }
  3665. }
  3666. else
  3667. {
  3668. // initialize networking after commandline & autoexec.cfg have been parsed
  3669. NET_Init( NET_IsDedicated() );
  3670. }
  3671. g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
  3672. // Make sure state is correct
  3673. CL_CheckClientState();
  3674. // Additional networking ops for SPLITPACKET stuff (99.9% of the time this will be an empty list of work)
  3675. NET_SendQueuedPackets();
  3676. //-------------------
  3677. //
  3678. // client operations
  3679. //
  3680. //-------------------
  3681. if ( !sv.IsDedicated() )
  3682. {
  3683. _Host_RunFrame_Client( bFinalTick );
  3684. }
  3685. toolframework->Think( bFinalTick );
  3686. }
  3687. #if defined( VOICE_OVER_IP )
  3688. // Send any enqueued voice data to the server
  3689. CL_ProcessVoiceData();
  3690. #endif // VOICE_OVER_IP
  3691. // This is a hack to let timedemo pull messages from the queue faster than every 15 msec
  3692. // Also when demoplayer is skipping packets to a certain tick we should process the queue
  3693. // as quickly as we can.
  3694. if ( clientticks == 0 && ( demoplayer->IsPlayingTimeDemo() || demoplayer->IsSkipping() ) )
  3695. {
  3696. _Host_RunFrame_Client( true );
  3697. }
  3698. // This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
  3699. Host_SetClientInSimulation( false );
  3700. // Now allow for interpolation on client
  3701. g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
  3702. //-------------------
  3703. // Run prediction if it hasn't been run yet
  3704. //-------------------
  3705. // If we haven't predicted/simulated the player (multiplayer with prediction enabled and
  3706. // not a listen server with zero frame lag, then go ahead and predict now
  3707. CL_RunPrediction( PREDICTION_NORMAL );
  3708. CL_ApplyAddAngle();
  3709. Host_SetClientInSimulation( true );
  3710. // THREADED: Run Input
  3711. // -------------------
  3712. int saveTick = g_ClientGlobalVariables.tickcount;
  3713. for ( int tick = 0; tick < serverticks; tick++ )
  3714. {
  3715. // NOTE: Do we want do this at start or end of this loop?
  3716. ++host_tickcount;
  3717. ++host_currentframetick;
  3718. g_ClientGlobalVariables.tickcount = host_tickcount;
  3719. bool bFinalTick = tick==(serverticks-1) ? true : false;
  3720. _Host_RunFrame_Input( prevremainder, bFinalTick );
  3721. prevremainder = 0;
  3722. // process any asynchronous network traffic (TCP), set net_time
  3723. NET_RunFrame( Plat_FloatTime() );
  3724. }
  3725. #if defined( VOICE_OVER_IP )
  3726. if ( serverticks == 0 )
  3727. {
  3728. _Host_ProcessVoice_Server();
  3729. }
  3730. #endif
  3731. Host_SetClientInSimulation( false );
  3732. // The mouse is always simulated for the current frame's time
  3733. // This makes updates smooth in every case
  3734. // continuous controllers affecting the view are also simulated this way
  3735. // but they have a cap applied by IN_SetSampleTime() so they are not also
  3736. // simulated during input gathering
  3737. CL_ExtraMouseUpdate( g_ClientGlobalVariables.frametime );
  3738. g_ClientGlobalVariables.tickcount = saveTick;
  3739. numticks_last_frame = numticks;
  3740. host_remainder_last_frame = host_remainder;
  3741. // THREADED: Run Server
  3742. // -------------------
  3743. // set net_time once before running the server
  3744. NET_SetTime( Plat_FloatTime() );
  3745. #ifdef _PS3
  3746. SNPROF("Kick sv");
  3747. g_pGcmSharedData->RunServer(_Host_RunFrame_Server_Async, serverticks);
  3748. pGameJob = (CJob*)1;
  3749. #else
  3750. pGameJob = new CFunctorJob( CreateFunctor( _Host_RunFrame_Server_Async, serverticks ) );
  3751. if ( IsX360() )
  3752. {
  3753. pGameJob->SetServiceThread( g_nServerThread );
  3754. }
  3755. g_pThreadPool->AddJob( pGameJob );
  3756. #endif
  3757. #if LOG_FRAME_OUTPUT
  3758. if ( !cl.IsPaused() || !sv.IsPaused() )
  3759. {
  3760. Msg("=============SIM: CLIENT %5d + %d, SERVER %5d + %d\t REM: %.2f\n", cl.GetClientTickCount(), clientticks, sv.m_nTickCount, serverticks, host_remainder*1000.0f );
  3761. }
  3762. #endif
  3763. }
  3764. #endif // DEDICATED
  3765. #if defined ( INCLUDE_SCALEFORM )
  3766. if ( g_pScaleformUI && shouldrender )
  3767. {
  3768. float timeScale = host_timescale.GetFloat() * sv.GetTimescale();
  3769. if ( timeScale <= 0.0f )
  3770. timeScale = 1.0f;
  3771. // using realtime here, because we never want scaleform menus paused (they fail to work).
  3772. // we may want to remove timescale here also
  3773. static float flLastScaleformRunFrame = g_ClientGlobalVariables.realtime;
  3774. g_pScaleformUI->RunFrame( ( g_ClientGlobalVariables.realtime - flLastScaleformRunFrame ) / timeScale );
  3775. flLastScaleformRunFrame = g_ClientGlobalVariables.realtime;
  3776. }
  3777. #endif
  3778. g_Log.RunFrame();
  3779. if ( shouldrender )
  3780. {
  3781. #if LOG_FRAME_OUTPUT
  3782. if ( !cl.IsPaused() || !sv.IsPaused() )
  3783. {
  3784. static float lastFrameTime = 0;
  3785. float frametime = g_ClientGlobalVariables.curtime - lastFrameTime;
  3786. Msg("RENDER AT: %6.4f: %.2fms [%.2fms implicit] frametime\n",
  3787. g_ClientGlobalVariables.curtime, g_ClientGlobalVariables.frametime*1000.0f, frametime * 1000.0f);
  3788. lastFrameTime = g_ClientGlobalVariables.curtime;
  3789. }
  3790. #endif
  3791. //-------------------
  3792. // rendering
  3793. //-------------------
  3794. _Host_RunFrame_Render();
  3795. //-------------------
  3796. // sound
  3797. //-------------------
  3798. _Host_RunFrame_Sound();
  3799. if ( g_bVCRSingleStep )
  3800. {
  3801. VCR_EnterPausedState();
  3802. }
  3803. }
  3804. //-------------------
  3805. // simulation
  3806. //-------------------
  3807. g_HostTimes.MarkSwapTime( );
  3808. #ifndef DEDICATED
  3809. if ( !sv.IsDedicated() )
  3810. {
  3811. VPROF_BUDGET( "_Host_RunFrame - ClientDLL_Update", VPROF_BUDGETGROUP_CLIENT_SIM );
  3812. // Client-side simulation
  3813. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CLDLL );
  3814. ClientDLL_Update();
  3815. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CLDLL );
  3816. }
  3817. #endif
  3818. if ( pGameJob )
  3819. {
  3820. {
  3821. VPROF_BUDGET( "WaitForAsyncServer", "AsyncServer" );
  3822. #ifndef _PS3
  3823. if ( Host_IsSinglePlayerGame() )
  3824. {
  3825. // This should change to a YieldWait if the server starts wanting to parallel process. If
  3826. // so, will need some route for the server to queue up work it wants to execute outside
  3827. // its frame, otherwise some of it would be performed during the yield. Right now
  3828. // need to wait for server so we don't stall on queued AI operations (toml 7/3/2007)
  3829. pGameJob->ExecuteAndRelease();
  3830. }
  3831. else
  3832. {
  3833. pGameJob->WaitForFinishAndRelease();
  3834. }
  3835. #else
  3836. SNPROF("WaitFor Sv");
  3837. g_pGcmSharedData->WaitForServer();
  3838. #endif
  3839. }
  3840. SV_FrameExecuteThreadDeferred();
  3841. }
  3842. Host_EndThreadedSound();
  3843. //-------------------
  3844. // time
  3845. //-------------------
  3846. Host_Speeds();
  3847. Host_UpdateMapList();
  3848. host_framecount++;
  3849. #if !defined(DEDICATED)
  3850. if ( !demoplayer->IsPlaybackPaused() )
  3851. {
  3852. host_time = host_tickcount * host_state.interval_per_tick + cl.m_tickRemainder;
  3853. }
  3854. #endif
  3855. Host_PostFrameRate( host_frametime );
  3856. if ( host_checkheap )
  3857. {
  3858. #ifdef _WIN32
  3859. if ( _heapchk() != _HEAPOK )
  3860. {
  3861. Sys_Error( "_Host_RunFrame (bottom): _heapchk() != _HEAPOK\n" );
  3862. }
  3863. #endif
  3864. }
  3865. Status_CheckSendETWMark();
  3866. Host_CheckDumpMemoryStats();
  3867. GetTestScriptMgr()->CheckPoint( "frame_end" );
  3868. } // Profile scope, protect from setjmp() problems
  3869. Host_ShowIPCCallCount();
  3870. }
  3871. /*
  3872. ==============================
  3873. Host_Frame
  3874. ==============================
  3875. */
  3876. void Host_RunFrame( float time )
  3877. {
  3878. static double timetotal = 0;
  3879. static int timecount = 0;
  3880. static double timestart = 0;
  3881. #ifndef DEDICATED
  3882. if ( !scr_drawloading && sv.IsActive() && GetBaseLocalClient().IsActive() && !sv.m_bLoadgame)
  3883. {
  3884. switch ( host_thread_mode.GetInt() )
  3885. {
  3886. case HTM_DISABLED: g_bThreadedEngine = false; break;
  3887. case HTM_DEFAULT: g_bThreadedEngine = ( g_pThreadPool->NumThreads() > 0 ); break;
  3888. case HTM_FORCED: g_bThreadedEngine = true; break;
  3889. }
  3890. #ifdef _PS3
  3891. g_bThreadedEngine = true; // Not reqd anuymore ?
  3892. #endif
  3893. }
  3894. else
  3895. #endif
  3896. {
  3897. g_bThreadedEngine = false;
  3898. }
  3899. {
  3900. VPROF( "UpdateDynamicModels" );
  3901. CMDLCacheCriticalSection critsec(g_pMDLCache);
  3902. modelloader->UpdateDynamicModels();
  3903. }
  3904. if ( !host_profile.GetBool() )
  3905. {
  3906. _Host_RunFrame( time );
  3907. return;
  3908. }
  3909. double time1 = Sys_FloatTime();
  3910. _Host_RunFrame( time );
  3911. double time2 = Sys_FloatTime();
  3912. timetotal += time2 - time1; // time in seconds
  3913. timecount++;
  3914. if (timecount < 1000)
  3915. return;
  3916. float fps = 1000/(time2 - timestart);
  3917. ConMsg ("host_profile : %i clients, %.1f msec, %.1f fps\n",
  3918. sv.GetNumClients(), timetotal, fps );
  3919. timecount = 0;
  3920. timetotal = 0;
  3921. timestart = time2;
  3922. }
  3923. //-----------------------------------------------------------------------------
  3924. // If the user passed -lv on the command-line, they want low violence mode.
  3925. //-----------------------------------------------------------------------------
  3926. bool IsLowViolence_CommandLine()
  3927. {
  3928. #if defined( _LOWVIOLENCE )
  3929. // a low violence build can not be-undone
  3930. return true;
  3931. #endif
  3932. return ( CommandLine()->FindParm( "-lv" ) != 0 );
  3933. }
  3934. #ifndef DEDICATED
  3935. //-----------------------------------------------------------------------------
  3936. // A more secure means of enforcing low violence.
  3937. //-----------------------------------------------------------------------------
  3938. bool IsLowViolence_Secure()
  3939. {
  3940. // CS:GO does not have any low violence regions. Ignore what Steam reports.
  3941. #if defined( CSTRIKE15 )
  3942. return false;
  3943. #endif
  3944. #ifndef _GAMECONSOLE
  3945. if ( IsPC() && Steam3Client().SteamApps() )
  3946. {
  3947. // let Steam determine current violence settings
  3948. return Steam3Client().SteamApps()->BIsLowViolence();
  3949. }
  3950. #endif
  3951. if ( IsGameConsole() )
  3952. {
  3953. #if defined( _LOWVIOLENCE )
  3954. // a low violence build can not be-undone
  3955. return true;
  3956. #endif
  3957. // Users can opt into low violence mode on the command-line.
  3958. if ( IsLowViolence_CommandLine() )
  3959. {
  3960. return true;
  3961. }
  3962. }
  3963. return false;
  3964. }
  3965. //-----------------------------------------------------------------------------
  3966. // If "User Token 2" exists in HKEY_CURRENT_USER/Software/Valve/Half-Life/Settings
  3967. // then we disable gore. Obviously not very secure.
  3968. //-----------------------------------------------------------------------------
  3969. bool IsLowViolence_Registry()
  3970. {
  3971. if ( IsGameConsole() )
  3972. {
  3973. #if defined( _LOWVIOLENCE )
  3974. // a low violence build can not be-undone
  3975. return true;
  3976. #endif
  3977. // Users can opt into low violence mode on the command-line.
  3978. if ( IsLowViolence_CommandLine() )
  3979. {
  3980. return true;
  3981. }
  3982. }
  3983. // CS:GO does not have any low violence regions. Ignore the registry settings.
  3984. #if defined( CSTRIKE15 )
  3985. return false;
  3986. #endif
  3987. char szSubKey[128];
  3988. int nBufferLen;
  3989. char szBuffer[128];
  3990. bool bReducedGore = false;
  3991. memset( szBuffer, 0, 128 );
  3992. char const *appname = "Source";
  3993. Q_snprintf(szSubKey, sizeof( szSubKey ), "Software\\Valve\\%s\\Settings", appname );
  3994. nBufferLen = 127;
  3995. Q_strncpy( szBuffer, "", sizeof( szBuffer ) );
  3996. Sys_GetRegKeyValue( szSubKey, "User Token 2", szBuffer, nBufferLen, szBuffer );
  3997. // Gore reduction active?
  3998. bReducedGore = ( Q_strlen( szBuffer ) > 0 ) ? true : false;
  3999. if ( !bReducedGore )
  4000. {
  4001. Sys_GetRegKeyValue( szSubKey, "User Token 3", szBuffer, nBufferLen, szBuffer );
  4002. bReducedGore = ( Q_strlen( szBuffer ) > 0 ) ? true : false;
  4003. }
  4004. char gamedir[MAX_OSPATH];
  4005. Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
  4006. // also check mod specific directories for LV changes
  4007. Q_snprintf(szSubKey, sizeof( szSubKey ), "Software\\Valve\\%s\\%s\\Settings", appname, gamedir );
  4008. nBufferLen = 127;
  4009. Q_strncpy( szBuffer, "", sizeof( szBuffer ) );
  4010. Sys_GetRegKeyValue( szSubKey, "User Token 2", szBuffer, nBufferLen, szBuffer );
  4011. if ( Q_strlen( szBuffer ) > 0 )
  4012. {
  4013. bReducedGore = true;
  4014. }
  4015. Sys_GetRegKeyValue( szSubKey, "User Token 3", szBuffer, nBufferLen, szBuffer );
  4016. if ( Q_strlen( szBuffer ) > 0 )
  4017. {
  4018. bReducedGore = true;
  4019. }
  4020. return bReducedGore;
  4021. }
  4022. #endif
  4023. //-----------------------------------------------------------------------------
  4024. //-----------------------------------------------------------------------------
  4025. void Host_CheckGore( void )
  4026. {
  4027. bool bLowViolenceRegistry = false;
  4028. bool bLowViolenceSecure = false;
  4029. bool bLowViolenceCommandLine = IsLowViolence_CommandLine();
  4030. #ifndef DEDICATED
  4031. //
  4032. // First check the old method of enabling low violence via the registry.
  4033. //
  4034. #ifdef WIN32
  4035. bLowViolenceRegistry = IsLowViolence_Registry();
  4036. #endif
  4037. //
  4038. // Next check the new method of enabling low violence based on country of purchase
  4039. // and other means that are inaccessible by the user.
  4040. //
  4041. bLowViolenceSecure = IsLowViolence_Secure();
  4042. #endif
  4043. //
  4044. // If either method says "yes" to low violence, we're in low violence mode.
  4045. //
  4046. if ( bLowViolenceRegistry || bLowViolenceSecure || bLowViolenceCommandLine )
  4047. {
  4048. g_bLowViolence = true;
  4049. if ( bLowViolenceRegistry )
  4050. {
  4051. violence_hblood.SetValue( 0 );
  4052. violence_hgibs.SetValue( 0 );
  4053. violence_ablood.SetValue( 0 );
  4054. violence_agibs.SetValue( 0 );
  4055. }
  4056. }
  4057. else
  4058. {
  4059. g_bLowViolence = false;
  4060. }
  4061. }
  4062. //-----------------------------------------------------------------------------
  4063. // Purpose:
  4064. //-----------------------------------------------------------------------------
  4065. void Host_InitProcessor( void )
  4066. {
  4067. const CPUInformation& pi = GetCPUInformation();
  4068. // Compute Frequency in Mhz:
  4069. char* szFrequencyDenomination = "Mhz";
  4070. double fFrequency = pi.m_Speed / 1000000.0;
  4071. // Adjust to Ghz if nessecary:
  4072. if( fFrequency > 1000.0 )
  4073. {
  4074. fFrequency /= 1000.0;
  4075. szFrequencyDenomination = "Ghz";
  4076. }
  4077. char szFeatureString[256];
  4078. Q_strncpy( szFeatureString, pi.m_szProcessorID, sizeof( szFeatureString ) );
  4079. Q_strncat( szFeatureString, " ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4080. if( pi.m_bSSE )
  4081. {
  4082. if( MathLib_SSEEnabled() ) Q_strncat(szFeatureString, "SSE ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4083. else Q_strncat(szFeatureString, "(SSE) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4084. }
  4085. if( pi.m_bSSE2 )
  4086. {
  4087. if( MathLib_SSE2Enabled() ) Q_strncat(szFeatureString, "SSE2 ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4088. else Q_strncat(szFeatureString, "(SSE2) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4089. }
  4090. if( pi.m_bMMX )
  4091. {
  4092. if( MathLib_MMXEnabled() ) Q_strncat(szFeatureString, "MMX ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4093. else Q_strncat(szFeatureString, "(MMX) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4094. }
  4095. if( pi.m_bRDTSC ) Q_strncat(szFeatureString, "RDTSC ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4096. if( pi.m_bCMOV ) Q_strncat(szFeatureString, "CMOV ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4097. if( pi.m_bFCMOV ) Q_strncat(szFeatureString, "FCMOV ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  4098. // Remove the trailing space. There will always be one.
  4099. szFeatureString[Q_strlen(szFeatureString)-1] = '\0';
  4100. // Dump CPU information:
  4101. if( pi.m_nLogicalProcessors == 1 )
  4102. {
  4103. ConDMsg( "1 CPU, Frequency: %.01f %s, Features: %s\n",
  4104. fFrequency,
  4105. szFrequencyDenomination,
  4106. szFeatureString
  4107. );
  4108. }
  4109. else
  4110. {
  4111. char buffer[256] = "";
  4112. if( pi.m_nPhysicalProcessors != pi.m_nLogicalProcessors )
  4113. {
  4114. Q_snprintf(buffer, sizeof( buffer ), " (%i physical)", (int) pi.m_nPhysicalProcessors );
  4115. }
  4116. ConDMsg( "%i CPUs%s, Frequency: %.01f %s, Features: %s\n",
  4117. (int)pi.m_nLogicalProcessors,
  4118. buffer,
  4119. fFrequency,
  4120. szFrequencyDenomination,
  4121. szFeatureString
  4122. );
  4123. }
  4124. #if defined( _WIN32 )
  4125. if ( s_bInitPME )
  4126. {
  4127. // Initialize the performance monitoring events code.
  4128. InitPME();
  4129. }
  4130. #endif
  4131. }
  4132. //-----------------------------------------------------------------------------
  4133. // Specifically used by the model loading code to mark models
  4134. // touched by the current map
  4135. //-----------------------------------------------------------------------------
  4136. int Host_GetServerCount( void )
  4137. {
  4138. #ifndef DEDICATED
  4139. if ( GetBaseLocalClient().m_nSignonState >= SIGNONSTATE_NEW ||
  4140. ( GetBaseLocalClient().m_nSignonState >= SIGNONSTATE_CONNECTED && GetBaseLocalClient().m_bServerInfoProcessed ) )
  4141. {
  4142. // the server count cannot be relied on until the server info message is processed
  4143. // the mulitple state checking state guarantees its validity
  4144. return GetBaseLocalClient().m_nServerCount;
  4145. }
  4146. else
  4147. #endif
  4148. if ( sv.m_State >= ss_loading )
  4149. {
  4150. return sv.GetSpawnCount();
  4151. }
  4152. // this is unfortunate, and happens, but the caller is too early in the protocol or a demo
  4153. // cannot identify the correct server count
  4154. // return the same count that demo will use
  4155. return gHostSpawnCount;
  4156. }
  4157. //-----------------------------------------------------------------------------
  4158. // Purpose:
  4159. //-----------------------------------------------------------------------------
  4160. void SpewInstallStatus( void )
  4161. {
  4162. if ( IsGameConsole() && g_pFullFileSystem )
  4163. {
  4164. #if defined( _X360 )
  4165. Msg( "\nXbox Launched From %s.\n", g_pFullFileSystem->IsLaunchedFromXboxHDD() ? "HDD" : "DVD" );
  4166. if ( g_pXboxInstaller )
  4167. {
  4168. g_pXboxInstaller->SpewStatus();
  4169. }
  4170. #elif defined( _PS3 )
  4171. // This is intended to match CXboxInstaller::SpewStatus as closely as possible:
  4172. Msg( "Install Status:\n" );
  4173. Msg( "Version: %u (%s) (ps3)\n", XBX_GetImageChangelist(), XBX_GetLanguageString() );
  4174. Msg( "DVD Hosted: Disabled\n" );
  4175. // This spew is XBox-specific (could be hooked up to the FIOS installer)
  4176. //if ( g_pFullFileSystem->IsInstalledToXboxHDDCache() )
  4177. //{
  4178. // Msg( "Existing Image Found.\n" );
  4179. //}
  4180. //if ( !IsInstallEnabled() )
  4181. //{
  4182. // Msg( "Install Enabled.\n" );
  4183. //}
  4184. //if ( IsFullyInstalled() )
  4185. //{
  4186. // Msg( "Fully Installed.\n" );
  4187. //}
  4188. //Msg( "Progress: %d/%d MB\n", GetCopyStats()->m_BytesCopied/(1024*1024), GetTotalSize()/(1024*1024) );
  4189. #endif
  4190. }
  4191. }
  4192. //-----------------------------------------------------------------------------
  4193. // Purpose:
  4194. //-----------------------------------------------------------------------------
  4195. void Host_PostInit()
  4196. {
  4197. if ( serverGameDLL )
  4198. {
  4199. serverGameDLL->PostInit();
  4200. }
  4201. #if !defined( DEDICATED )
  4202. if ( g_ClientDLL )
  4203. {
  4204. g_ClientDLL->PostInit();
  4205. }
  4206. toolframework->PostInit();
  4207. if ( !sv.IsDedicated() )
  4208. {
  4209. // vgui needs other systems to finalize
  4210. EngineVGui()->PostInit();
  4211. }
  4212. if ( serverGameDLL )
  4213. {
  4214. serverGameDLL->PostToolsInit();
  4215. }
  4216. SpewInstallStatus();
  4217. if ( IsGameConsole() )
  4218. {
  4219. // fully setup, can now publish cvars to vxconsole
  4220. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "getcvars" );
  4221. }
  4222. #endif
  4223. }
  4224. #if defined( REPLAY_ENABLED )
  4225. void Replay_Init()
  4226. {
  4227. Assert( replay == NULL );
  4228. }
  4229. void Replay_Shutdown()
  4230. {
  4231. if ( replay )
  4232. {
  4233. replay->Shutdown();
  4234. delete replay;
  4235. replay = NULL;
  4236. }
  4237. }
  4238. #endif
  4239. void HLTV_Init()
  4240. {
  4241. for ( int i = 0; i < HLTV_SERVER_MAX_COUNT; ++i )
  4242. Assert ( g_pHltvServer[ i ] == NULL );
  4243. Assert ( hltvtest == NULL );
  4244. }
  4245. void HLTV_Shutdown()
  4246. {
  4247. for ( int i = 0; i < HLTV_SERVER_MAX_COUNT; ++i )
  4248. {
  4249. if ( g_pHltvServer[ i ] )
  4250. {
  4251. g_pHltvServer[ i ]->Shutdown();
  4252. delete g_pHltvServer[ i ];
  4253. g_pHltvServer[ i ] = NULL;
  4254. }
  4255. }
  4256. if ( hltvtest )
  4257. {
  4258. delete hltvtest;
  4259. hltvtest = NULL;
  4260. }
  4261. }
  4262. void InstallConVarHook( void );
  4263. int g_nForkID = 0;
  4264. int g_nSocketToParentProcess = -1;
  4265. #ifdef _LINUX
  4266. #include <sys/socket.h>
  4267. #include <sys/types.h>
  4268. void SendStringToParentProcess( char const *pMsg )
  4269. {
  4270. Assert( IsChildProcess() );
  4271. Assert( g_nSocketToParentProcess != -1 );
  4272. send( g_nSocketToParentProcess, pMsg, 1 + strlen( pMsg ), MSG_DONTWAIT );
  4273. }
  4274. #endif
  4275. CDebugInputThread * g_pDebugInputThread;
  4276. //--------------------------------------------------------------------------------------------------
  4277. // PS3 QMS/Server thread
  4278. //--------------------------------------------------------------------------------------------------
  4279. #ifdef _PS3
  4280. static uint32 QMSServerThreadEntry(void* param)
  4281. {
  4282. while(1)
  4283. {
  4284. // Wait on semaphore
  4285. // For each semaphore posted, we look to see if we should run either "job"
  4286. // It is also possible to decr the semaphore, only to have nothing to run...
  4287. // ie The semaphore is a wakeup rather than a count of jobs
  4288. sys_semaphore_wait(g_pGcmSharedData->m_semaphore, 0);
  4289. g_pGcmSharedData->CheckForAudioRequest();
  4290. g_pGcmSharedData->CheckForServerRequest();
  4291. if (g_pGcmSharedData->m_qmsRunFlag)
  4292. {
  4293. g_pGcmSharedData->m_qmsRunFlag = 0;
  4294. void* p1 = (void*)g_pGcmSharedData->m_cmat;
  4295. void* p2 = (void*)g_pGcmSharedData->m_ptr;
  4296. g_pGcmSharedData->m_func(p1, p2);
  4297. g_pGcmSharedData->m_qmsDoneFlag = 1;
  4298. }
  4299. }
  4300. return 0;
  4301. }
  4302. static void CreateQMSServerThread()
  4303. {
  4304. CreateSimpleThread(QMSServerThreadEntry, 0, 0x40000);
  4305. }
  4306. #endif
  4307. // Check with steam to see if the requested file (requires full path) is a valid, signed binary
  4308. #define SignatureWarning( ... ) ((void)(0))
  4309. static bool Host_IsValidSignature( const char *pFilename, bool bAllowUnknown )
  4310. {
  4311. #if defined( DEDICATED ) || defined( _GAMECONSOLE )
  4312. return true;
  4313. #else
  4314. if ( Steam3Client().SteamUtils() )
  4315. {
  4316. SteamAPICall_t hAPICall = Steam3Client().SteamUtils()->CheckFileSignature( pFilename );
  4317. bool bAPICallFailed = true;
  4318. while ( !Steam3Client().SteamUtils()->IsAPICallCompleted(hAPICall, &bAPICallFailed) )
  4319. {
  4320. SteamAPI_RunCallbacks();
  4321. ThreadSleep( 1 );
  4322. }
  4323. if( bAPICallFailed )
  4324. {
  4325. SignatureWarning( "CheckFileSignature API call on %s failed", pFilename );
  4326. }
  4327. else
  4328. {
  4329. CheckFileSignature_t result;
  4330. Steam3Client().SteamUtils()->GetAPICallResult( hAPICall, &result, sizeof(result), result.k_iCallback, &bAPICallFailed );
  4331. if( bAPICallFailed )
  4332. {
  4333. SignatureWarning( "CheckFileSignature API call on %s failed\n", pFilename );
  4334. }
  4335. else
  4336. {
  4337. if( result.m_eCheckFileSignature == k_ECheckFileSignatureValidSignature || result.m_eCheckFileSignature == k_ECheckFileSignatureNoSignaturesFoundForThisApp )
  4338. return true;
  4339. if ( bAllowUnknown && result.m_eCheckFileSignature == k_ECheckFileSignatureNoSignaturesFoundForThisFile )
  4340. return true;
  4341. SignatureWarning( "No valid signature found for %s\n", pFilename );
  4342. }
  4343. }
  4344. }
  4345. return false;
  4346. #endif
  4347. }
  4348. // Ask steam if it is ok to load this DLL. Unsigned DLLs should not be loaded unless
  4349. // the client is running -insecure (testing a plugin for example)
  4350. // This keeps legitimate users with modified binaries from getting VAC banned because of them
  4351. #if defined( DEDICATED ) || defined( OSX ) || defined( LINUX )
  4352. #else
  4353. static CUtlVector< CUtlString * > g_PendingSignatureChecks;
  4354. static CUtlVector< CUtlString * > g_FailedSignatureChecks;
  4355. #endif
  4356. bool Host_AllowLoadModule( const char *pFilename, const char *pPathID, bool bAllowUnknown )
  4357. {
  4358. #if defined( DEDICATED ) || defined( OSX ) || defined( LINUX )
  4359. // dedicated servers don't check signatures
  4360. // OSX and Linux have no ability to check signatures
  4361. return true;
  4362. #else
  4363. // Allow loading plugins
  4364. if ( sv.IsDedicated() )
  4365. return true;
  4366. // check signature
  4367. bool bSignatureIsValid = false;
  4368. if ( g_bAllowSecureServers && Steam3Client().SteamUtils() )
  4369. {
  4370. char szDllname[512];
  4371. V_strncpy( szDllname, pFilename, sizeof(szDllname) );
  4372. V_SetExtension( szDllname, DLL_EXT_STRING, sizeof(szDllname) );
  4373. if ( pPathID )
  4374. {
  4375. char szFullPath[ 512 ];
  4376. const char *pFullPath = g_pFileSystem->RelativePathToFullPath( szDllname, pPathID, szFullPath, sizeof(szFullPath) );
  4377. if ( !pFullPath )
  4378. {
  4379. SignatureWarning("Can't find %s on disk\n", szDllname );
  4380. bSignatureIsValid = false;
  4381. }
  4382. else
  4383. {
  4384. if ( CommandLine()->FindParm( "-immediatesignaturechecks" ) )
  4385. {
  4386. bSignatureIsValid = Host_IsValidSignature( pFullPath, bAllowUnknown );
  4387. }
  4388. else
  4389. {
  4390. g_PendingSignatureChecks.AddToTail( new CUtlString( pFullPath ) );
  4391. bSignatureIsValid = true;
  4392. }
  4393. }
  4394. }
  4395. else
  4396. {
  4397. if ( CommandLine()->FindParm( "-immediatesignaturechecks" ) )
  4398. {
  4399. bSignatureIsValid = Host_IsValidSignature( szDllname, bAllowUnknown );
  4400. }
  4401. else
  4402. {
  4403. g_PendingSignatureChecks.AddToTail( new CUtlString( szDllname ) );
  4404. bSignatureIsValid = true;
  4405. }
  4406. }
  4407. }
  4408. else
  4409. {
  4410. if ( g_bAllowSecureServers )
  4411. {
  4412. SignatureWarning("Steam is not active, running in -insecure mode.\n");
  4413. }
  4414. g_bAllowSecureServers = false;
  4415. }
  4416. if ( bSignatureIsValid )
  4417. return true;
  4418. if ( !g_bAllowSecureServers )
  4419. {
  4420. SignatureWarning("Loading unsigned module %s\nAccess to secure servers is disabled.\n", pFilename );
  4421. return true;
  4422. }
  4423. return false;
  4424. #endif
  4425. }
  4426. bool Host_IsSecureServerAllowed()
  4427. {
  4428. if ( CommandLine()->FindParm("-insecure") || CommandLine()->FindParm("-tools") )
  4429. g_bAllowSecureServers = false;
  4430. return g_bAllowSecureServers;
  4431. }
  4432. void Host_DisallowSecureServers()
  4433. {
  4434. #if !defined(DEDICATED)
  4435. if ( g_bAllowSecureServers && ( GetBaseLocalClient().IsConnected() || sv.IsActive() ) )
  4436. { // Force-disconnect local client if secure mode changes mid-connection
  4437. GetBaseLocalClient().Disconnect( true );
  4438. }
  4439. g_bAllowSecureServers = false;
  4440. #endif
  4441. }
  4442. void Host_FinishSecureSignatureChecks()
  4443. {
  4444. #if defined( DEDICATED ) || defined( OSX ) || defined( LINUX )
  4445. #else
  4446. while ( g_PendingSignatureChecks.Count() )
  4447. {
  4448. // CSGO May 2017 checking via library loader hook
  4449. // bool bSignatureIsValid = Host_IsValidSignature( g_PendingSignatureChecks.Head()->Get(), false );
  4450. bool bSignatureIsValid = true;
  4451. if ( !bSignatureIsValid )
  4452. {
  4453. SignatureWarning( "Loaded unsigned module %s\nAccess to secure servers is disabled.\n", g_PendingSignatureChecks.Head()->Get() );
  4454. g_bAllowSecureServers = false;
  4455. g_FailedSignatureChecks.AddToTail( new CUtlString( g_PendingSignatureChecks.Head()->Get() ) );
  4456. }
  4457. delete g_PendingSignatureChecks.Head();
  4458. g_PendingSignatureChecks.FastRemove( 0 );
  4459. }
  4460. g_PendingSignatureChecks.PurgeAndDeleteElements();
  4461. // Also check the main .exe that is running us
  4462. TCHAR tchBufExe[ MAX_PATH ] = {};
  4463. DWORD dwResult = GetModuleFileName( NULL, tchBufExe, MAX_PATH );
  4464. if ( dwResult > 0 && dwResult < MAX_PATH-1 )
  4465. {
  4466. bool bSignatureIsValid = Host_IsValidSignature( tchBufExe, false );
  4467. if ( !bSignatureIsValid )
  4468. {
  4469. SignatureWarning( "Loaded unsigned module %s\nAccess to secure servers is disabled.\n", tchBufExe );
  4470. g_bAllowSecureServers = false;
  4471. g_FailedSignatureChecks.AddToTail( new CUtlString( tchBufExe ) );
  4472. }
  4473. }
  4474. else
  4475. {
  4476. SignatureWarning( "Failed to determine exe module filename.\nAccess to secure servers is disabled.\n" );
  4477. g_bAllowSecureServers = false;
  4478. g_FailedSignatureChecks.AddToTail( new CUtlString( "" ) );
  4479. }
  4480. // if ( IScaleformSlotInitController *pCtrlr = g_ClientDLL->GetScaleformSlotInitController() )
  4481. // pCtrlr->PassSignaturesArray( &g_FailedSignatureChecks );
  4482. #endif
  4483. }
  4484. #if !defined( DEDICATED ) && defined( INCLUDE_SCALEFORM )
  4485. class CScaleformSlotInitControllerEngineImpl : public IScaleformSlotInitController
  4486. {
  4487. public:
  4488. // A new slot has been created and InitSlot almost finished, perform final configuration
  4489. virtual void ConfigureNewSlotPostInit( int slot )
  4490. {
  4491. };
  4492. // Notification to external systems that a file was loaded by Scaleform libraries
  4493. virtual bool OnFileLoadedByScaleform( char const *pszFilename, void *pvBuffer, int numBytesLoaded )
  4494. {
  4495. Host_DisallowSecureServers();
  4496. return false;
  4497. }
  4498. virtual const void * GetStringUserData( const char * pchStringTableName, const char * pchKeyName, int * pLength )
  4499. {
  4500. int numTables = GetBaseLocalClient().m_StringTableContainer->GetNumTables();
  4501. CNetworkStringTable *pTable = NULL;
  4502. for ( int i = 0; i < numTables; i++ )
  4503. {
  4504. // iterate through server tables
  4505. pTable = ( CNetworkStringTable* )GetBaseLocalClient().m_StringTableContainer->GetTable( i );
  4506. if ( !pTable )
  4507. continue;
  4508. if ( !V_strcmp( pTable->GetTableName(), pchStringTableName ) )
  4509. break;
  4510. }
  4511. if ( pTable )
  4512. {
  4513. int index = pTable->FindStringIndex( pchKeyName );
  4514. if ( index != ::INVALID_STRING_INDEX )
  4515. {
  4516. return pTable->GetStringUserData( index, pLength );
  4517. }
  4518. }
  4519. return NULL;
  4520. }
  4521. virtual void PassSignaturesArray( void *pvArray )
  4522. {
  4523. ;
  4524. }
  4525. }
  4526. g_CScaleformSlotInitControllerEngineImpl;
  4527. IScaleformSlotInitController *g_pIScaleformSlotInitControllerEngineImpl = &g_CScaleformSlotInitControllerEngineImpl;
  4528. #endif
  4529. bool Should360EmulatePS3()
  4530. {
  4531. return ( IsX360() && CommandLine()->FindParm( "-ps3" ) );
  4532. }
  4533. static bool s_bDedicatedForPurposesOfThreadPool = false;
  4534. void GetThreadPoolStartParams( ThreadPoolStartParams_t &startParams )
  4535. {
  4536. if ( IsX360() )
  4537. {
  4538. // 360 overrides defaults, 2 computation threads distributed to core 1 and 2
  4539. if ( !Should360EmulatePS3() )
  4540. {
  4541. startParams.nThreads = 2;
  4542. startParams.nStackSize = 256 * 1024;
  4543. startParams.fDistribute = TRS_TRUE;
  4544. startParams.bUseAffinityTable = true;
  4545. startParams.iAffinityTable[ 0 ] = XBOX_PROCESSOR_2;
  4546. startParams.iAffinityTable[ 1 ] = XBOX_PROCESSOR_4;
  4547. }
  4548. else
  4549. {
  4550. startParams.nThreads = 1;
  4551. startParams.nStackSize = 256 * 1024;
  4552. startParams.fDistribute = TRS_TRUE;
  4553. startParams.bUseAffinityTable = true;
  4554. startParams.iAffinityTable[ 0 ] = XBOX_PROCESSOR_1;
  4555. ConVarRef cl_threaded_bone_setup( "cl_threaded_bone_setup" );
  4556. host_threaded_sound.SetValue( 0 );
  4557. cl_threaded_bone_setup.SetValue( 2 );
  4558. host_thread_mode.SetValue( 0 );
  4559. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "cache_gimp\n" );
  4560. g_nMaterialSystemThread = 0;
  4561. }
  4562. ThreadSetAffinity( NULL, 1 );
  4563. }
  4564. // Dedicated servers should not explicitly set the main thread's affinity so that machines running multiple
  4565. // copies of the dedicated server can load-balance properly.
  4566. // For now on the PC we use SetThreadIdealProcessor instead of explicity affinity
  4567. if ( !s_bDedicatedForPurposesOfThreadPool && IsPC() )
  4568. {
  4569. // this will set ideal processor on each thread
  4570. startParams.fDistribute = TRS_TRUE;
  4571. }
  4572. }
  4573. //-----------------------------------------------------------------------------
  4574. // Purpose:
  4575. //-----------------------------------------------------------------------------
  4576. void Host_Init( bool bDedicated )
  4577. {
  4578. realtime = 0;
  4579. host_idealtime = 0;
  4580. // this code is called prefork. If we are going to fork, we want to delay some stuff, because we might not even be acting as a "real" server.
  4581. #ifdef _LINUX
  4582. if ( CommandLine()->FindParm( "-fork" ) )
  4583. {
  4584. g_nForkID = FORK_ID_PARENT_PROCESS;
  4585. }
  4586. #endif
  4587. #if defined(_WIN32)
  4588. if ( CommandLine()->FindParm( "-pme" ) )
  4589. {
  4590. s_bInitPME = true;
  4591. }
  4592. #endif
  4593. if ( !bDedicated && Host_IsSecureServerAllowed() )
  4594. {
  4595. //
  4596. // Signature checking code:
  4597. //
  4598. /** Removed for partner depot **/
  4599. }
  4600. ThreadPoolStartParams_t startParams;
  4601. s_bDedicatedForPurposesOfThreadPool = bDedicated;
  4602. GetThreadPoolStartParams( startParams );
  4603. #ifdef _PS3
  4604. {
  4605. // PS3 overrides defaults,
  4606. if ( host_threaded_sound.GetBool() && ( !host_threaded_sound_simplethread.GetBool() ) )
  4607. {
  4608. startParams.nThreads = 1;
  4609. }
  4610. else
  4611. {
  4612. startParams.nThreads = 0;
  4613. }
  4614. // Second thread for CSGO, which is not a jobthread, so that we can more easily control "what runs where and whem"
  4615. g_pGcmSharedData->Init();
  4616. CreateQMSServerThread();
  4617. }
  4618. #endif
  4619. //////// DISABLE FOR SHIP! //////////
  4620. if ( !IsCert() || CommandLine()->FindParm( "-dbginput" ) )
  4621. {
  4622. g_pDebugInputThread = new CDebugInputThread();
  4623. g_pDebugInputThread->SetName( "Debug Input" );
  4624. g_pDebugInputThread->Start( 0, TP_PRIORITY_HIGH );
  4625. }
  4626. #ifndef _CERT
  4627. if ( CommandLine()->FindParm( "-tslist" ) )
  4628. {
  4629. int nTests = 10000;
  4630. Msg( "Running TSList tests\n" );
  4631. RunTSListTests( nTests );
  4632. Msg( "Running TSQueue tests\n" );
  4633. RunTSQueueTests( nTests );
  4634. Msg( "Running Thread Pool tests\n" );
  4635. RunThreadPoolTests();
  4636. }
  4637. #endif
  4638. if ( g_pThreadPool )
  4639. {
  4640. g_pThreadPool->Start( startParams );
  4641. #ifdef _X360
  4642. if ( !Should360EmulatePS3() )
  4643. {
  4644. g_pAlternateThreadPool = CreateNewThreadPool();
  4645. startParams.iAffinityTable[0] = XBOX_PROCESSOR_3;
  4646. startParams.iAffinityTable[1] = XBOX_PROCESSOR_5;
  4647. g_pAlternateThreadPool->Start( startParams );
  4648. }
  4649. #endif
  4650. }
  4651. // From const.h, the loaded game .dll will give us the correct value which is transmitted to the client
  4652. host_state.interval_per_tick = DEFAULT_TICK_INTERVAL;
  4653. InstallBitBufErrorHandler();
  4654. InstallConVarHook();
  4655. TRACEINIT( Con_Init(), Con_Shutdown() );
  4656. TRACEINIT( Memory_Init(), Memory_Shutdown() );
  4657. TRACEINIT( Cbuf_Init(), Cbuf_Shutdown() );
  4658. TRACEINIT( Cmd_Init(), Cmd_Shutdown() );
  4659. TRACEINIT( g_pCVar->Init(), g_pCVar->Shutdown() ); // So we can list cvars with "cvarlst"
  4660. #ifndef DEDICATED
  4661. TRACEINIT( V_Init(), V_Shutdown() );
  4662. #endif
  4663. //TRACEINIT( Host_InitVCR(), Host_ShutdownVCR() );
  4664. TRACEINIT( COM_Init(), COM_Shutdown() );
  4665. #if !defined(DEDICATED) && !defined(LEFT4DEAD)
  4666. TRACEINIT( saverestore->Init(), saverestore->Shutdown() );
  4667. #endif
  4668. TRACEINIT( Filter_Init(), Filter_Shutdown() );
  4669. #ifndef DEDICATED
  4670. TRACEINIT( Key_Init(), Key_Shutdown() );
  4671. #endif
  4672. // Check for special -dev flag
  4673. if ( CommandLine()->FindParm( "-dev" ) || ( CommandLine()->FindParm( "-allowdebug" ) && !CommandLine()->FindParm( "-nodev" ) ) )
  4674. {
  4675. sv_cheats.SetValue( 1 );
  4676. developer.SetValue( 1 );
  4677. }
  4678. #ifdef _DEBUG
  4679. developer.SetValue( 1 );
  4680. #endif
  4681. if ( CommandLine()->FindParm( "-nocrashdialog" ) )
  4682. {
  4683. // stop the various windows error message boxes from showing up (used by the auto-builder so it doesn't block on error)
  4684. Sys_NoCrashDialog();
  4685. }
  4686. // Seed the random number generator
  4687. float flTimeToSeed = Plat_FloatTime();
  4688. COMPILE_TIME_ASSERT( sizeof( flTimeToSeed ) == sizeof( int ) );
  4689. RandomSeed( ( reinterpret_cast< int & >( flTimeToSeed ) ) & 0x7FFFFFFF );
  4690. DevMsg( "Seeded random number generator @ %d ( %.3f )\n", ( reinterpret_cast< int & >( flTimeToSeed ) ) & 0x7FFFFFFF, flTimeToSeed );
  4691. TRACEINIT( g_pSteamSocketMgr->Init(), g_pSteamSocketMgr->Shutdown() );
  4692. if ( CommandLine()->FindParm( "-xlsp" ) != 0 )
  4693. {
  4694. TRACEINIT( NET_Init( bDedicated ), NET_Shutdown() );
  4695. }
  4696. TRACEINIT( g_GameEventManager.Init(), g_GameEventManager.Shutdown() );
  4697. TRACEINIT( sv.Init( bDedicated ), sv.Shutdown() );
  4698. if ( !CommandLine()->FindParm( "-nogamedll" ) )
  4699. {
  4700. SV_InitGameDLL();
  4701. }
  4702. TRACEINIT( g_Log.Init(), g_Log.Shutdown() );
  4703. TRACEINIT( HLTV_Init(), HLTV_Shutdown() );
  4704. #if defined( REPLAY_ENABLED )
  4705. TRACEINIT( Replay_Init(), Replay_Shutdown() );
  4706. #endif
  4707. ConDMsg( "Heap: %5.2f Mb\n", host_parms.memsize/(1024.0f*1024.0f) );
  4708. // Deal with Gore Settings
  4709. Host_CheckGore();
  4710. #if !defined( DEDICATED )
  4711. if ( !bDedicated )
  4712. {
  4713. TRACEINIT( CL_Init(), CL_Shutdown() );
  4714. // NOTE: This depends on the mod search path being set up
  4715. TRACEINIT( InitMaterialSystem(), ShutdownMaterialSystem() );
  4716. #if defined( INCLUDE_SCALEFORM )
  4717. extern IScaleformSlotInitController *g_pIScaleformSlotInitControllerEngineImpl;
  4718. TRACEINIT( ScaleformInitFullScreenAndCursor(g_pScaleformUI, g_szDefaultScaleformMovieName, g_szDefaultScaleformCursorName, g_pIScaleformSlotInitControllerEngineImpl ), ScaleformReleaseFullScreenAndCursor( g_pScaleformUI ) );
  4719. #endif
  4720. TRACEINIT( modelloader->Init(), modelloader->Shutdown() );
  4721. TRACEINIT( StaticPropMgr()->Init(), StaticPropMgr()->Shutdown() );
  4722. TRACEINIT( InitStudioRender(), ShutdownStudioRender() );
  4723. TRACEINIT( g_pMatchFramework->Init(), g_pMatchFramework->Shutdown() );
  4724. //startup vgui
  4725. TRACEINIT( EngineVGui()->Init(), EngineVGui()->Shutdown() );
  4726. TRACEINIT( TextMessageInit(), TextMessageShutdown() );
  4727. TRACEINIT( ClientDLL_Init(), ClientDLL_Shutdown() );
  4728. TRACEINIT( SCR_Init(), SCR_Shutdown() );
  4729. TRACEINIT( R_Init(), R_Shutdown() );
  4730. TRACEINIT( Decal_Init(), Decal_Shutdown() );
  4731. // hookup interfaces
  4732. EngineVGui()->Connect();
  4733. }
  4734. else
  4735. #endif
  4736. {
  4737. TRACEINIT( InitMaterialSystem(), ShutdownMaterialSystem() );
  4738. TRACEINIT( modelloader->Init(), modelloader->Shutdown() );
  4739. TRACEINIT( StaticPropMgr()->Init(), StaticPropMgr()->Shutdown() );
  4740. TRACEINIT( InitStudioRender(), ShutdownStudioRender() );
  4741. TRACEINIT( g_pMatchFramework->Init(), g_pMatchFramework->Shutdown() );
  4742. TRACEINIT( Decal_Init(), Decal_Shutdown() );
  4743. #ifndef DEDICATED
  4744. GetBaseLocalClient().m_nSignonState = SIGNONSTATE_NONE; // disable client
  4745. #endif
  4746. }
  4747. if ( IsPC() )
  4748. {
  4749. #if !defined(NO_STEAM)
  4750. // on PC, enable FCVAR_DEVELOPMENTONLY cvars if we're logged into beta or dev universes. They remain hidden & disabled otherwise.
  4751. EUniverse eUniverse = GetSteamUniverse();
  4752. if ( ( eUniverse == k_EUniverseBeta ) || ( eUniverse == k_EUniverseDev ) )
  4753. {
  4754. ConVarUtilities->EnableDevCvars();
  4755. }
  4756. #endif
  4757. }
  4758. else if ( IsGameConsole() )
  4759. {
  4760. // on 360, enable FCVAR_DEVELOPMENTONLY cvars always. No cvars are accessible to customers on X360.
  4761. ConVarUtilities->EnableDevCvars();
  4762. }
  4763. #ifndef DEDICATED
  4764. memset( g_bConfigCfgExecuted, 0, sizeof(g_bConfigCfgExecuted) );
  4765. Host_ReadConfiguration( -1, false );
  4766. TRACEINIT( S_Init(), S_Shutdown() );
  4767. // Audio system initializes after matchmaking, so need to explicitly
  4768. // set the voice interface extension
  4769. IEngineVoice *pIEngineVoice = NULL;
  4770. #ifdef _GAMECONSOLE
  4771. pIEngineVoice = Audio_GetXVoice();
  4772. #elif ( defined( _WIN32 ) || defined( OSX ) || defined( LINUX ) ) && !defined( NO_STEAM )
  4773. pIEngineVoice = Audio_GetEngineVoiceSteam();
  4774. #else
  4775. pIEngineVoice = Audio_GetEngineVoiceStub();
  4776. #endif
  4777. if ( !pIEngineVoice )
  4778. {
  4779. Warning( "Using IEngineVoice extension stub!\n" );
  4780. pIEngineVoice = Audio_GetEngineVoiceStub();
  4781. }
  4782. g_pMatchFramework->GetMatchExtensions()->RegisterExtensionInterface(
  4783. IENGINEVOICE_INTERFACE_VERSION, pIEngineVoice );
  4784. if (vaudio)
  4785. {
  4786. //Pin miles sound system as loaded until Host_Shutdown() is caused. This prevents any
  4787. //possible path where MSS could unload and then somehow be reloaded.
  4788. g_pMilesAudioEngineRef = vaudio->CreateMilesAudioEngine();
  4789. }
  4790. #endif
  4791. // Execute valve.rc
  4792. #ifdef _GAMECONSOLE
  4793. // the 360 version loads a 3d background
  4794. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec valve.rc\n" );
  4795. #else
  4796. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec valve.rc\n" );
  4797. #endif
  4798. // Execute mod-specfic settings, without falling back based on search path.
  4799. // This lets us set overrides for games while letting mods of those games
  4800. // use the default settings.
  4801. if ( g_pFileSystem->FileExists( "//mod/cfg/modsettings.cfg" ) )
  4802. {
  4803. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "exec modsettings.cfg mod\n" );
  4804. }
  4805. #ifdef _GAMECONSOLE
  4806. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "cmd2 exec config" PLATFORM_EXT ".cfg\n" );
  4807. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "cmd1 exec config" PLATFORM_EXT ".cfg\n" );
  4808. #endif
  4809. // Mark DLL as active
  4810. // eng->SetNextState( InEditMode() ? IEngine::DLL_PAUSED : IEngine::DLL_ACTIVE );
  4811. TelemetryTick();
  4812. // Initialize processor subsystem, and print relevant information:
  4813. Host_InitProcessor();
  4814. // Mark hunklevel at end of startup
  4815. Hunk_AllocName( 0, "-HOST_HUNKLEVEL-" );
  4816. host_hunklevel = Hunk_LowMark();
  4817. #ifdef SOURCE_MT
  4818. if ( CommandLine()->FindParm( "-swapcores" ) && !IsPS3() )
  4819. {
  4820. g_nMaterialSystemThread = 1;
  4821. g_nServerThread = 0;
  4822. }
  4823. #endif
  4824. Host_AllowQueuedMaterialSystem( false );
  4825. // Finished initializing
  4826. host_initialized = true;
  4827. host_checkheap = CommandLine()->FindParm( "-heapcheck" ) ? true : false;
  4828. if ( host_checkheap )
  4829. {
  4830. #if defined( _WIN32 )
  4831. if ( _heapchk() != _HEAPOK )
  4832. {
  4833. Sys_Error( "Host_Init: _heapchk() != _HEAPOK\n" );
  4834. }
  4835. #endif
  4836. }
  4837. // go directly to run state with no active game
  4838. HostState_Init();
  4839. // check for reslist generation
  4840. if ( CommandLine()->FindParm( "-makereslists" ) )
  4841. {
  4842. MapReslistGenerator().StartReslistGeneration();
  4843. }
  4844. // check for devshot generation
  4845. if ( CommandLine()->FindParm( "-makedevshots" ) )
  4846. {
  4847. DevShotGenerator().StartDevShotGeneration();
  4848. }
  4849. // if running outside of steam and NOT a dedicated server then phone home (or if "-phonehome" is passed on the command line)
  4850. if ( !sv.IsDedicated() || CommandLine()->FindParm( "-phonehome" ) )
  4851. {
  4852. // In debug, only run this check if -phonehome is on the command line (so a debug build will "just work").
  4853. if ( IsDebug() && CommandLine()->FindParm( "-phonehome" ) )
  4854. {
  4855. phonehome->Init();
  4856. phonehome->Message( IPhoneHome::PHONE_MSG_ENGINESTART, NULL );
  4857. }
  4858. }
  4859. Host_PostInit();
  4860. EndLoadingUpdates();
  4861. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  4862. pRenderContext->SetNonInteractiveTempFullscreenBuffer( NULL, MATERIAL_NON_INTERACTIVE_MODE_STARTUP );
  4863. pRenderContext->SetNonInteractivePacifierTexture( NULL, 0, 0, 0 );
  4864. pRenderContext->SetNonInteractiveLogoTexture( NULL, 0, 0, 0, 0 );
  4865. // disable future render target allocation
  4866. g_pMaterialSystem->FinishRenderTargetAllocation();
  4867. if ( CommandLine()->FindParm( "-profileinit" ) )
  4868. {
  4869. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
  4870. }
  4871. if ( !bDedicated && Host_IsSecureServerAllowed() )
  4872. {
  4873. Host_FinishSecureSignatureChecks();
  4874. }
  4875. #if !defined(DEDICATED)
  4876. if ( g_pMatchFramework && !Host_IsSecureServerAllowed() )
  4877. {
  4878. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnClientInsecureBlocked", "reason", "init" ) );
  4879. }
  4880. #endif
  4881. // Official valve servers must be running with a certificate
  4882. if ( CommandLine()->FindParm( "-certificate" ) ||
  4883. ( serverGameDLL && serverGameDLL->IsValveDS() && !CommandLine()->FindParm( "-ignore_certificate_valveds" ) ) )
  4884. {
  4885. const byte *pbNetEncryptPrivateKey = NULL;
  4886. int cbNetEncryptPrivateKey = 0;
  4887. bool bHasPrivateKey =
  4888. NET_CryptGetNetworkCertificate( k_ENetworkCertificate_PublicKey, &pbNetEncryptPrivateKey, &cbNetEncryptPrivateKey ) &&
  4889. NET_CryptGetNetworkCertificate( k_ENetworkCertificate_Signature, &pbNetEncryptPrivateKey, &cbNetEncryptPrivateKey ) &&
  4890. NET_CryptGetNetworkCertificate( k_ENetworkCertificate_PrivateKey, &pbNetEncryptPrivateKey, &cbNetEncryptPrivateKey );
  4891. if ( !bHasPrivateKey || !pbNetEncryptPrivateKey || !cbNetEncryptPrivateKey )
  4892. {
  4893. Warning( "NET_CryptGetNetworkCertificate is missing server certificates!\n" );
  4894. Plat_ExitProcess( 0 );
  4895. }
  4896. }
  4897. }
  4898. class CAddTransitionResourcesCB : public ISaveRestoreDataCallback
  4899. {
  4900. public:
  4901. CAddTransitionResourcesCB( const char *pLevelName, const char *pLandmarkName )
  4902. : m_pLevelName( pLevelName ), m_pLandMarkName( pLandmarkName ) {}
  4903. //-----------------------------------------------------------------------------
  4904. // Adds hints to the loader to keep resources that are in the transition volume,
  4905. // as they may not be part of the next map's reslist.
  4906. //-----------------------------------------------------------------------------
  4907. virtual void Execute( CSaveRestoreData *pSaveData )
  4908. {
  4909. if ( !pSaveData || IsPC() || ( g_pFileSystem->GetDVDMode() == DVDMODE_OFF ) )
  4910. {
  4911. return;
  4912. }
  4913. // get the bit marked for the next level
  4914. int transitionMask = 0;
  4915. for ( int i = 0; i < pSaveData->levelInfo.connectionCount; i++ )
  4916. {
  4917. if ( !Q_stricmp( m_pLevelName, pSaveData->levelInfo.levelList[i].mapName ) && !Q_stricmp( m_pLandMarkName, pSaveData->levelInfo.levelList[i].landmarkName ) )
  4918. {
  4919. transitionMask = 1<<i;
  4920. break;
  4921. }
  4922. }
  4923. if ( !transitionMask )
  4924. {
  4925. // nothing to do
  4926. return;
  4927. }
  4928. const char *pModelName;
  4929. bool bHasHumans = false;
  4930. for ( int i = 0; i < pSaveData->NumEntities(); i++ )
  4931. {
  4932. if ( pSaveData->GetEntityInfo(i)->flags & transitionMask )
  4933. {
  4934. // this entity will cross the transition and needs to be preserved
  4935. // add to the next map's resource list which effectively keeps it from being purged
  4936. // only care about the actual mdl and not any of its dependants
  4937. pModelName = pSaveData->GetEntityInfo(i)->modelname.ToCStr();
  4938. g_pQueuedLoader->AddMapResource( pModelName );
  4939. // humans require a post pass
  4940. if ( !bHasHumans && V_stristr( pModelName, "models/humans" ) )
  4941. {
  4942. bHasHumans = true;
  4943. }
  4944. }
  4945. }
  4946. if ( bHasHumans )
  4947. {
  4948. // the presence of any human entity in the transition needs to ensure all the human mdls stay
  4949. int count = modelloader->GetCount();
  4950. for ( int i = 0; i < count; i++ )
  4951. {
  4952. pModelName = modelloader->GetName( modelloader->GetModelForIndex( i ) );
  4953. if ( V_stristr( pModelName, "models/humans" ) )
  4954. {
  4955. g_pQueuedLoader->AddMapResource( pModelName );
  4956. }
  4957. }
  4958. }
  4959. }
  4960. const char *m_pLevelName;
  4961. const char *m_pLandMarkName;
  4962. };
  4963. // There's a version of this in bsplib.cpp!!! Make sure that they match.
  4964. void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int maxLength )
  4965. {
  4966. Q_strncpy( pPlatformMapPath, pMapPath, maxLength );
  4967. // It's OK for this to be NULL on the dedicated server.
  4968. if( g_pMaterialSystemHardwareConfig )
  4969. {
  4970. Q_StripExtension( pMapPath, pPlatformMapPath, maxLength );
  4971. Q_strncat( pPlatformMapPath, ".bsp", maxLength, COPY_ALL_CHARACTERS );
  4972. }
  4973. }
  4974. void AdjustThreadPoolThreadCount()
  4975. {
  4976. #if defined( DEDICATED ) && IsPlatformLinux()
  4977. extern ConVar occlusion_test_async;
  4978. int nTargetThreads = occlusion_test_async.GetInt();
  4979. if ( nTargetThreads != g_pThreadPool->NumThreads() )
  4980. {
  4981. uint64 nTickStart = GetTimebaseRegister();
  4982. Msg( "Stopping %d worker threads\n", g_pThreadPool->NumThreads() );
  4983. g_pThreadPool->ExecuteAll();
  4984. g_pThreadPool->Stop();
  4985. if ( nTargetThreads != 0 )
  4986. {
  4987. Msg( "Starting %d worker threads\n", nTargetThreads);
  4988. ThreadPoolStartParams_t startParams;
  4989. GetThreadPoolStartParams( startParams );
  4990. startParams.nThreads = Max( 1, Min( 4, nTargetThreads ) );
  4991. startParams.bEnableOnLinuxDedicatedServer = true; // if we run with -threads parameter, we should also enable the thread pool
  4992. if ( g_pThreadPool )
  4993. {
  4994. g_pThreadPool->Start( startParams );
  4995. }
  4996. }
  4997. uint64 nTickEnd = GetTimebaseRegister();
  4998. Msg( "%d threads. %s ticks\n", g_pThreadPool->NumThreads(), V_pretifynum( nTickEnd - nTickStart ) );
  4999. int nCmdLineThreads = CommandLine()->ParmValue( "-threads", -1 );
  5000. if ( nCmdLineThreads >= 0 )
  5001. {
  5002. Msg( "Note that cmd line -threads %d is specified\n", nCmdLineThreads );
  5003. }
  5004. }
  5005. #endif
  5006. }
  5007. void Host_Changelevel( bool loadfromsavedgame, const char *mapname, char *mapGroupName, const char *start )
  5008. {
  5009. char level[ MAX_QPATH ];
  5010. char _startspot[ MAX_QPATH ];
  5011. char *startspot;
  5012. char oldlevel[ MAX_QPATH ];
  5013. #if !defined(DEDICATED)
  5014. bool bTransitionBySave = false;
  5015. #endif
  5016. if ( !sv.IsActive() )
  5017. {
  5018. ConMsg( "Only the server may changelevel\n" );
  5019. return;
  5020. }
  5021. #ifndef DEDICATED
  5022. // FIXME: Even needed?
  5023. if ( demoplayer->IsPlayingBack() )
  5024. {
  5025. ConMsg( "Changelevel invalid during demo playback\n" );
  5026. return;
  5027. }
  5028. if ( !sv.IsDedicated() )
  5029. {
  5030. EngineVGui()->SetProgressLevelName( mapname );
  5031. }
  5032. SCR_BeginLoadingPlaque( mapname );
  5033. #endif
  5034. g_pFileSystem->AsyncFinishAll();
  5035. #if !defined DEDICATED
  5036. // stop sounds (especially looping!)
  5037. S_StopAllSounds( true );
  5038. #endif
  5039. char dxMapName[ MAX_PATH ];
  5040. GetPlatformMapPath( mapname, dxMapName, MAX_PATH );
  5041. host_map.SetValue( dxMapName );
  5042. Q_strncpy( level, mapname, sizeof( level ) );
  5043. if ( !start )
  5044. startspot = NULL;
  5045. else
  5046. {
  5047. Q_strncpy( _startspot, start, sizeof( _startspot ) );
  5048. startspot = _startspot;
  5049. }
  5050. Warning( "---- Host_Changelevel ----\n" );
  5051. SV_CheckForFlushMemory( sv.GetMapName(), mapname );
  5052. if ( IsX360() )
  5053. {
  5054. // Reset material system temporary memory (frees up memory for map loading)
  5055. materials->ResetTempHWMemory( true );
  5056. }
  5057. materials->OnLevelShutdown();
  5058. #if !defined( DEDICATED )
  5059. // Always save as an xsave if we're on the xbox
  5060. saverestore->SetIsXSave( IsX360() );
  5061. // Add on time passed since the last time we kept track till this transition
  5062. int iAdditionalSeconds = g_ServerGlobalVariables.curtime - saverestore->GetMostRecentElapsedTimeSet();
  5063. int iElapsedSeconds = saverestore->GetMostRecentElapsedSeconds() + iAdditionalSeconds;
  5064. int iElapsedMinutes = saverestore->GetMostRecentElapsedMinutes() + ( iElapsedSeconds / 60 );
  5065. saverestore->SetMostRecentElapsedMinutes( iElapsedMinutes );
  5066. saverestore->SetMostRecentElapsedSeconds( ( iElapsedSeconds % 60 ) );
  5067. KeyValues *kvChangelevelEvent = new KeyValues( "OnHostChangeLevel" );
  5068. kvChangelevelEvent->SetString( "map", mapname );
  5069. kvChangelevelEvent->SetUint64( "elapsed", iElapsedMinutes * 60 + iElapsedSeconds % 60 );
  5070. kvChangelevelEvent->SetInt( "bysave", !!bTransitionBySave );
  5071. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvChangelevelEvent );
  5072. if ( bTransitionBySave )
  5073. {
  5074. char comment[ 80 ];
  5075. // Pass in the total elapsed time so it gets added to the elapsed time for this map.
  5076. serverGameDLL->GetSaveComment(
  5077. comment,
  5078. sizeof( comment ),
  5079. saverestore->GetMostRecentElapsedMinutes(),
  5080. saverestore->GetMostRecentElapsedSeconds() );
  5081. if ( !saverestore->SaveGameSlot( "_transition", comment, false, true, mapname, startspot ) )
  5082. {
  5083. Warning( "Failed to save data for transition\n" );
  5084. SCR_EndLoadingPlaque();
  5085. return;
  5086. }
  5087. // Not going to load a save after the transition, so add this map's elapsed time to the total elapsed time
  5088. int totalSeconds = g_ServerGlobalVariables.curtime + saverestore->GetMostRecentElapsedSeconds();
  5089. saverestore->SetMostRecentElapsedMinutes( ( int )( totalSeconds / 60.0f ) + saverestore->GetMostRecentElapsedMinutes() );
  5090. saverestore->SetMostRecentElapsedSeconds( ( int )fmod( totalSeconds, 60.0f ) );
  5091. }
  5092. #endif
  5093. Q_strncpy( oldlevel, sv.GetMapName(), sizeof( oldlevel ) );
  5094. #if !defined(DEDICATED)
  5095. if ( loadfromsavedgame )
  5096. {
  5097. if ( !bTransitionBySave )
  5098. {
  5099. // This callback ensures resources in the transition volume stay
  5100. CAddTransitionResourcesCB addTransitionResources( level, startspot );
  5101. // save the current level's state
  5102. if ( !saverestore->SaveGameState( true, &addTransitionResources ) )
  5103. {
  5104. Warning( "Failed to save data for transition\n" );
  5105. SCR_EndLoadingPlaque();
  5106. return;
  5107. }
  5108. }
  5109. }
  5110. #endif
  5111. g_pServerPluginHandler->LevelShutdown();
  5112. #if !defined(DEDICATED)
  5113. audiosourcecache->LevelShutdown();
  5114. #endif
  5115. sv.InactivateClients();
  5116. #if !defined(DEDICATED)
  5117. saverestore->FinishAsyncSave();
  5118. #endif
  5119. if ( sv.RestartOnLevelChange() )
  5120. {
  5121. Cbuf_Clear( Cbuf_GetCurrentPlayer() );
  5122. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
  5123. return;
  5124. }
  5125. DownloadListGenerator().OnLevelLoadStart( level );
  5126. Msg( "*** Map Load: %s: Map Group %s", level, mapGroupName );
  5127. if ( !sv.SpawnServer( level, mapGroupName, startspot ) )
  5128. {
  5129. return;
  5130. }
  5131. #ifndef DEDICATED
  5132. if ( loadfromsavedgame )
  5133. {
  5134. g_ServerGlobalVariables.curtime = sv.GetTime();
  5135. audiosourcecache->LevelInit( level );
  5136. g_pServerPluginHandler->LevelInit( level, CM_EntityString(), oldlevel, startspot, true, false );
  5137. sv.SetPaused( true ); // pause until client connects
  5138. sv.m_bLoadgame = true;
  5139. }
  5140. else
  5141. #endif
  5142. {
  5143. g_ServerGlobalVariables.curtime = sv.GetTime();
  5144. #if !defined(DEDICATED)
  5145. audiosourcecache->LevelInit( level );
  5146. #endif
  5147. g_pServerPluginHandler->LevelInit( level, CM_EntityString(), NULL, NULL, false, false );
  5148. }
  5149. SV_ActivateServer();
  5150. #if !defined(DEDICATED)
  5151. // Offset stored elapsed time by the current elapsed time for this new map
  5152. int maptime = sv.GetTime();
  5153. int minutes = ( int )( maptime / 60.0f );
  5154. int seconds = ( int )fmod( maptime, 60.0f );
  5155. saverestore->SetMostRecentElapsedMinutes( saverestore->GetMostRecentElapsedMinutes() - minutes );
  5156. saverestore->SetMostRecentElapsedSeconds( saverestore->GetMostRecentElapsedSeconds() - seconds );
  5157. saverestore->ForgetRecentSave();
  5158. #endif
  5159. NotifyDedicatedServerUI( "UpdateMap" );
  5160. DownloadListGenerator().OnLevelLoadEnd();
  5161. AdjustThreadPoolThreadCount();
  5162. }
  5163. /*
  5164. ===============================================================================
  5165. SERVER TRANSITIONS
  5166. ===============================================================================
  5167. */
  5168. bool Host_NewGame( char *mapName, char *mapGroupName, bool loadGame, bool bBackgroundLevel, bool bSplitScreenConnect, const char *pszOldMap, const char *pszLandmark )
  5169. {
  5170. VPROF( "Host_NewGame" );
  5171. COM_TimestampedLog( "Host_NewGame" );
  5172. // reset some convars if loading background map
  5173. if ( bBackgroundLevel )
  5174. ResetGameConVarsToDefaults();
  5175. char previousMapName[MAX_PATH];
  5176. char dxMapName[MAX_PATH];
  5177. V_FixSlashes( mapName, '/' );
  5178. GetPlatformMapPath( mapName, dxMapName, MAX_PATH );
  5179. Q_strncpy( previousMapName, host_map.GetString(), sizeof( previousMapName ) );
  5180. host_map.SetValue( dxMapName );
  5181. // Setup gamemode based on the settings the map was started with
  5182. sv.ExecGameTypeCfg( mapName );
  5183. #ifndef DEDICATED
  5184. if ( !sv.IsDedicated() )
  5185. {
  5186. EngineVGui()->SetProgressLevelName( mapName );
  5187. }
  5188. SCR_BeginLoadingPlaque( mapName );
  5189. #endif
  5190. Warning( "---- Host_NewGame ----\n" );
  5191. SV_CheckForFlushMemory( previousMapName, mapName );
  5192. if ( IsX360() )
  5193. {
  5194. // Reset material system temporary memory (frees up memory for map loading)
  5195. materials->ResetTempHWMemory( true );
  5196. }
  5197. materials->OnLevelShutdown();
  5198. MapReslistGenerator().OnLevelLoadStart(mapName);
  5199. DownloadListGenerator().OnLevelLoadStart(mapName);
  5200. if ( !loadGame )
  5201. {
  5202. VPROF( "Host_NewGame_HostState_RunGameInit" );
  5203. HostState_RunGameInit();
  5204. }
  5205. // init network mode
  5206. VPROF_SCOPE_BEGIN( "Host_NewGame_SpawnServer" );
  5207. NET_SetMultiplayer( sv.IsMultiplayer() );
  5208. if ( !sv.IsMultiplayer() )
  5209. NET_SetMultiplayer( ( g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_SETTING_MULTIPLAYER ) != 0 );
  5210. NET_ListenSocket( sv.m_Socket, true ); // activated server TCP socket
  5211. // let's not have any servers with no name
  5212. Host_EnsureHostNameSet();
  5213. COM_TimestampedLog( "*** Map Load: %s Map %s Group", mapName, mapGroupName );
  5214. HostState_Pre_LoadMapIntoMemory(); // A map is about to be loaded into memory
  5215. if ( !sv.SpawnServer ( mapName, mapGroupName, NULL ) )
  5216. {
  5217. HostState_Post_FlushMapFromMemory(); // Map load failed, no impact on memory
  5218. return false;
  5219. }
  5220. sv.m_bIsLevelMainMenuBackground = bBackgroundLevel;
  5221. ConColorMsg( Color( 0, 255, 0 ), "Host_NewGame on map %s%s\n",
  5222. mapName, sv.IsLevelMainMenuBackground() ? " (background map)" : "" );
  5223. VPROF_SCOPE_END();
  5224. // make sure the time is set
  5225. g_ServerGlobalVariables.curtime = sv.GetTime();
  5226. COM_TimestampedLog( "serverGameDLL->LevelInit" );
  5227. #ifndef DEDICATED
  5228. EngineVGui()->UpdateProgressBar(PROGRESS_LEVELINIT);
  5229. audiosourcecache->LevelInit( mapName );
  5230. #endif
  5231. g_pServerPluginHandler->LevelInit( mapName, CM_EntityString(), pszOldMap, pszLandmark, loadGame, bBackgroundLevel );
  5232. if ( loadGame )
  5233. {
  5234. sv.SetPaused( true ); // pause until all clients connect
  5235. sv.m_bLoadgame = true;
  5236. g_ServerGlobalVariables.curtime = sv.GetTime();
  5237. }
  5238. if( !SV_ActivateServer() )
  5239. {
  5240. return false;
  5241. }
  5242. // Connect the local client when a "map" command is issued.
  5243. if ( !sv.IsDedicated() )
  5244. {
  5245. COM_TimestampedLog( "Stuff 'connect localhost' to console" );
  5246. int nNumPlayers = 1;
  5247. if( IsGameConsole() && !bBackgroundLevel )
  5248. {
  5249. #ifdef _GAMECONSOLE
  5250. // on the 360 we need to ask matchmaking how many players to connect.
  5251. nNumPlayers = XBX_GetNumGameUsers();
  5252. #endif
  5253. }
  5254. if ( bSplitScreenConnect )
  5255. {
  5256. Assert( !bBackgroundLevel );
  5257. nNumPlayers = host_state.max_splitscreen_players;
  5258. }
  5259. char str[512];
  5260. if ( nNumPlayers > 1 )
  5261. {
  5262. Q_snprintf( str, sizeof( str ), "connect_splitscreen localhost:%d %d", sv.GetUDPPort(), nNumPlayers );
  5263. }
  5264. else
  5265. {
  5266. Q_snprintf( str, sizeof( str ), "connect localhost:%d", sv.GetUDPPort() );
  5267. }
  5268. Cbuf_AddText( Cbuf_GetCurrentPlayer(), str );
  5269. }
  5270. else
  5271. {
  5272. // Dedicated server triggers map load here.
  5273. GetTestScriptMgr()->CheckPoint( "FinishedMapLoad" );
  5274. }
  5275. #ifndef DEDICATED
  5276. if ( !loadGame )
  5277. {
  5278. // clear the most recent remember save, so the level will just restart if the player dies
  5279. saverestore->ForgetRecentSave();
  5280. }
  5281. saverestore->SetMostRecentElapsedMinutes( 0 );
  5282. saverestore->SetMostRecentElapsedSeconds( 0 );
  5283. #endif
  5284. if (MapReslistGenerator().IsEnabled())
  5285. {
  5286. MapReslistGenerator().OnLevelLoadEnd();
  5287. }
  5288. DownloadListGenerator().OnLevelLoadEnd();
  5289. return true;
  5290. }
  5291. void Host_FreeStateAndWorld( bool server )
  5292. {
  5293. Assert( host_initialized );
  5294. Assert( host_hunklevel );
  5295. // If called by the client and we are running a listen server, just ignore
  5296. if ( !server && sv.IsActive() )
  5297. return;
  5298. // HACKHACK: You can't clear the hunk unless the client data is free
  5299. // since this gets called by the server, it's necessary to wipe the client
  5300. // in case we are on a listen server
  5301. #ifndef DEDICATED
  5302. if ( server && !sv.IsDedicated() )
  5303. {
  5304. CL_ClearState();
  5305. }
  5306. #endif
  5307. // The world model relies on the low hunk, so we need to force it to unload
  5308. if ( host_state.worldmodel )
  5309. {
  5310. modelloader->UnreferenceModel( host_state.worldmodel, IModelLoader::FMODELLOADER_SERVER );
  5311. modelloader->UnreferenceModel( host_state.worldmodel, IModelLoader::FMODELLOADER_CLIENT );
  5312. host_state.SetWorldModel( NULL );
  5313. }
  5314. modelloader->UnloadUnreferencedModels();
  5315. modelloader->UnMountCompatibilityPaths();
  5316. g_TimeLastMemTest = 0;
  5317. }
  5318. //-----------------------------------------------------------------------------
  5319. // Purpose:
  5320. //-----------------------------------------------------------------------------
  5321. void Host_FreeToLowMark( bool server )
  5322. {
  5323. Assert( host_initialized );
  5324. Assert( host_hunklevel );
  5325. // If called by the client and we are running a listen server, just ignore
  5326. if ( !server && ( sv.IsActive() || sv.IsLoading() ) )
  5327. return;
  5328. CM_FreeMap();
  5329. if ( host_hunklevel )
  5330. {
  5331. // See if we are going to obliterate any malloc'd pointers
  5332. Hunk_FreeToLowMark(host_hunklevel);
  5333. }
  5334. }
  5335. //-----------------------------------------------------------------------------
  5336. // Purpose:
  5337. //-----------------------------------------------------------------------------
  5338. void Host_Shutdown(void)
  5339. {
  5340. if ( host_checkheap )
  5341. {
  5342. #ifdef _WIN32
  5343. if ( _heapchk() != _HEAPOK )
  5344. {
  5345. Sys_Error( "Host_Shutdown (top): _heapchk() != _HEAPOK\n" );
  5346. }
  5347. #endif
  5348. }
  5349. // Check for recursive shutdown, should never happen
  5350. static bool shutting_down = false;
  5351. if ( shutting_down )
  5352. {
  5353. Msg( "Recursive shutdown!!!\n" );
  5354. return;
  5355. }
  5356. shutting_down = true;
  5357. if( g_pDebugInputThread )
  5358. {
  5359. g_pDebugInputThread->Stop();
  5360. delete g_pDebugInputThread;
  5361. }
  5362. phonehome->Message( IPhoneHome::PHONE_MSG_ENGINEEND, NULL );
  5363. phonehome->Shutdown();
  5364. #ifndef DEDICATED
  5365. // Store active configuration settings
  5366. Host_WriteConfiguration( -1, "config.cfg" );
  5367. #endif
  5368. // Disconnect from server
  5369. Host_Disconnect(true);
  5370. #ifndef DEDICATED
  5371. // keep ConMsg from trying to update the screen
  5372. scr_disabled_for_loading = true;
  5373. #endif
  5374. #if defined VOICE_OVER_IP && !defined DEDICATED && !defined( NO_VOICE )
  5375. Voice_Deinit();
  5376. #endif // VOICE_OVER_IP
  5377. // TODO, Trace this
  5378. CM_FreeMap();
  5379. host_initialized = false;
  5380. #if defined(VPROF_ENABLED)
  5381. VProfRecord_Shutdown();
  5382. #endif
  5383. #if !defined DEDICATED
  5384. if ( !sv.IsDedicated() )
  5385. {
  5386. if (vaudio && g_pMilesAudioEngineRef)
  5387. {
  5388. //let miles sound system exit here.
  5389. vaudio->DestroyMilesAudioEngine(g_pMilesAudioEngineRef);
  5390. g_pMilesAudioEngineRef = nullptr;
  5391. }
  5392. TRACESHUTDOWN( Decal_Shutdown() );
  5393. TRACESHUTDOWN( R_Shutdown() );
  5394. TRACESHUTDOWN( SCR_Shutdown() );
  5395. if ( g_pMatchFramework )
  5396. {
  5397. TRACESHUTDOWN( g_pMatchFramework->Shutdown() );
  5398. }
  5399. TRACESHUTDOWN( ClientDLL_Shutdown() );
  5400. TRACESHUTDOWN( TextMessageShutdown() );
  5401. TRACESHUTDOWN( EngineVGui()->Shutdown() );
  5402. #if defined( INCLUDE_SCALEFORM )
  5403. TRACESHUTDOWN( ScaleformReleaseFullScreenAndCursor( g_pScaleformUI ) );
  5404. #endif
  5405. TRACESHUTDOWN( S_Shutdown() );
  5406. TRACESHUTDOWN( StaticPropMgr()->Shutdown() );
  5407. // Model loader must shutdown before StudioRender
  5408. // because it calls into StudioRender
  5409. TRACESHUTDOWN( modelloader->Shutdown() );
  5410. TRACESHUTDOWN( ShutdownStudioRender() );
  5411. TRACESHUTDOWN( ShutdownMaterialSystem() );
  5412. TRACESHUTDOWN( CL_Shutdown() );
  5413. }
  5414. else
  5415. #endif
  5416. {
  5417. if ( g_pMatchFramework )
  5418. {
  5419. TRACESHUTDOWN( g_pMatchFramework->Shutdown() );
  5420. }
  5421. #ifndef DEDICATED
  5422. TRACESHUTDOWN( S_Shutdown() );
  5423. #endif
  5424. TRACESHUTDOWN( Decal_Shutdown() );
  5425. TRACESHUTDOWN( modelloader->Shutdown() );
  5426. TRACESHUTDOWN( ShutdownStudioRender() );
  5427. TRACESHUTDOWN( StaticPropMgr()->Shutdown() );
  5428. TRACESHUTDOWN( ShutdownMaterialSystem() );
  5429. }
  5430. #if defined( REPLAY_ENABLED )
  5431. TRACESHUTDOWN( Replay_Shutdown() );
  5432. #endif
  5433. TRACESHUTDOWN( HLTV_Shutdown() );
  5434. TRACESHUTDOWN( g_Log.Shutdown() );
  5435. TRACESHUTDOWN( g_GameEventManager.Shutdown() );
  5436. #if !defined( DEDICATED )
  5437. if ( !sv.IsDedicated() )
  5438. {
  5439. TRACESHUTDOWN( Steam3Client().Shutdown() );
  5440. }
  5441. #endif
  5442. TRACESHUTDOWN( sv.Shutdown() );
  5443. TRACESHUTDOWN( NET_Shutdown() );
  5444. TRACESHUTDOWN( g_pSteamSocketMgr->Shutdown() );
  5445. #ifndef DEDICATED
  5446. TRACESHUTDOWN( Key_Shutdown() );
  5447. #if !defined( _X360 )
  5448. TRACESHUTDOWN( ShutdownMixerControls() );
  5449. #endif
  5450. #endif
  5451. TRACESHUTDOWN( Filter_Shutdown() );
  5452. #if !defined(DEDICATED) && !defined(LEFT4DEAD)
  5453. TRACESHUTDOWN( saverestore->Shutdown() );
  5454. #endif
  5455. TRACESHUTDOWN( COM_Shutdown() );
  5456. // TRACESHUTDOWN( Host_ShutdownVCR() );
  5457. #ifndef DEDICATED
  5458. TRACESHUTDOWN( V_Shutdown() );
  5459. #endif
  5460. TRACESHUTDOWN( g_pCVar->Shutdown() );
  5461. TRACESHUTDOWN( Cmd_Shutdown() );
  5462. TRACESHUTDOWN( Cbuf_Shutdown() );
  5463. TRACESHUTDOWN( Con_Shutdown() );
  5464. TRACESHUTDOWN( Memory_Shutdown() );
  5465. if ( g_pThreadPool )
  5466. g_pThreadPool->Stop();
  5467. DTI_Term();
  5468. ServerDTI_Term();
  5469. #if defined(_WIN32)
  5470. if ( s_bInitPME )
  5471. {
  5472. ShutdownPME();
  5473. }
  5474. #endif
  5475. if ( host_checkheap )
  5476. {
  5477. #ifdef _WIN32
  5478. if ( _heapchk() != _HEAPOK )
  5479. {
  5480. Sys_Error( "Host_Shutdown (bottom): _heapchk() != _HEAPOK\n" );
  5481. }
  5482. #endif
  5483. }
  5484. }
  5485. //-----------------------------------------------------------------------------
  5486. // Centralize access to enabling QMS.
  5487. //-----------------------------------------------------------------------------
  5488. bool Host_AllowQueuedMaterialSystem( bool bAllow )
  5489. {
  5490. #if !defined DEDICATED
  5491. g_bAllowThreadedSound = bAllow;
  5492. // NOTE: Moved this to materialsystem for integrating with other mqm changes
  5493. return g_pMaterialSystem->AllowThreading( bAllow, g_nMaterialSystemThread );
  5494. #endif
  5495. }
  5496. void Host_EnsureHostNameSet()
  5497. {
  5498. // if there is host name set, set one
  5499. if ( host_name.GetString()[0] == 0 )
  5500. {
  5501. const char *szHostName = "";
  5502. #ifndef DEDICATED
  5503. // if this is a PC listen server and there is a logged-on Steam user, use the user's Steam name as the host name
  5504. if ( IsPC() && !sv.IsDedicated() && Steam3Client().SteamUser() )
  5505. {
  5506. if ( Steam3Client().SteamUser()->BLoggedOn() )
  5507. {
  5508. szHostName = Steam3Client().SteamFriends()->GetPersonaName();
  5509. }
  5510. }
  5511. #endif
  5512. // if all else fails, use the game description as the host name
  5513. if ( !szHostName[0] )
  5514. {
  5515. szHostName = serverGameDLL->GetGameDescription();
  5516. }
  5517. host_name.SetValue( szHostName );
  5518. }
  5519. }