Team Fortress 2 Source Code as on 22/4/2020
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.

5025 lines
130 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "tier0/fasttimer.h"
  7. #ifdef _WIN32
  8. #include "tier0/memdbgon.h" // needed because in release builds crtdbg.h is handled specially if USE_MEM_DEBUG is defined
  9. #include "tier0/memdbgoff.h"
  10. #include <crtdbg.h> // For getting at current heap size
  11. #endif
  12. #include "tier1/fmtstr.h"
  13. #include "vstdlib/jobthread.h"
  14. #ifdef USE_SDL
  15. #include "appframework/ilaunchermgr.h"
  16. extern ILauncherMgr *g_pLauncherMgr;
  17. #endif
  18. #include "server.h"
  19. #include "host_jmp.h"
  20. #include "screen.h"
  21. #include "keys.h"
  22. #include "cdll_int.h"
  23. #include "eiface.h"
  24. #include "sv_main.h"
  25. #include "sv_log.h"
  26. #include "shadowmgr.h"
  27. #include "zone.h"
  28. #include "gl_cvars.h"
  29. #include "sv_filter.h"
  30. #include "ivideomode.h"
  31. #include "vprof_engine.h"
  32. #include "iengine.h"
  33. #include "tier2/tier2.h"
  34. #include "enginethreads.h"
  35. #include "steam/steam_api.h"
  36. #include "LoadScreenUpdate.h"
  37. #include "datacache/idatacache.h"
  38. #if !defined SWDS
  39. #include "voice.h"
  40. #include "sound.h"
  41. #endif
  42. #include "icvar.h"
  43. #include "sys.h"
  44. #include "client.h"
  45. #include "cl_pred.h"
  46. #include "console.h"
  47. #include "view.h"
  48. #include "host.h"
  49. #include "decal.h"
  50. #include "gl_matsysiface.h"
  51. #include "gl_shader.h"
  52. #include "sys_dll.h"
  53. #include "cmodel_engine.h"
  54. #ifndef SWDS
  55. #include "con_nprint.h"
  56. #endif
  57. #include "filesystem.h"
  58. #include "filesystem_engine.h"
  59. #include "tier0/etwprof.h"
  60. #include "tier0/vcrmode.h"
  61. #include "traceinit.h"
  62. #include "host_saverestore.h"
  63. #include "l_studio.h"
  64. #include "cl_demo.h"
  65. #include "cdll_engine_int.h"
  66. #include "host_cmd.h"
  67. #include "host_state.h"
  68. #include "dt_instrumentation.h"
  69. #include "dt_instrumentation_server.h"
  70. #include "const.h"
  71. #include "bitbuf_errorhandler.h"
  72. #include "soundflags.h"
  73. #include "enginestats.h"
  74. #include "tier1/strtools.h"
  75. #include "testscriptmgr.h"
  76. #include "tmessage.h"
  77. #include "tier0/vprof.h"
  78. #include "tier0/icommandline.h"
  79. #include "materialsystem/imaterialsystemhardwareconfig.h"
  80. #include "MapReslistGenerator.h"
  81. #include "DownloadListGenerator.h"
  82. #include "download.h"
  83. #include "staticpropmgr.h"
  84. #include "GameEventManager.h"
  85. #include "iprediction.h"
  86. #include "netmessages.h"
  87. #include "cl_main.h"
  88. #include "hltvserver.h"
  89. #include "hltvtest.h"
  90. #if defined( REPLAY_ENABLED )
  91. #include "replayserver.h"
  92. #include "replay_internal.h"
  93. #endif
  94. #include "sys_mainwind.h"
  95. #include "host_phonehome.h"
  96. #ifndef SWDS
  97. #include "vgui_baseui_interface.h"
  98. #include "cl_steamauth.h"
  99. #endif
  100. #include "sv_remoteaccess.h" // NotifyDedicatedServerUI()
  101. #include "snd_audio_source.h"
  102. #include "sv_steamauth.h"
  103. #include "MapReslistGenerator.h"
  104. #include "DevShotGenerator.h"
  105. #include "sv_plugin.h"
  106. #include "toolframework/itoolframework.h"
  107. #include "ienginetoolinternal.h"
  108. #include "inputsystem/iinputsystem.h"
  109. #include "vgui_askconnectpanel.h"
  110. #include "cvar.h"
  111. #include "saverestoretypes.h"
  112. #include "filesystem/IQueuedLoader.h"
  113. #include "soundservice.h"
  114. #include "profile.h"
  115. #include "steam/isteamremotestorage.h"
  116. #if defined( _X360 )
  117. #include "xbox/xbox_win32stubs.h"
  118. #include "audio_pch.h"
  119. #endif
  120. #if defined( LINUX )
  121. #include <locale.h>
  122. #include "SDL.h"
  123. #endif
  124. #include "ixboxsystem.h"
  125. extern IXboxSystem *g_pXboxSystem;
  126. extern ConVar cl_cloud_settings;
  127. extern ConVar cl_logofile;
  128. // memdbgon must be the last include file in a .cpp file!!!
  129. #include "tier0/memdbgon.h"
  130. //-----------------------------------------------------------------------------
  131. // Forward declarations
  132. //-----------------------------------------------------------------------------
  133. void CL_SetPagedPoolInfo();
  134. extern char *CM_EntityString( void );
  135. extern ConVar host_map;
  136. extern ConVar sv_cheats;
  137. bool g_bDedicatedServerBenchmarkMode = false;
  138. bool g_bAllowSecureServers = true;
  139. bool g_bLowViolence = false;
  140. // These counters are for debugging in dumps. If these are non-zero it may indicate some kind of
  141. // heap problem caused by the setjmp/longjmp error handling
  142. int g_HostServerAbortCount = 0;
  143. int g_HostErrorCount = 0;
  144. int g_HostEndDemo = 0;
  145. char g_szDefaultLogoFileName[] = "materials/vgui/logos/spray.vtf";
  146. int host_frameticks = 0;
  147. int host_tickcount = 0;
  148. int host_currentframetick = 0;
  149. static const char g_pModuleExtension[] = DLL_EXT_STRING;
  150. // Engine player info, no game related infos here
  151. BEGIN_BYTESWAP_DATADESC( player_info_s )
  152. DEFINE_ARRAY( name, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  153. DEFINE_FIELD( userID, FIELD_INTEGER ),
  154. DEFINE_ARRAY( guid, FIELD_CHARACTER, SIGNED_GUID_LEN + 1 ),
  155. DEFINE_FIELD( friendsID, FIELD_INTEGER ),
  156. DEFINE_ARRAY( friendsName, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ),
  157. DEFINE_FIELD( fakeplayer, FIELD_BOOLEAN ),
  158. DEFINE_FIELD( ishltv, FIELD_BOOLEAN ),
  159. #if defined( REPLAY_ENABLED )
  160. DEFINE_FIELD( isreplay, FIELD_BOOLEAN ),
  161. #endif
  162. DEFINE_ARRAY( customFiles, FIELD_INTEGER, MAX_CUSTOM_FILES ),
  163. DEFINE_FIELD( filesDownloaded, FIELD_INTEGER ),
  164. END_BYTESWAP_DATADESC()
  165. //------------------------------------------
  166. enum
  167. {
  168. FRAME_SEGMENT_INPUT = 0,
  169. FRAME_SEGMENT_CLIENT,
  170. FRAME_SEGMENT_SERVER,
  171. FRAME_SEGMENT_RENDER,
  172. FRAME_SEGMENT_SOUND,
  173. FRAME_SEGMENT_CLDLL,
  174. FRAME_SEGMENT_CMD_EXECUTE,
  175. NUM_FRAME_SEGMENTS,
  176. };
  177. class CFrameTimer
  178. {
  179. public:
  180. void ResetDeltas();
  181. CFrameTimer() : swaptime(0)
  182. {
  183. ResetDeltas();
  184. }
  185. void MarkFrame();
  186. void StartFrameSegment( int i )
  187. {
  188. starttime[i] = Sys_FloatTime();
  189. }
  190. void EndFrameSegment( int i )
  191. {
  192. double dt = Sys_FloatTime() - starttime[i];
  193. deltas[ i ] += dt;
  194. }
  195. void MarkSwapTime( )
  196. {
  197. double newswaptime = Sys_FloatTime();
  198. frametime = newswaptime - swaptime;
  199. swaptime = newswaptime;
  200. ComputeFrameVariability();
  201. g_EngineStats.SetFrameTime( frametime );
  202. g_EngineStats.SetFPSVariability( m_flFPSVariability );
  203. host_frametime_stddeviation = m_flFPSStdDeviationSeconds;
  204. }
  205. private:
  206. enum
  207. {
  208. FRAME_HISTORY_COUNT = 50
  209. };
  210. friend void Host_Speeds();
  211. void ComputeFrameVariability();
  212. double time_base;
  213. double times[9];
  214. double swaptime;
  215. double frametime;
  216. double m_flFPSVariability;
  217. double m_flFPSStdDeviationSeconds;
  218. double starttime[NUM_FRAME_SEGMENTS];
  219. double deltas[NUM_FRAME_SEGMENTS];
  220. float m_pFrameTimeHistory[FRAME_HISTORY_COUNT];
  221. int m_nFrameTimeHistoryIndex;
  222. };
  223. static CFrameTimer g_HostTimes;
  224. //------------------------------------------
  225. float host_time = 0.0;
  226. static ConVar violence_hblood( "violence_hblood","1", 0, "Draw human blood" );
  227. static ConVar violence_hgibs( "violence_hgibs","1", 0, "Show human gib entities" );
  228. static ConVar violence_ablood( "violence_ablood","1", 0, "Draw alien blood" );
  229. static ConVar violence_agibs( "violence_agibs","1", 0, "Show alien gib entities" );
  230. // Marked as FCVAR_USERINFO so that the server can cull CC messages before networking them down to us!!!
  231. ConVar closecaption( "closecaption", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX | FCVAR_USERINFO, "Enable close captioning." );
  232. extern ConVar sv_unlockedchapters;
  233. void Snd_Restart_f()
  234. {
  235. #ifndef SWDS
  236. extern bool snd_firsttime;
  237. char szVoiceCodec[_MAX_PATH] = { 0 };
  238. int nVoiceSampleRate = Voice_ConfiguredSampleRate();
  239. {
  240. // This is not valid after voice shuts down
  241. const char *pPreviousCodec = Voice_ConfiguredCodec();
  242. if ( pPreviousCodec && *pPreviousCodec )
  243. {
  244. V_strncpy( szVoiceCodec, pPreviousCodec, sizeof( szVoiceCodec ) );
  245. }
  246. }
  247. S_Shutdown();
  248. snd_firsttime = true;
  249. cl.ClearSounds();
  250. S_Init();
  251. // Restart voice if it was running
  252. if ( szVoiceCodec[0] )
  253. Voice_Init( szVoiceCodec, nVoiceSampleRate );
  254. // Do this or else it won't have anything in the cache.
  255. if ( audiosourcecache && sv.GetMapName()[0] )
  256. {
  257. audiosourcecache->LevelInit( sv.GetMapName() );
  258. }
  259. // Flush soundscapes so they don't stop. We don't insert text in the buffer here because
  260. // cl_soundscape_flush is normally cheat-protected.
  261. ConCommand *pCommand = (ConCommand*)dynamic_cast< const ConCommand* >( g_pCVar->FindCommand( "cl_soundscape_flush" ) );
  262. if ( pCommand )
  263. {
  264. char const *argv[ 1 ] = { "cl_soundscape_flush" };
  265. CCommand cmd( 1, argv );
  266. pCommand->Dispatch( cmd );
  267. }
  268. #endif
  269. }
  270. static ConCommand snd_restart( "snd_restart", Snd_Restart_f, "Restart sound system." );
  271. // In other C files.
  272. void Shader_Shutdown( void );
  273. void R_Shutdown( void );
  274. bool g_bAbortServerSet = false;
  275. #ifdef _WIN32
  276. static bool s_bInitPME = false;
  277. #endif
  278. CON_COMMAND( mem_dump, "Dump memory stats to text file." )
  279. {
  280. ConMsg("Writing memory stats to file memstats.txt\n");
  281. #if defined( _MEMTEST )
  282. const char *pTest = sv.GetMapName();
  283. if ( !pTest || !pTest[0] )
  284. {
  285. // possibly at menu
  286. pTest = "unknown";
  287. }
  288. MemAlloc_SetStatsExtraInfo( pTest,"" );
  289. #endif
  290. MemAlloc_DumpStats();
  291. }
  292. CON_COMMAND( mem_compact, "" )
  293. {
  294. MemAlloc_CompactHeap();
  295. }
  296. CON_COMMAND( mem_eat, "" )
  297. {
  298. MemAlloc_Alloc( 1024* 1024 );
  299. }
  300. CON_COMMAND( mem_test, "" )
  301. {
  302. MemAlloc_CrtCheckMemory();
  303. }
  304. static ConVar host_competitive_ever_enabled( "host_competitive_ever_enabled", "0", FCVAR_HIDDEN, "Has competitive ever been enabled this run?", true, 0, true, 1, true, 1, false, 1, NULL );
  305. static ConVar mem_test_each_frame( "mem_test_each_frame", "0", 0, "Run heap check at end of every frame\n" );
  306. static ConVar mem_test_every_n_seconds( "mem_test_every_n_seconds", "0", 0, "Run heap check at a specified interval\n" );
  307. static ConVar singlestep( "singlestep", "0", FCVAR_CHEAT, "Run engine in single step mode ( set next to 1 to advance a frame )" );
  308. static ConVar cvarNext( "next", "0", FCVAR_CHEAT, "Set to 1 to advance to next frame ( when singlestep == 1 )" );
  309. // Print a debug message when the client or server cache is missed
  310. ConVar host_showcachemiss( "host_showcachemiss", "0", 0, "Print a debug message when the client or server cache is missed." );
  311. 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" );
  312. 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." );
  313. #if defined( RAD_TELEMETRY_ENABLED )
  314. static void OnChangeTelemetryPause ( IConVar *var, const char *pOldValue, float flOldValue )
  315. {
  316. tmPause( TELEMETRY_LEVEL0, 1 );
  317. }
  318. static void OnChangeTelemetryResume ( IConVar *var, const char *pOldValue, float flOldValue )
  319. {
  320. tmPause( TELEMETRY_LEVEL0, 0 );
  321. }
  322. static void OnChangeTelemetryLevel ( IConVar *var, const char *pOldValue, float flOldValue )
  323. {
  324. char* pIEnd;
  325. const char *pLevel = (( ConVar* )var)->GetString();
  326. TelemetrySetLevel( strtoul( pLevel, &pIEnd, 0 ) );
  327. }
  328. static void OnChangeTelemetryFrameCount ( IConVar *var, const char *pOldValue, float flOldValue )
  329. {
  330. char* pIEnd;
  331. const char *pFrameCount = (( ConVar* )var)->GetString();
  332. g_Telemetry.FrameCount = strtoul( pFrameCount, &pIEnd, 0 );
  333. Msg( " TELEMETRY: Setting Telemetry FrameCount: '%d'\n", g_Telemetry.FrameCount );
  334. }
  335. static void OnChangeTelemetryServer ( IConVar *var, const char *pOldValue, float flOldValue )
  336. {
  337. const char *pServerAddress = (( ConVar* )var)->GetString();
  338. Q_strncpy( g_Telemetry.ServerAddress, pServerAddress, ARRAYSIZE( g_Telemetry.ServerAddress ) );
  339. Msg( " TELEMETRY: Setting Telemetry server: '%s'\n", pServerAddress );
  340. }
  341. static void OnChangeTelemetryDemoStart ( IConVar *var, const char *pOldValue, float flOldValue )
  342. {
  343. char* pIEnd;
  344. const char *pVal = (( ConVar* )var)->GetString();
  345. g_Telemetry.DemoTickStart = strtoul( pVal, &pIEnd, 0 );
  346. if( g_Telemetry.DemoTickStart > 2000 )
  347. {
  348. char cmd[ 256 ];
  349. // If we're far away from the start of the demo file, then jump to ~1000 ticks before.
  350. Q_snprintf( cmd, sizeof( cmd ), "demo_gototick %d", g_Telemetry.DemoTickStart - 1000 );
  351. Cbuf_AddText( cmd );
  352. }
  353. Msg( " TELEMETRY: Setting Telemetry DemoTickStart: '%d'\n", g_Telemetry.DemoTickStart );
  354. }
  355. static void OnChangeTelemetryDemoEnd ( IConVar *var, const char *pOldValue, float flOldValue )
  356. {
  357. char* pIEnd;
  358. const char *pVal = (( ConVar* )var)->GetString();
  359. g_Telemetry.DemoTickEnd = strtoul( pVal, &pIEnd, 0 );
  360. Msg( " TELEMETRY: Setting Telemetry DemoTickEnd: '%d'\n", g_Telemetry.DemoTickEnd );
  361. }
  362. ConVar telemetry_pause( "telemetry_pause", "0", 0, "Pause Telemetry", OnChangeTelemetryPause );
  363. ConVar telemetry_resume( "telemetry_resume", "0", 0, "Resume Telemetry", OnChangeTelemetryResume );
  364. ConVar telemetry_framecount( "telemetry_framecount", "0", 0, "Set Telemetry count of frames to capture", OnChangeTelemetryFrameCount );
  365. ConVar telemetry_level( "telemetry_level", "0", 0, "Set Telemetry profile level: 0 being off.", OnChangeTelemetryLevel );
  366. ConVar telemetry_server( "telemetry_server", "localhost", 0, "Set Telemetry server", OnChangeTelemetryServer );
  367. ConVar telemetry_demostart( "telemetry_demostart", "0", 0, "When playing demo, start telemetry on tick #", OnChangeTelemetryDemoStart );
  368. ConVar telemetry_demoend( "telemetry_demoend", "0", 0, "When playing demo, stop telemetry on tick #", OnChangeTelemetryDemoEnd );
  369. #endif
  370. extern bool gfBackground;
  371. static bool host_checkheap = false;
  372. CCommonHostState host_state;
  373. //-----------------------------------------------------------------------------
  374. enum HostThreadMode
  375. {
  376. HTM_DISABLED,
  377. HTM_DEFAULT,
  378. HTM_FORCED,
  379. };
  380. ConVar host_thread_mode( "host_thread_mode", ( IsX360() ) ? "1" : "0", 0, "Run the host in threaded mode, (0 == off, 1 == if multicore, 2 == force)" );
  381. extern ConVar threadpool_affinity;
  382. void OnChangeThreadAffinity( IConVar *var, const char *pOldValue, float flOldValue )
  383. {
  384. if ( g_pThreadPool->NumThreads() )
  385. {
  386. g_pThreadPool->Distribute( threadpool_affinity.GetBool() );
  387. }
  388. }
  389. ConVar threadpool_affinity( "threadpool_affinity", "1", 0, "Enable setting affinity", 0, 0, 0, 0, &OnChangeThreadAffinity );
  390. #if 0
  391. extern ConVar threadpool_reserve;
  392. CThreadEvent g_ReleaseThreadReservation( true );
  393. CInterlockedInt g_NumReservedThreads;
  394. void ThreadPoolReserverFunction()
  395. {
  396. g_ReleaseThreadReservation.Wait();
  397. --g_NumReservedThreads;
  398. }
  399. void ReserveThreads( int nToReserve )
  400. {
  401. nToReserve = clamp( nToReserve, 0, g_pThreadPool->NumThreads() );
  402. g_ReleaseThreadReservation.Set();
  403. while ( g_NumReservedThreads != 0 )
  404. {
  405. ThreadSleep( 0 );
  406. }
  407. g_ReleaseThreadReservation.Reset();
  408. while ( nToReserve-- )
  409. {
  410. g_NumReservedThreads++;
  411. g_pThreadPool->QueueCall( &ThreadPoolReserverFunction )->Release();
  412. }
  413. Msg( "%d threads being reserved\n", (int)g_NumReservedThreads );
  414. }
  415. void OnChangeThreadReserve( IConVar *var, const char *pOldValue, float flOldValue )
  416. {
  417. ReserveThreads( threadpool_reserve.GetInt() );
  418. }
  419. ConVar threadpool_reserve( "threadpool_reserve", "0", 0, "Consume the specified number of threads in the thread pool", 0, 0, 0, 0, &OnChangeThreadReserve );
  420. CON_COMMAND( threadpool_cycle_reserve, "Cycles threadpool reservation by powers of 2" )
  421. {
  422. int nCores = g_pThreadPool->NumThreads() + 1;
  423. int nAvailableCores = nCores - g_NumReservedThreads;
  424. Assert( nAvailableCores );
  425. int ratio = nCores / nAvailableCores;
  426. ratio *= 2;
  427. if ( ratio > nCores )
  428. {
  429. ReserveThreads( 0 );
  430. }
  431. else
  432. {
  433. ReserveThreads( nCores - nCores / ratio );
  434. }
  435. }
  436. CON_COMMAND( thread_test_tslist, "" )
  437. {
  438. int nTests = ( args.ArgC() == 1 ) ? 10000 : atoi( args.Arg( 1 ) );
  439. RunTSListTests( nTests );
  440. }
  441. CON_COMMAND( thread_test_tsqueue, "" )
  442. {
  443. int nTests = ( args.ArgC() == 1 ) ? 10000 : atoi( args.Arg( 1 ) );
  444. RunTSQueueTests( nTests );
  445. }
  446. CON_COMMAND( threadpool_run_tests, "" )
  447. {
  448. int nTests = ( args.ArgC() == 1 ) ? 1 : atoi( args.Arg( 1 ) );
  449. for ( int i = 0; i < nTests; i++ )
  450. {
  451. RunThreadPoolTests();
  452. }
  453. }
  454. #endif
  455. //-----------------------------------------------------------------------------
  456. /*
  457. A server can always be started, even if the system started out as a client
  458. to a remote system.
  459. A client can NOT be started if the system started as a dedicated server.
  460. Memory is cleared / released when a server or client begins, not when they end.
  461. */
  462. // Ear position + orientation
  463. static AudioState_t s_AudioState;
  464. engineparms_t host_parms;
  465. bool host_initialized = false; // true if into command execution
  466. float host_frametime = 0.0f;
  467. float host_frametime_unbounded = 0.0f;
  468. float host_frametime_stddeviation = 0.0f;
  469. double realtime = 0; // without any filtering or bounding
  470. double host_idealtime = 0; // "ideal" server time assuming perfect tick rate
  471. float host_nexttick = 0; // next server tick in this many ms
  472. float host_jitterhistory[128] = { 0 };
  473. unsigned int host_jitterhistorypos = 0;
  474. int host_framecount;
  475. static int host_hunklevel;
  476. CGameClient *host_client; // current client
  477. jmp_buf host_abortserver;
  478. jmp_buf host_enddemo;
  479. static ConVar host_profile( "host_profile","0" );
  480. ConVar host_limitlocal( "host_limitlocal", "0", 0, "Apply cl_cmdrate and cl_updaterate to loopback connection" );
  481. ConVar host_framerate( "host_framerate","0", 0, "Set to lock per-frame time elapse." );
  482. ConVar host_timescale( "host_timescale","1.0", FCVAR_REPLICATED, "Prescale the clock by this amount." );
  483. ConVar host_speeds( "host_speeds","0", 0, "Show general system running times." ); // set for running times
  484. ConVar host_flush_threshold( "host_flush_threshold", "20", 0, "Memory threshold below which the host should flush caches between server instances" );
  485. void HostTimerSpinMsChangedCallback( IConVar *var, const char *pOldString, float flOldValue );
  486. ConVar host_timer_spin_ms( "host_timer_spin_ms", "0", FCVAR_NONE, "Use CPU busy-loop for improved timer precision (dedicated only)", HostTimerSpinMsChangedCallback );
  487. void HostTimerSpinMsChangedCallback( IConVar *var, const char *pOldString, float flOldValue )
  488. {
  489. const char *pForcedValue = CommandLine()->ParmValue( "+host_timer_spin_ms" );
  490. if ( pForcedValue != NULL )
  491. {
  492. if ( V_strcmp( host_timer_spin_ms.GetString(), pForcedValue ) )
  493. {
  494. Msg( "Value for host_timer_spin_ms is locked to %s by command line parameter.\n", pForcedValue );
  495. host_timer_spin_ms.SetValue( pForcedValue );
  496. }
  497. }
  498. }
  499. CON_COMMAND( host_timer_report, "Spew CPU timer jitter for the last 128 frames in microseconds (dedicated only)" )
  500. {
  501. if ( sv.IsDedicated() )
  502. {
  503. for (int i = 1; i <= ARRAYSIZE( host_jitterhistory ); ++i)
  504. {
  505. unsigned int slot = ( i + host_jitterhistorypos ) % ARRAYSIZE( host_jitterhistory );
  506. Msg( "%1.3fms\n", host_jitterhistory[ slot ] * 1000 );
  507. }
  508. }
  509. }
  510. #ifdef REL_TO_STAGING_MERGE_TODO
  511. // Do this when merging the game DLLs so FCVAR_CHEAT can be set on them at the same time.
  512. ConVar developer( "developer", "0", FCVAR_CHEAT, "Set developer message level");
  513. #else
  514. ConVar developer( "developer", "0", 0, "Set developer message level");
  515. #endif
  516. ConVar skill( "skill","1", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Game skill level (1-3).", true, 1, true, 3 ); // 1 - 3
  517. ConVar deathmatch( "deathmatch","0", FCVAR_NOTIFY | FCVAR_INTERNAL_USE, "Running a deathmatch server." ); // 0, 1, or 2
  518. ConVar coop( "coop","0", FCVAR_NOTIFY, "Cooperative play." ); // 0 or 1
  519. #ifdef _DEBUG
  520. ConVar r_ForceRestore( "r_ForceRestore", "0", 0 );
  521. #endif // _DEBUG
  522. ConVar vcr_verbose( "vcr_verbose", "0", 0, "Write extra information into .vcr file." );
  523. #ifndef SWDS
  524. void CL_CheckToDisplayStartupMenus(); // in cl_main.cpp
  525. #endif
  526. bool GetFileFromRemoteStorage( ISteamRemoteStorage *pRemoteStorage, const char *pszRemoteFileName, const char *pszLocalFileName )
  527. {
  528. bool bSuccess = false;
  529. // check if file exists in Steam Cloud first
  530. int32 nFileSize = pRemoteStorage->GetFileSize( pszRemoteFileName );
  531. if ( nFileSize > 0 )
  532. {
  533. CUtlMemory<char> buf( 0, nFileSize );
  534. if ( pRemoteStorage->FileRead( pszRemoteFileName, buf.Base(), nFileSize ) == nFileSize )
  535. {
  536. char filepath[ 512 ];
  537. Q_strncpy( filepath, pszLocalFileName, sizeof( filepath ) );
  538. Q_StripFilename( filepath );
  539. g_pFullFileSystem->CreateDirHierarchy( filepath, "MOD" );
  540. FileHandle_t hFile = g_pFileSystem->Open( pszLocalFileName, "wb", "MOD" );
  541. if( hFile )
  542. {
  543. bSuccess = g_pFileSystem->Write( buf.Base(), nFileSize, hFile ) == nFileSize;
  544. g_pFileSystem->Close( hFile );
  545. if ( bSuccess )
  546. {
  547. DevMsg( "[Cloud]: SUCCEESS retrieved %s from remote storage into %s\n", pszRemoteFileName, pszLocalFileName );
  548. }
  549. else
  550. {
  551. DevMsg( "[Cloud]: FAILED retrieved %s from remote storage into %s\n", pszRemoteFileName, pszLocalFileName );
  552. }
  553. }
  554. }
  555. }
  556. return bSuccess;
  557. }
  558. void CCommonHostState::SetWorldModel( model_t *pModel )
  559. {
  560. worldmodel = pModel;
  561. if ( pModel )
  562. {
  563. worldbrush = pModel->brush.pShared;
  564. }
  565. else
  566. {
  567. worldbrush = NULL;
  568. }
  569. }
  570. void Host_DefaultMapFileName( const char *pFullMapName, /* out */ char *pDiskName, unsigned int nDiskNameSize )
  571. {
  572. if ( IsPC() || !IsX360() )
  573. {
  574. // pc names are as is
  575. Q_snprintf( pDiskName, nDiskNameSize, "maps/%s.bsp", pFullMapName );
  576. }
  577. else if ( IsX360() )
  578. {
  579. Q_snprintf( pDiskName, nDiskNameSize, "maps/%s.360.bsp", pFullMapName );
  580. }
  581. }
  582. void Host_SetAudioState( const AudioState_t &audioState )
  583. {
  584. memcpy( &s_AudioState, &audioState, sizeof(AudioState_t) );
  585. }
  586. bool Host_IsSinglePlayerGame( void )
  587. {
  588. if ( sv.IsActive() )
  589. {
  590. return !sv.IsMultiplayer();
  591. }
  592. else
  593. {
  594. return cl.m_nMaxClients == 1;
  595. }
  596. }
  597. void CheckForFlushMemory( const char *pCurrentMapName, const char *pDestMapName )
  598. {
  599. if ( host_flush_threshold.GetInt() == 0 )
  600. return;
  601. #if defined(_X360)
  602. // There are three cases in which we flush memory
  603. // Case 1: changing from one map to another
  604. // -> flush temp data caches
  605. // Case 2: loading any map (inc. A to A) and free memory is below host_flush_threshold MB
  606. // -> flush everything
  607. // Case 3: loading a 'blacklisted' map (the known biggest memory users, or where texture sets change)
  608. // -> flush everything
  609. static const char *mapBlackList[] =
  610. {
  611. // --hl2--
  612. "d1_canals_01",
  613. "d1_canals_05",
  614. "d1_eli_01",
  615. "d1_town_01",
  616. "d2_coast_01",
  617. "d2_prison_01",
  618. "d3_c17_01",
  619. "d3_c17_05",
  620. "d3_c17_09",
  621. "d3_citadel_01",
  622. "d3_breen_01",
  623. // --ep1--
  624. "ep1_c17_02",
  625. "ep1_c17_02b",
  626. "ep1_c17_05",
  627. "ep1_c17_06",
  628. // --ep2--
  629. "ep2_outland_06a",
  630. "ep2_outland_09",
  631. "ep2_outland_11",
  632. "ep2_outland_12",
  633. "ep2_outland_12a",
  634. // --tf--
  635. "tc_hydro"
  636. };
  637. char szCurrentMapName[MAX_PATH];
  638. char szDestMapName[MAX_PATH];
  639. if ( pCurrentMapName )
  640. {
  641. V_FileBase( pCurrentMapName, szCurrentMapName, sizeof( szCurrentMapName ) );
  642. }
  643. else
  644. {
  645. szCurrentMapName[0] = '\0';
  646. }
  647. pCurrentMapName = szCurrentMapName;
  648. if ( pDestMapName )
  649. {
  650. V_FileBase( pDestMapName, szDestMapName, sizeof( szDestMapName ) );
  651. }
  652. else
  653. {
  654. szDestMapName[0] = '\0';
  655. }
  656. pDestMapName = szDestMapName;
  657. bool bIsMapChanging = pCurrentMapName[0] && V_stricmp( pCurrentMapName, pDestMapName );
  658. bool bIsDestMapBlacklisted = false;
  659. for ( int i = 0; i < ARRAYSIZE( mapBlackList ); i++ )
  660. {
  661. if ( pDestMapName && !V_stricmp( pDestMapName, mapBlackList[i] ) )
  662. {
  663. bIsDestMapBlacklisted = true;
  664. }
  665. }
  666. DevMsg( "---CURRENT(%s), NEXT(%s)\n", (pCurrentMapName[0] ? pCurrentMapName : "----"), (pDestMapName[0] ? pDestMapName : "----") );
  667. if ( bIsMapChanging )
  668. {
  669. DevMsg( "---CHANGING MAPS!\n" );
  670. }
  671. if ( bIsDestMapBlacklisted )
  672. {
  673. DevMsg( "---BLACKLISTED!\n" );
  674. }
  675. MEMORYSTATUS stat;
  676. GlobalMemoryStatus( &stat );
  677. if ( ( stat.dwAvailPhys < host_flush_threshold.GetInt() * 1024 * 1024 ) ||
  678. ( bIsDestMapBlacklisted && bIsMapChanging ) )
  679. {
  680. // Flush everything; ALL data is reloaded from scratch
  681. SV_FlushMemoryOnNextServer();
  682. g_pDataCache->Flush();
  683. DevWarning( "---FULL FLUSH\n" );
  684. }
  685. else if ( bIsMapChanging )
  686. {
  687. // Flush temporary data (async anim, non-locked async audio)
  688. g_pMDLCache->Flush( MDLCACHE_FLUSH_ANIMBLOCK );
  689. wavedatacache->Flush();
  690. DevWarning( "---PARTIAL FLUSH\n" );
  691. }
  692. DevMsg( "---- --- ----\n" );
  693. #endif
  694. }
  695. void Host_AbortServer()
  696. {
  697. g_HostServerAbortCount++;
  698. longjmp( host_abortserver, 1 );
  699. }
  700. /*
  701. ================
  702. Host_EndGame
  703. ================
  704. */
  705. void Host_EndGame (bool bShowMainMenu, const char *message, ...)
  706. {
  707. int oldn;
  708. va_list argptr;
  709. char string[1024];
  710. va_start (argptr,message);
  711. Q_vsnprintf (string,sizeof(string),message,argptr);
  712. va_end (argptr);
  713. ConMsg ("Host_EndGame: %s\n",string);
  714. #ifndef SWDS
  715. scr_disabled_for_loading = true;
  716. #endif
  717. oldn = cl.demonum;
  718. cl.demonum = -1;
  719. Host_Disconnect(bShowMainMenu);
  720. cl.demonum = oldn;
  721. if ( sv.IsDedicated() )
  722. {
  723. Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit
  724. return;
  725. }
  726. if (cl.demonum != -1)
  727. {
  728. #ifndef SWDS
  729. CL_NextDemo ();
  730. #endif
  731. g_HostEndDemo++;
  732. longjmp (host_enddemo, 1);
  733. }
  734. else
  735. {
  736. #ifndef SWDS
  737. scr_disabled_for_loading = false;
  738. #endif
  739. if ( g_bAbortServerSet )
  740. {
  741. Host_AbortServer();
  742. }
  743. }
  744. }
  745. /*
  746. ================
  747. Host_Error
  748. This shuts down both the client and server
  749. ================
  750. */
  751. void Host_Error (const char *error, ...)
  752. {
  753. va_list argptr;
  754. char string[1024];
  755. static bool inerror = false;
  756. DebuggerBreakIfDebugging_StagingOnly();
  757. g_HostErrorCount++;
  758. if (inerror)
  759. {
  760. Sys_Error ("Host_Error: recursively entered");
  761. }
  762. inerror = true;
  763. #ifndef SWDS
  764. // CL_WriteMessageHistory(); TODO must be done by network layer
  765. #endif
  766. va_start (argptr,error);
  767. Q_vsnprintf(string,sizeof(string),error,argptr);
  768. va_end (argptr);
  769. if ( sv.IsDedicated() )
  770. {
  771. // dedicated servers just exit
  772. Sys_Error( "Host_Error: %s\n", string );
  773. return;
  774. }
  775. #ifndef SWDS
  776. // Reenable screen updates
  777. SCR_EndLoadingPlaque ();
  778. #endif
  779. ConMsg( "\nHost_Error: %s\n\n", string );
  780. Host_Disconnect( true, string );
  781. cl.demonum = -1;
  782. inerror = false;
  783. if ( g_bAbortServerSet )
  784. {
  785. Host_AbortServer();
  786. }
  787. }
  788. #ifndef SWDS
  789. ButtonCode_t nInvalidKeyBindings[] =
  790. {
  791. KEY_PAD_0,
  792. KEY_PAD_1,
  793. KEY_PAD_2,
  794. KEY_PAD_3,
  795. KEY_PAD_4,
  796. KEY_PAD_5,
  797. KEY_PAD_6,
  798. KEY_PAD_7,
  799. KEY_PAD_8,
  800. KEY_PAD_9,
  801. KEY_PAD_DIVIDE,
  802. KEY_PAD_MULTIPLY,
  803. KEY_PAD_MINUS,
  804. KEY_PAD_PLUS,
  805. KEY_PAD_ENTER,
  806. KEY_PAD_DECIMAL,
  807. KEY_ESCAPE,
  808. KEY_SCROLLLOCK,
  809. KEY_INSERT,
  810. KEY_DELETE,
  811. KEY_HOME,
  812. KEY_END,
  813. KEY_PAGEUP,
  814. KEY_PAGEDOWN,
  815. KEY_BREAK,
  816. KEY_LSHIFT,
  817. KEY_RSHIFT,
  818. KEY_LALT,
  819. KEY_RALT,
  820. KEY_LCONTROL,
  821. KEY_RCONTROL,
  822. KEY_LWIN,
  823. KEY_RWIN,
  824. KEY_APP,
  825. KEY_UP,
  826. KEY_LEFT,
  827. KEY_DOWN,
  828. KEY_RIGHT,
  829. KEY_CAPSLOCKTOGGLE,
  830. KEY_NUMLOCKTOGGLE,
  831. KEY_SCROLLLOCKTOGGLE,
  832. KEY_BACKQUOTE,
  833. };
  834. //******************************************
  835. // SetupNewBindings
  836. //
  837. // In the rare case that we ship an update
  838. // where we need a key to be bound to a given
  839. // con-command, this function do its best to
  840. // bind those keys, based on a file called
  841. // newbindings.txt.
  842. //******************************************
  843. void SetupNewBindings()
  844. {
  845. char szBindCmd[ 256 ];
  846. // Load the file
  847. const char *pFilename = "scripts\\newbindings.txt";
  848. KeyValues *pNewBindingsData = new KeyValues( pFilename );
  849. if ( !pNewBindingsData->LoadFromFile( g_pFileSystem, pFilename ) )
  850. {
  851. pNewBindingsData->deleteThis();
  852. return;
  853. }
  854. FOR_EACH_TRUE_SUBKEY( pNewBindingsData, pSubKey )
  855. {
  856. // Get the binding
  857. const char *pBinding = pSubKey->GetName();
  858. if ( !pBinding )
  859. continue;
  860. // Get the ideal key
  861. const char *pIdealKey = pSubKey->GetString( "ideal_key", NULL );
  862. if ( !pIdealKey )
  863. continue;
  864. // Force the key binding if the ideal key is bound to an irrelevant command, which is the
  865. // case for CS:S, which binds F6 to "quick save," which has no used in the game at all.
  866. const char *pOverrideIfCmd = pSubKey->GetString( "override_if", NULL );
  867. if ( pOverrideIfCmd )
  868. {
  869. const char *pCurrentBindingForKey = ::Key_BindingForKey( g_pInputSystem->StringToButtonCode( pIdealKey ) );
  870. if ( !pCurrentBindingForKey || !V_stricmp( pOverrideIfCmd, pCurrentBindingForKey ) )
  871. {
  872. V_snprintf( szBindCmd, sizeof( szBindCmd ), "bind \"%s\" \"%s\"", pIdealKey, pBinding );
  873. Cbuf_AddText( szBindCmd );
  874. continue;
  875. }
  876. }
  877. // Already have a key for this command?
  878. if ( ::Key_NameForBinding( pBinding ) )
  879. continue;
  880. // No binding. Is the ideal key available?
  881. ButtonCode_t bcIdealKey = g_pInputSystem->StringToButtonCode( pIdealKey );
  882. const char *pCurrentBindingForIdealKey = ::Key_BindingForKey( bcIdealKey );
  883. if ( !pCurrentBindingForIdealKey )
  884. {
  885. // Yes - bind to the ideal key.
  886. V_snprintf( szBindCmd, sizeof( szBindCmd ), "bind \"%s\" \"%s\"", pIdealKey, pBinding );
  887. Cbuf_AddText( szBindCmd );
  888. continue;
  889. }
  890. // Ideal key already bound - find another key at random and bind it
  891. bool bFound = false;
  892. int nNumAttempts = 1;
  893. for ( int nCurButton = (int)KEY_0; nCurButton <= (int)KEY_LAST; ++nCurButton, ++nNumAttempts )
  894. {
  895. // Don't consider numpad, windows keys, etc
  896. bool bFoundInvalidKey = false;
  897. for ( int iKeyIndex = 0; iKeyIndex < sizeof( nInvalidKeyBindings )/sizeof( nInvalidKeyBindings[0] ); iKeyIndex++ )
  898. {
  899. if ( nCurButton == (int)nInvalidKeyBindings[iKeyIndex] )
  900. {
  901. bFoundInvalidKey = true;
  902. break;
  903. }
  904. }
  905. if ( bFoundInvalidKey )
  906. continue;
  907. // Key available?
  908. ButtonCode_t bcCurButton = (ButtonCode_t)nCurButton;
  909. if ( !::Key_BindingForKey( bcCurButton ) )
  910. {
  911. // Yes - use it.
  912. V_snprintf( szBindCmd, sizeof( szBindCmd ), "bind \"%s\" \"%s\"", g_pInputSystem->ButtonCodeToString( bcCurButton ), pBinding );
  913. Cbuf_AddText( szBindCmd );
  914. bFound = true;
  915. break;
  916. }
  917. }
  918. // We tried really hard - did we fail?
  919. if ( !bFound )
  920. {
  921. Warning( "Unable to bind a key for command \"%s\" after %i attempt(s).\n", pBinding, nNumAttempts );
  922. }
  923. }
  924. }
  925. //******************************************
  926. // UseDefuaultBinding
  927. //
  928. // If the config.cfg file is not present, this
  929. // function is called to set the default key
  930. // bindings to match those defined in kb_def.lst
  931. //******************************************
  932. void UseDefaultBindings( void )
  933. {
  934. FileHandle_t f;
  935. char szFileName[ _MAX_PATH ];
  936. char token[ 1024 ];
  937. char szKeyName[ 256 ];
  938. // read kb_def file to get default key binds
  939. Q_snprintf( szFileName, sizeof( szFileName ), "%skb_def.lst", SCRIPT_DIR );
  940. f = g_pFileSystem->Open( szFileName, "r");
  941. if ( !f )
  942. {
  943. ConMsg( "Couldn't open kb_def.lst\n" );
  944. return;
  945. }
  946. // read file into memory
  947. int size = g_pFileSystem->Size(f);
  948. char *startbuf = new char[ size ];
  949. g_pFileSystem->Read( startbuf, size, f );
  950. g_pFileSystem->Close( f );
  951. const char *buf = startbuf;
  952. while ( 1 )
  953. {
  954. buf = COM_ParseFile( buf, token, sizeof( token ) );
  955. if ( strlen( token ) <= 0 )
  956. break;
  957. Q_strncpy ( szKeyName, token, sizeof( szKeyName ) );
  958. buf = COM_ParseFile( buf, token, sizeof( token ) );
  959. if ( strlen( token ) <= 0 ) // Error
  960. break;
  961. // finally, bind key
  962. Key_SetBinding ( g_pInputSystem->StringToButtonCode( szKeyName ), token );
  963. }
  964. delete [] startbuf; // cleanup on the way out
  965. }
  966. static bool g_bConfigCfgExecuted = false;
  967. //-----------------------------------------------------------------------------
  968. // Purpose: Write out our 360 exclusive settings to internal storage
  969. //-----------------------------------------------------------------------------
  970. void Host_WriteConfiguration_360( void )
  971. {
  972. #ifdef _X360
  973. if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
  974. return;
  975. // Construct the name for our config settings for this mod
  976. char strFilename[MAX_PATH];
  977. Q_snprintf( strFilename, sizeof(strFilename), "cfg:/%s_config.cfg", GetCurrentMod() );
  978. // Always throw away all keys that are left over.
  979. CUtlBuffer configBuff( 0, 0, CUtlBuffer::TEXT_BUFFER);
  980. configBuff.Printf( "unbindall\n" );
  981. Key_WriteBindings( configBuff );
  982. cv->WriteVariables( configBuff );
  983. ConVarRef mat_monitorgamma( "mat_monitorgamma" );
  984. ConVarRef mat_monitorgamma_tv_enabled( "mat_monitorgamma_tv_enabled" );
  985. char strVideoFilename[MAX_PATH];
  986. CUtlBuffer videoBuff( 0, 0, CUtlBuffer::TEXT_BUFFER);
  987. Q_snprintf( strVideoFilename, sizeof(strVideoFilename), "cfg:/video_config.cfg" );
  988. videoBuff.Printf( "mat_monitorgamma %f\n", mat_monitorgamma.GetFloat() );
  989. videoBuff.Printf( "mat_monitorgamma_tv_enabled %d\n", mat_monitorgamma_tv_enabled.GetBool() );
  990. // Anything to write?
  991. if ( configBuff.TellMaxPut() )
  992. {
  993. g_pFileSystem->WriteFile( strFilename, NULL, configBuff );
  994. }
  995. if ( videoBuff.TellMaxPut() )
  996. {
  997. g_pFileSystem->WriteFile( strVideoFilename, NULL, videoBuff );
  998. }
  999. g_pXboxSystem->FinishContainerWrites();
  1000. #endif // #ifdef _X360
  1001. }
  1002. /*
  1003. ===============
  1004. Host_WriteConfiguration
  1005. Writes key bindings and archived cvars to config.cfg
  1006. ===============
  1007. */
  1008. void Host_WriteConfiguration( const char *filename, bool bAllVars )
  1009. {
  1010. const bool cbIsUserRequested = ( filename != NULL );
  1011. if ( !filename )
  1012. filename = "config.cfg";
  1013. if ( !g_bConfigCfgExecuted )
  1014. return;
  1015. if ( !host_initialized )
  1016. return;
  1017. // Don't write config when in default--most of the values are defaults which is not what the player wants.
  1018. // If bAllVars is set, go ahead and write out the file anyways, since it was requested explicitly.
  1019. if ( !cbIsUserRequested && ( CommandLine()->CheckParm( "-default" ) || host_competitive_ever_enabled.GetBool() ) )
  1020. return;
  1021. // Write to internal storage on the 360
  1022. if ( IsX360() )
  1023. {
  1024. Host_WriteConfiguration_360();
  1025. return;
  1026. }
  1027. // If in map editing mode don't save configuration
  1028. if (g_bInEditMode)
  1029. {
  1030. ConMsg( "skipping %s output when in map edit mode\n", filename );
  1031. return;
  1032. }
  1033. // dedicated servers initialize the host but don't parse and set the
  1034. // config.cfg cvars
  1035. if ( sv.IsDedicated() )
  1036. return;
  1037. if ( IsPC() && Key_CountBindings() <= 1 )
  1038. {
  1039. ConMsg( "skipping %s output, no keys bound\n", filename );
  1040. return;
  1041. }
  1042. // force any queued convar changes to flush before reading/writing them
  1043. UpdateMaterialSystemConfig();
  1044. // Generate a new .cfg file.
  1045. char szFileName[MAX_PATH];
  1046. CUtlBuffer configBuff( 0, 0, CUtlBuffer::TEXT_BUFFER);
  1047. Q_snprintf( szFileName, sizeof(szFileName), "cfg/%s", filename );
  1048. g_pFileSystem->CreateDirHierarchy( "cfg", "MOD" );
  1049. if ( g_pFileSystem->FileExists( szFileName, "MOD" ) && !g_pFileSystem->IsFileWritable( szFileName, "MOD" ) )
  1050. {
  1051. ConMsg( "Config file %s is read-only!!\n", szFileName );
  1052. return;
  1053. }
  1054. // Always throw away all keys that are left over.
  1055. configBuff.Printf( "unbindall\n" );
  1056. Key_WriteBindings( configBuff );
  1057. cv->WriteVariables( configBuff, bAllVars );
  1058. #if !defined( SWDS )
  1059. bool down;
  1060. if ( g_ClientDLL->IN_IsKeyDown( "in_jlook", down ) && down )
  1061. {
  1062. configBuff.Printf( "+jlook\n" );
  1063. }
  1064. #endif // SWDS
  1065. if ( !configBuff.TellMaxPut() )
  1066. {
  1067. // nothing to write
  1068. return;
  1069. }
  1070. #if defined(NO_STEAM)
  1071. AssertMsg( false, "SteamCloud not available on Xbox 360. Badger Martin to fix this." );
  1072. #else
  1073. ISteamRemoteStorage *pRemoteStorage = SteamClient()?(ISteamRemoteStorage *)SteamClient()->GetISteamGenericInterface(
  1074. SteamAPI_GetHSteamUser(), SteamAPI_GetHSteamPipe(), STEAMREMOTESTORAGE_INTERFACE_VERSION ):NULL;
  1075. if ( pRemoteStorage )
  1076. {
  1077. int32 availableBytes, totalBytes = 0;
  1078. if ( pRemoteStorage->GetQuota( &totalBytes, &availableBytes ) )
  1079. {
  1080. if ( totalBytes > 0 )
  1081. {
  1082. if ( cl_cloud_settings.GetInt() == STEAMREMOTESTORAGE_CLOUD_ON )
  1083. {
  1084. // TODO put MOD dir in pathname
  1085. if ( pRemoteStorage->FileWrite( szFileName, configBuff.Base(), configBuff.TellMaxPut() ) )
  1086. {
  1087. DevMsg( "[Cloud]: SUCCEESS saving %s in remote storage\n", szFileName );
  1088. }
  1089. else
  1090. {
  1091. // probably a quota issue. TODO what to do ?
  1092. DevMsg( "[Cloud]: FAILED saving %s in remote storage\n", szFileName );
  1093. }
  1094. // write the current logo file
  1095. char szLogoFileName[MAX_PATH];
  1096. Q_strncpy( szLogoFileName, cl_logofile.GetString(), sizeof(szLogoFileName) ); // .vtf file
  1097. if ( g_pFileSystem->FileExists( szLogoFileName, "MOD" ) )
  1098. {
  1099. // store logo .VTF file
  1100. FileHandle_t hFile = g_pFileSystem->Open( szLogoFileName, "rb", "MOD" );
  1101. if ( FILESYSTEM_INVALID_HANDLE != hFile )
  1102. {
  1103. unsigned int unSize = g_pFileSystem->Size( hFile );
  1104. byte *pBuffer = (byte*) malloc( unSize );
  1105. if ( g_pFileSystem->Read( pBuffer, unSize, hFile ) == unSize )
  1106. {
  1107. Q_SetExtension( g_szDefaultLogoFileName, ".vtf", sizeof(g_szDefaultLogoFileName) );
  1108. if ( pRemoteStorage->FileWrite( g_szDefaultLogoFileName, pBuffer, unSize ) )
  1109. {
  1110. DevMsg( "[Cloud]: SUCCEESS saving %s in remote storage\n", g_szDefaultLogoFileName );
  1111. }
  1112. else
  1113. {
  1114. DevMsg( "[Cloud]: FAILED saving %s in remote storage\n", g_szDefaultLogoFileName );
  1115. }
  1116. }
  1117. free( pBuffer );
  1118. g_pFileSystem->Close( hFile );
  1119. }
  1120. // store logo .VMT file
  1121. Q_SetExtension( szLogoFileName, ".vmt", sizeof(szLogoFileName) );
  1122. hFile = g_pFileSystem->Open( szLogoFileName, "rb", "MOD" );
  1123. if ( FILESYSTEM_INVALID_HANDLE != hFile )
  1124. {
  1125. unsigned int unSize = g_pFileSystem->Size( hFile );
  1126. byte *pBuffer = (byte*) malloc( unSize );
  1127. if ( g_pFileSystem->Read( pBuffer, unSize, hFile ) == unSize )
  1128. {
  1129. Q_SetExtension( g_szDefaultLogoFileName, ".vmt", sizeof(g_szDefaultLogoFileName) );
  1130. if ( pRemoteStorage->FileWrite( g_szDefaultLogoFileName, pBuffer, unSize ) )
  1131. {
  1132. DevMsg( "[Cloud]: SUCCEESS saving %s in remote storage\n", g_szDefaultLogoFileName );
  1133. }
  1134. else
  1135. {
  1136. DevMsg( "[Cloud]: FAILED saving %s in remote storage\n", g_szDefaultLogoFileName );
  1137. }
  1138. }
  1139. free( pBuffer );
  1140. g_pFileSystem->Close( hFile );
  1141. }
  1142. }
  1143. }
  1144. }
  1145. }
  1146. // even if SteamCloud worked we still safe the same file locally
  1147. }
  1148. #endif
  1149. // make a persistent copy that async will use and free
  1150. char *tempBlock = new char[configBuff.TellMaxPut()];
  1151. Q_memcpy( tempBlock, configBuff.Base(), configBuff.TellMaxPut() );
  1152. // async write the buffer, and then free it
  1153. g_pFileSystem->AsyncWrite( szFileName, tempBlock, configBuff.TellMaxPut(), true );
  1154. ConMsg( "Host_WriteConfiguration: Wrote %s\n", szFileName );
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. // Purpose: Retrieve and set any defaults from the user's gamer profile
  1158. //-----------------------------------------------------------------------------
  1159. bool XBX_SetProfileDefaultSettings( void )
  1160. {
  1161. // These defined values can't play nicely with the PC, so we need to ignore them for that build target
  1162. #ifdef _X360
  1163. // These will act as indices into the array that is returned by the API
  1164. enum
  1165. {
  1166. XPS_GAMER_DIFFICULTY,
  1167. XPS_GAMER_ACTION_MOVEMENT_CONTROL,
  1168. XPS_GAMER_YAXIS_INVERSION,
  1169. XPS_OPTION_CONTROLLER_VIBRATION,
  1170. NUM_PROFILE_SETTINGS
  1171. };
  1172. // These are the values we're interested in having returned (must match the indices above)
  1173. const DWORD dwSettingIds[ NUM_PROFILE_SETTINGS ] =
  1174. {
  1175. XPROFILE_GAMER_DIFFICULTY,
  1176. XPROFILE_GAMER_ACTION_MOVEMENT_CONTROL,
  1177. XPROFILE_GAMER_YAXIS_INVERSION,
  1178. XPROFILE_OPTION_CONTROLLER_VIBRATION
  1179. };
  1180. // Must have a valid primary user by this point
  1181. int nPrimaryID = XBX_GetPrimaryUserId();
  1182. // First, we call with a NULL pointer and zero size to retrieve the buffer size we'll get back
  1183. DWORD dwResultSize = 0; // Must be zero to get the correct size back
  1184. XUSER_READ_PROFILE_SETTING_RESULT *pResults = NULL;
  1185. DWORD dwError = XUserReadProfileSettings( 0, // Family ID (current title)
  1186. nPrimaryID, // User ID
  1187. NUM_PROFILE_SETTINGS,
  1188. dwSettingIds,
  1189. &dwResultSize,
  1190. pResults,
  1191. NULL );
  1192. // We need this to inform us that it's given us a size back for the buffer
  1193. if ( dwError != ERROR_INSUFFICIENT_BUFFER )
  1194. return false;
  1195. // Now we allocate that buffer and supply it to the call
  1196. BYTE *pData = (BYTE *) stackalloc( dwResultSize );
  1197. ZeroMemory( pData, dwResultSize );
  1198. pResults = (XUSER_READ_PROFILE_SETTING_RESULT *) pData;
  1199. dwError = XUserReadProfileSettings( 0, // Family ID (current title)
  1200. nPrimaryID, // User ID
  1201. NUM_PROFILE_SETTINGS,
  1202. dwSettingIds,
  1203. &dwResultSize,
  1204. pResults,
  1205. NULL ); // Not overlapped, must be synchronous
  1206. // We now have a raw buffer of results
  1207. if ( dwError != ERROR_SUCCESS )
  1208. return false;
  1209. //
  1210. // Skill
  1211. //
  1212. XUSER_PROFILE_SETTING *pSetting = pResults->pSettings + XPS_GAMER_DIFFICULTY;
  1213. Assert( pSetting->data.type == XUSER_DATA_TYPE_INT32 );
  1214. int nSkillSetting = pSetting->data.nData;
  1215. int nResultSkill = 0;
  1216. switch( nSkillSetting )
  1217. {
  1218. case XPROFILE_GAMER_DIFFICULTY_NORMAL:
  1219. nResultSkill = 2;
  1220. break;
  1221. case XPROFILE_GAMER_DIFFICULTY_HARD:
  1222. nResultSkill = 3;
  1223. break;
  1224. case XPROFILE_GAMER_DIFFICULTY_EASY:
  1225. default:
  1226. nResultSkill = 1;
  1227. break;
  1228. }
  1229. // If the mod has no difficulty setting, only easy is allowed
  1230. KeyValues *modinfo = new KeyValues("ModInfo");
  1231. if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) )
  1232. {
  1233. if ( stricmp(modinfo->GetString("nodifficulty", "0"), "1") == 0 )
  1234. nResultSkill = 1;
  1235. }
  1236. modinfo->deleteThis();
  1237. char szScratch[MAX_PATH];
  1238. Q_snprintf( szScratch, sizeof(szScratch), "skill %d", nResultSkill );
  1239. Cbuf_AddText( szScratch );
  1240. //
  1241. // Movement control
  1242. //
  1243. pSetting = pResults->pSettings + XPS_GAMER_ACTION_MOVEMENT_CONTROL;
  1244. Assert( pSetting->data.type == XUSER_DATA_TYPE_INT32 );
  1245. Q_snprintf( szScratch, sizeof(szScratch), "joy_movement_stick %d", ( pSetting->data.nData == XPROFILE_ACTION_MOVEMENT_CONTROL_L_THUMBSTICK ) ? 0 : 1 );
  1246. Cbuf_AddText( szScratch );
  1247. Q_snprintf( szScratch, sizeof(szScratch), "joy_movement_stick_default %d", ( pSetting->data.nData == XPROFILE_ACTION_MOVEMENT_CONTROL_L_THUMBSTICK ) ? 0 : 1 );
  1248. Cbuf_AddText( szScratch );
  1249. Cbuf_AddText( "joyadvancedupdate" );
  1250. //
  1251. // Y-Inversion
  1252. //
  1253. pSetting = pResults->pSettings + XPS_GAMER_YAXIS_INVERSION;
  1254. Assert( pSetting->data.type == XUSER_DATA_TYPE_INT32 );
  1255. Q_snprintf( szScratch, sizeof(szScratch), "joy_inverty %d", pSetting->data.nData );
  1256. Cbuf_AddText( szScratch );
  1257. Q_snprintf( szScratch, sizeof(szScratch), "joy_inverty_default %d", pSetting->data.nData );
  1258. Cbuf_AddText( szScratch );
  1259. //
  1260. // Vibration control
  1261. //
  1262. pSetting = pResults->pSettings + XPS_OPTION_CONTROLLER_VIBRATION;
  1263. Assert( pSetting->data.type == XUSER_DATA_TYPE_INT32 );
  1264. Q_snprintf( szScratch, sizeof(szScratch), "cl_rumblescale %d", ( pSetting->data.nData != 0 ) ? 1 : 0 );
  1265. Cbuf_AddText( szScratch );
  1266. // Execute all commands we've queued up
  1267. Cbuf_Execute();
  1268. #endif // _X360
  1269. return true;
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. // Purpose: Read our configuration from the 360, filling in defaults on our first run
  1273. //-----------------------------------------------------------------------------
  1274. void Host_ReadConfiguration_360( void )
  1275. {
  1276. #ifdef _X360
  1277. // Exec our defaults on the first pass
  1278. if ( g_bConfigCfgExecuted == false )
  1279. {
  1280. // First, we exec our default configuration for the 360
  1281. Cbuf_AddText( "exec config.360.cfg game\n" );
  1282. Cbuf_Execute();
  1283. }
  1284. // Can't do any more in this function if we don't have a valid user id
  1285. if ( XBX_GetPrimaryUserId() == INVALID_USER_ID )
  1286. return;
  1287. // Build the config name we're looking for
  1288. char strFileName[MAX_PATH];
  1289. Q_snprintf( strFileName, sizeof(strFileName), "cfg:/%s_config.cfg", GetCurrentMod() );
  1290. bool bStorageDeviceValid = ( XBX_GetStorageDeviceId() != XBX_INVALID_STORAGE_ID && XBX_GetStorageDeviceId() != XBX_STORAGE_DECLINED );
  1291. bool bSaveConfig = false;
  1292. // Call through normal API function once the content container is opened
  1293. if ( CommandLine()->CheckParm( "-forcexboxreconfig" ) || bStorageDeviceValid == false || g_pFileSystem->FileExists( strFileName ) == false )
  1294. {
  1295. // If we've already done this in this session, never do it again (we don't want to stomp their settings under any circumstances)
  1296. if ( g_bConfigCfgExecuted == false )
  1297. {
  1298. // Get and set all our default setting we care about from the Xbox
  1299. XBX_SetProfileDefaultSettings();
  1300. }
  1301. // Save out what we have
  1302. bSaveConfig = true;
  1303. }
  1304. else
  1305. {
  1306. // Otherwise, exec the user settings stored on the 360
  1307. char szCommand[MAX_PATH];
  1308. Q_snprintf( szCommand, sizeof( szCommand ), "exec %s_config.cfg x360\n", GetCurrentMod() );
  1309. Cbuf_AddText( szCommand );
  1310. // Exec the video config as well
  1311. Q_snprintf( szCommand, sizeof( szCommand ), "exec video_config.cfg x360\n", GetCurrentMod() );
  1312. Cbuf_AddText( szCommand );
  1313. Cbuf_Execute();
  1314. }
  1315. // Mark that we've loaded a config and can now save it
  1316. g_bConfigCfgExecuted = true;
  1317. if ( bSaveConfig )
  1318. {
  1319. // An ugly hack, but we can probably save this safely
  1320. bool saveinit = host_initialized;
  1321. host_initialized = true;
  1322. Host_WriteConfiguration_360();
  1323. host_initialized = saveinit;
  1324. }
  1325. #endif // _X360
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. // Purpose:
  1329. // Input : false -
  1330. //-----------------------------------------------------------------------------
  1331. void Host_ReadConfiguration()
  1332. {
  1333. if ( sv.IsDedicated() )
  1334. return;
  1335. // Rebind keys and set cvars
  1336. if ( !g_pFileSystem )
  1337. {
  1338. Sys_Error( "Host_ReadConfiguration: g_pFileSystem == NULL\n" );
  1339. }
  1340. // Handle the 360 case
  1341. if ( IsX360() )
  1342. {
  1343. Host_ReadConfiguration_360();
  1344. return;
  1345. }
  1346. bool saveconfig = false;
  1347. ISteamRemoteStorage *pRemoteStorage = SteamClient()?(ISteamRemoteStorage *)SteamClient()->GetISteamGenericInterface(
  1348. SteamAPI_GetHSteamUser(), SteamAPI_GetHSteamPipe(), STEAMREMOTESTORAGE_INTERFACE_VERSION ):NULL;
  1349. if ( pRemoteStorage )
  1350. {
  1351. // if cloud settings is default but remote storage does not exist yet, set it to sync all because this is the first
  1352. // computer the game is run on--default to copying everything to the cloud
  1353. if ( !pRemoteStorage->FileExists( "cfg/config.cfg" ) )
  1354. {
  1355. DevMsg( "[Cloud]: Default setting with remote data non-existent, sync all\n" );
  1356. cl_cloud_settings.SetValue( STEAMREMOTESTORAGE_CLOUD_ON );
  1357. }
  1358. if ( cl_cloud_settings.GetInt() == STEAMREMOTESTORAGE_CLOUD_ON )
  1359. {
  1360. // config files are run through the exec command which got pretty complicated with all the splitscreen
  1361. // stuff. Steam UFS doens't support split screen well (2 users ?)
  1362. GetFileFromRemoteStorage( pRemoteStorage, "cfg/config.cfg", "cfg/config.cfg" );
  1363. }
  1364. }
  1365. if ( g_pFileSystem->FileExists( "//mod/cfg/config.cfg" ) )
  1366. {
  1367. Cbuf_AddText( "exec config.cfg\n" );
  1368. }
  1369. else
  1370. {
  1371. Cbuf_AddText( "exec config_default.cfg\n" );
  1372. saveconfig = true;
  1373. }
  1374. Cbuf_Execute();
  1375. if ( pRemoteStorage )
  1376. {
  1377. if ( cl_cloud_settings.GetInt() == STEAMREMOTESTORAGE_CLOUD_ON )
  1378. {
  1379. // get logo .VTF file
  1380. Q_SetExtension( g_szDefaultLogoFileName, ".vtf", sizeof(g_szDefaultLogoFileName) );
  1381. GetFileFromRemoteStorage( pRemoteStorage, g_szDefaultLogoFileName, g_szDefaultLogoFileName );
  1382. cl_logofile.SetValue( g_szDefaultLogoFileName );
  1383. // get logo .VMT file
  1384. Q_SetExtension( g_szDefaultLogoFileName, ".vmt", sizeof(g_szDefaultLogoFileName) );
  1385. GetFileFromRemoteStorage( pRemoteStorage, g_szDefaultLogoFileName, g_szDefaultLogoFileName );
  1386. }
  1387. }
  1388. // check to see if we actually set any keys, if not, load defaults from kb_def.lst
  1389. // so we at least have basics setup.
  1390. int nNumBinds = Key_CountBindings();
  1391. if ( nNumBinds == 0 )
  1392. {
  1393. UseDefaultBindings();
  1394. }
  1395. else
  1396. {
  1397. // Setup new bindings - if we ship an update that requires that every user has a key bound for
  1398. // X concommand, SetupNewBindings() will do its best to ensure that a key is bound. We assume
  1399. // that kb_def.lst includes any bindings that SetupNewBindings() might include in the case
  1400. // that nNumBinds == 0 above.
  1401. SetupNewBindings();
  1402. }
  1403. Key_SetBinding( KEY_ESCAPE, "cancelselect" );
  1404. // Make sure that something is always bound to console
  1405. if (NULL == Key_NameForBinding("toggleconsole"))
  1406. {
  1407. // If nothing is bound to it then bind it to '
  1408. Key_SetBinding( KEY_BACKQUOTE, "toggleconsole" );
  1409. }
  1410. SetupDefaultAskConnectAcceptKey();
  1411. g_bConfigCfgExecuted = true;
  1412. if ( saveconfig )
  1413. {
  1414. // An ugly hack, but we can probably save this safely
  1415. bool saveinit = host_initialized;
  1416. host_initialized = true;
  1417. Host_WriteConfiguration();
  1418. host_initialized = saveinit;
  1419. }
  1420. }
  1421. CON_COMMAND( host_writeconfig, "Store current settings to config.cfg (or specified .cfg file)." )
  1422. {
  1423. if ( args.ArgC() > 3 )
  1424. {
  1425. ConMsg( "Usage: writeconfig <filename.cfg> [full]\n" );
  1426. ConMsg( "<filename.cfg> is required, optionally specify \"full\" to write out all archived convars.\n" );
  1427. ConMsg( "By default, only non-default values are written out.\n" );
  1428. return;
  1429. }
  1430. if ( args.ArgC() >= 2 )
  1431. {
  1432. bool bWriteAll = ( args.ArgC() == 3 && V_stricmp( args[ 2 ], "full" ) == 0 );
  1433. char const *filename = args[ 1 ];
  1434. if ( !filename || !filename[ 0 ] )
  1435. {
  1436. return;
  1437. }
  1438. char outfile[ MAX_QPATH ];
  1439. // Strip path and extension from filename
  1440. Q_FileBase( filename, outfile, sizeof( outfile ) );
  1441. Host_WriteConfiguration( va( "%s.cfg", outfile ), bWriteAll );
  1442. if ( !bWriteAll )
  1443. ConMsg( "Wrote partial config file \"%s\" out, to write full file use host_writeconfig \"%s\" full\n", outfile, outfile );
  1444. }
  1445. else
  1446. {
  1447. Host_WriteConfiguration( NULL, true );
  1448. }
  1449. }
  1450. #endif
  1451. //-----------------------------------------------------------------------------
  1452. // Purpose: Does a quick parse of the config.cfg to read cvars that
  1453. // need to be read before any games systems are initialized
  1454. // assumes only cvars and filesystem are initialized
  1455. //-----------------------------------------------------------------------------
  1456. void Host_ReadPreStartupConfiguration()
  1457. {
  1458. FileHandle_t f = NULL;
  1459. if ( IsX360() )
  1460. {
  1461. // 360 config is less restrictive and can be anywhere in the game path
  1462. f = g_pFileSystem->Open( "//game/cfg/config.360.cfg", "rt" );
  1463. }
  1464. else
  1465. {
  1466. f = g_pFileSystem->Open( "//mod/cfg/config.cfg", "rt" );
  1467. }
  1468. if ( !f )
  1469. return;
  1470. // read file into memory
  1471. int size = g_pFileSystem->Size(f);
  1472. char *configBuffer = new char[ size + 1 ];
  1473. g_pFileSystem->Read( configBuffer, size, f );
  1474. configBuffer[size] = 0;
  1475. g_pFileSystem->Close( f );
  1476. // parse out file
  1477. static const char *s_PreStartupConfigConVars[] =
  1478. {
  1479. "sv_unlockedchapters", // needed to display the startup graphic while loading
  1480. "snd_legacy_surround", // needed to init the sound system
  1481. "gameui_xbox", // needed to initialize the correct UI
  1482. "save_in_memory" // needed to preread data from the correct location in UI
  1483. };
  1484. // loop through looking for all the cvars to apply
  1485. for (int i = 0; i < ARRAYSIZE(s_PreStartupConfigConVars); i++)
  1486. {
  1487. const char *search = Q_stristr(configBuffer, s_PreStartupConfigConVars[i]);
  1488. if (search)
  1489. {
  1490. // read over the token
  1491. search = COM_Parse(search);
  1492. // read the value
  1493. COM_Parse(search);
  1494. // apply the value
  1495. ConVar *var = (ConVar *)g_pCVar->FindVar( s_PreStartupConfigConVars[i] );
  1496. if ( var )
  1497. {
  1498. var->SetValue( com_token );
  1499. }
  1500. }
  1501. }
  1502. // free
  1503. delete [] configBuffer;
  1504. }
  1505. void Host_RecomputeSpeed_f( void )
  1506. {
  1507. ConMsg( "Recomputing clock speed...\n" );
  1508. CClockSpeedInit::Init();
  1509. ConMsg( "Clock speed: %.0f Mhz\n", CFastTimer::GetClockSpeed() / 1000000.0 );
  1510. }
  1511. static ConCommand recompute_speed( "recompute_speed", Host_RecomputeSpeed_f, "Recomputes clock speed (for debugging purposes).", FCVAR_CHEAT );
  1512. void DTI_Flush_f()
  1513. {
  1514. DTI_Flush();
  1515. ServerDTI_Flush();
  1516. }
  1517. static ConCommand dti_flush( "dti_flush", DTI_Flush_f, "Write out the datatable instrumentation files (you must run with -dti for this to work)." );
  1518. /*
  1519. ==================
  1520. Host_ShutdownServer
  1521. This only happens at the end of a game, not between levels
  1522. ==================
  1523. */
  1524. void Host_ShutdownServer( void )
  1525. {
  1526. if ( !sv.IsActive() )
  1527. return;
  1528. Host_AllowQueuedMaterialSystem( false );
  1529. // clear structures
  1530. #if !defined( SWDS )
  1531. g_pShadowMgr->LevelShutdown();
  1532. #endif
  1533. StaticPropMgr()->LevelShutdown();
  1534. Host_FreeStateAndWorld( true );
  1535. sv.Shutdown();// sv.Shutdown() references some heap memory, so run it before Host_FreeToLowMark()
  1536. Host_FreeToLowMark( true );
  1537. IGameEvent *event = g_GameEventManager.CreateEvent( "server_shutdown" );
  1538. if ( event )
  1539. {
  1540. event->SetString( "reason", "restart" );
  1541. g_GameEventManager.FireEvent( event );
  1542. }
  1543. g_Log.Close();
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. // Purpose:
  1547. // Input : time -
  1548. // Output : bool
  1549. //-----------------------------------------------------------------------------
  1550. void Host_AccumulateTime( float dt )
  1551. {
  1552. // Accumulate some time
  1553. realtime += dt;
  1554. bool bUseNormalTickTime = true;
  1555. #if !defined(SWDS)
  1556. if ( demoplayer->IsPlayingTimeDemo() )
  1557. bUseNormalTickTime = false;
  1558. #endif
  1559. if ( g_bDedicatedServerBenchmarkMode )
  1560. bUseNormalTickTime = false;
  1561. if ( bUseNormalTickTime )
  1562. {
  1563. host_frametime = dt;
  1564. }
  1565. else
  1566. {
  1567. // Used to help increase reproducibility of timedemos
  1568. host_frametime = host_state.interval_per_tick;
  1569. }
  1570. #if 1
  1571. if ( host_framerate.GetFloat() > 0
  1572. #if !defined(SWDS)
  1573. && ( CanCheat() || demoplayer->IsPlayingBack() )
  1574. #endif
  1575. )
  1576. {
  1577. float fps = host_framerate.GetFloat();
  1578. if ( fps > 1 )
  1579. {
  1580. fps = 1.0f/fps;
  1581. }
  1582. host_frametime = fps;
  1583. #if !defined(SWDS) && defined( REPLAY_ENABLED )
  1584. extern IDemoPlayer *g_pReplayDemoPlayer;
  1585. if ( demoplayer->IsPlayingBack() && demoplayer == g_pReplayDemoPlayer )
  1586. {
  1587. // adjust time scale if playing back demo
  1588. host_frametime *= demoplayer->GetPlaybackTimeScale();
  1589. }
  1590. #endif
  1591. host_frametime_unbounded = host_frametime;
  1592. }
  1593. else if (host_timescale.GetFloat() > 0
  1594. #if !defined(SWDS)
  1595. && ( CanCheat() || demoplayer->IsPlayingBack() )
  1596. #endif
  1597. )
  1598. {
  1599. float fullscale = host_timescale.GetFloat();
  1600. #if !defined(SWDS)
  1601. if ( demoplayer->IsPlayingBack() )
  1602. {
  1603. // adjust time scale if playing back demo
  1604. fullscale *= demoplayer->GetPlaybackTimeScale();
  1605. }
  1606. #endif
  1607. host_frametime *= fullscale;
  1608. host_frametime_unbounded = host_frametime;
  1609. #ifndef NO_TOOLFRAMEWORK
  1610. if ( CommandLine()->CheckParm( "-tools" ) == NULL )
  1611. {
  1612. #endif
  1613. host_frametime = min( (double)host_frametime, MAX_FRAMETIME * fullscale);
  1614. #ifndef NO_TOOLFRAMEWORK
  1615. }
  1616. #endif
  1617. }
  1618. else
  1619. #ifndef NO_TOOLFRAMEWORK
  1620. if ( CommandLine()->CheckParm( "-tools" ) != NULL )
  1621. {
  1622. host_frametime_unbounded = host_frametime;
  1623. }
  1624. else
  1625. #endif // !NO_TOOLFRAMEWORK
  1626. { // don't allow really long or short frames
  1627. host_frametime_unbounded = host_frametime;
  1628. host_frametime = min( (double)host_frametime, MAX_FRAMETIME );
  1629. host_frametime = max( (double)host_frametime, MIN_FRAMETIME );
  1630. }
  1631. #endif
  1632. // Adjust the client clock very slightly to keep it in line with the server clock.
  1633. float adj = cl.GetClockDriftMgr().AdjustFrameTime( host_frametime ) - host_frametime;
  1634. host_frametime += adj;
  1635. host_frametime_unbounded += adj;
  1636. if ( g_pSoundServices ) // not present on linux server
  1637. g_pSoundServices->SetSoundFrametime(dt, host_frametime);
  1638. }
  1639. #define FPS_AVG_FRAC 0.9f
  1640. float g_fFramesPerSecond = 0.0f;
  1641. /*
  1642. ==================
  1643. Host_PostFrameRate
  1644. ==================
  1645. */
  1646. void Host_PostFrameRate( float frameTime )
  1647. {
  1648. frameTime = clamp( frameTime, 0.0001f, 1.0f );
  1649. float fps = 1.0f / frameTime;
  1650. g_fFramesPerSecond = g_fFramesPerSecond * FPS_AVG_FRAC + ( 1.0f - FPS_AVG_FRAC ) * fps;
  1651. }
  1652. /*
  1653. ==================
  1654. Host_GetHostInfo
  1655. ==================
  1656. */
  1657. void Host_GetHostInfo(float *fps, int *nActive, int *nMaxPlayers, char *pszMap, int maxlen )
  1658. {
  1659. // Count clients, report
  1660. int clients = sv.GetNumClients();
  1661. *fps = g_fFramesPerSecond;
  1662. *nActive = clients;
  1663. if (pszMap)
  1664. {
  1665. if (sv.m_szMapname && sv.m_szMapname[0])
  1666. Q_strncpy(pszMap, sv.m_szMapname, maxlen );
  1667. else
  1668. pszMap[0] = '\0';
  1669. }
  1670. *nMaxPlayers = sv.GetMaxClients();
  1671. }
  1672. static bool AppearsNumeric( char const *in )
  1673. {
  1674. char const *p = in;
  1675. int special[ 3 ];
  1676. Q_memset( special, 0, sizeof( special ) );
  1677. for ( ; *p; p++ )
  1678. {
  1679. if ( *p == '-' )
  1680. {
  1681. special[0]++;
  1682. continue;
  1683. }
  1684. if ( *p == '+' )
  1685. {
  1686. special[1]++;
  1687. continue;
  1688. }
  1689. if ( *p >= '0' && *p <= '9' )
  1690. {
  1691. continue;
  1692. }
  1693. if ( *p == '.' )
  1694. {
  1695. special[2]++;
  1696. continue;
  1697. }
  1698. return false;
  1699. }
  1700. // Can't have multiple +, -, or decimals
  1701. for ( int i = 0; i < 3; i++ )
  1702. {
  1703. if ( special[ i ] > 1 )
  1704. return false;
  1705. }
  1706. // can't be + and - at same time
  1707. if ( special[ 0 ] && special[ 1 ] )
  1708. return false;
  1709. return true;
  1710. }
  1711. //-----------------------------------------------------------------------------
  1712. // Purpose: If the value is numeric, remove unnecessary trailing zeros
  1713. // Input : *invalue -
  1714. // Output : char const
  1715. //-----------------------------------------------------------------------------
  1716. char const * Host_CleanupConVarStringValue( char const *invalue )
  1717. {
  1718. static char clean[ 256 ];
  1719. Q_snprintf( clean, sizeof( clean ), "%s", invalue );
  1720. // Don't mess with empty string
  1721. // Otherwise, if it appears numeric and has a decimal, try to strip all zeroes after decimal
  1722. if ( Q_strlen( clean ) >= 1 && AppearsNumeric( clean ) && Q_strstr( clean, "." ) )
  1723. {
  1724. char *end = clean + strlen( clean ) - 1;
  1725. while ( *end && end >= clean )
  1726. {
  1727. // Removing trailing zeros
  1728. if ( *end != '0' )
  1729. {
  1730. // Remove decimal, zoo
  1731. if ( *end == '.' )
  1732. {
  1733. if ( end == clean )
  1734. {
  1735. *end = '0';
  1736. }
  1737. else
  1738. {
  1739. *end = 0;
  1740. }
  1741. }
  1742. break;
  1743. }
  1744. *end-- = 0;
  1745. }
  1746. }
  1747. return clean;
  1748. }
  1749. int Host_CountVariablesWithFlags( int flags, bool nonDefault )
  1750. {
  1751. int i = 0;
  1752. const ConCommandBase *var;
  1753. for ( var = g_pCVar->GetCommands() ; var ; var=var->GetNext() )
  1754. {
  1755. if ( var->IsCommand() )
  1756. continue;
  1757. const ConVar *pCvar = ( const ConVar * )var;
  1758. if ( !pCvar->IsFlagSet( flags ) )
  1759. continue;
  1760. // It's == to the default value, don't count
  1761. if ( nonDefault && !Q_strcasecmp( pCvar->GetDefault(), pCvar->GetString() ) )
  1762. continue;
  1763. i++;
  1764. }
  1765. return i;
  1766. }
  1767. //-----------------------------------------------------------------------------
  1768. // Purpose:
  1769. // Input : msg -
  1770. //-----------------------------------------------------------------------------
  1771. void Host_BuildConVarUpdateMessage( NET_SetConVar *cvarMsg, int flags, bool nonDefault )
  1772. {
  1773. int count = Host_CountVariablesWithFlags( flags, nonDefault );
  1774. // Nothing to send
  1775. if ( count <= 0 )
  1776. return;
  1777. // Too many to send, error out and have mod author get a clue.
  1778. if ( count > 255 )
  1779. {
  1780. Sys_Error( "Engine only supports 255 ConVars marked %i\n", flags );
  1781. return;
  1782. }
  1783. const ConCommandBase *var;
  1784. for ( var = g_pCVar->GetCommands() ; var ; var=var->GetNext() )
  1785. {
  1786. if ( var->IsCommand() )
  1787. continue;
  1788. const ConVar *pCvar = ( const ConVar * )var;
  1789. if ( !pCvar->IsFlagSet( flags ) )
  1790. continue;
  1791. // It's == to the default value, don't count
  1792. if ( nonDefault && !Q_strcasecmp( pCvar->GetDefault(), pCvar->GetString() ) )
  1793. continue;
  1794. NET_SetConVar::cvar_t acvar;
  1795. Q_strncpy( acvar.name, pCvar->GetName(), MAX_OSPATH );
  1796. Q_strncpy( acvar.value, Host_CleanupConVarStringValue( pCvar->GetString() ), MAX_OSPATH );
  1797. cvarMsg->m_ConVars.AddToTail( acvar );
  1798. }
  1799. // Make sure this count matches original one!!!
  1800. Assert( cvarMsg->m_ConVars.Count() == count );
  1801. }
  1802. #if !defined( SWDS )
  1803. // FIXME: move me somewhere more appropriate
  1804. void CL_SendVoicePacket(bool bFinal)
  1805. {
  1806. #if !defined( NO_VOICE )
  1807. if ( !Voice_IsRecording() )
  1808. return;
  1809. CLC_VoiceData voiceMsg;
  1810. // Get whatever compressed data there is and and send it.
  1811. char uchVoiceData[2048];
  1812. voiceMsg.m_DataOut.StartWriting( uchVoiceData, sizeof(uchVoiceData) );
  1813. voiceMsg.m_nLength = Voice_GetCompressedData( uchVoiceData, sizeof(uchVoiceData), bFinal ) * 8;
  1814. if( !voiceMsg.m_nLength )
  1815. return;
  1816. voiceMsg.m_DataOut.SeekToBit( voiceMsg.m_nLength ); // set correct writing position
  1817. if ( cl.IsActive() )
  1818. {
  1819. cl.m_NetChannel->SendNetMsg( voiceMsg );
  1820. }
  1821. #endif
  1822. }
  1823. #if defined ( _X360 )
  1824. void CL_ProcessXboxVoiceData()
  1825. {
  1826. if ( Audio_GetXVoice() == NULL )
  1827. return;
  1828. if ( Audio_GetXVoice()->VoiceUpdateData() == true )
  1829. {
  1830. if ( cl.IsActive() )
  1831. {
  1832. Audio_GetXVoice()->VoiceSendData( cl.m_NetChannel );
  1833. }
  1834. }
  1835. }
  1836. #endif
  1837. void CL_ProcessVoiceData()
  1838. {
  1839. VPROF_BUDGET( "CL_ProcessVoiceData", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1840. #if !defined( NO_VOICE )
  1841. Voice_Idle(host_frametime);
  1842. CL_SendVoicePacket(false);
  1843. #endif
  1844. #if defined ( _X360 )
  1845. CL_ProcessXboxVoiceData();
  1846. #endif
  1847. }
  1848. #endif
  1849. /*
  1850. =====================
  1851. Host_UpdateScreen
  1852. Refresh the screen
  1853. =====================
  1854. */
  1855. void Host_UpdateScreen( void )
  1856. {
  1857. #ifndef SWDS
  1858. #ifdef _DEBUG
  1859. if( r_ForceRestore.GetInt() )
  1860. {
  1861. ForceMatSysRestore();
  1862. r_ForceRestore.SetValue(0);
  1863. }
  1864. #endif // _DEBUG
  1865. // Refresh the screen
  1866. SCR_UpdateScreen ();
  1867. #endif
  1868. }
  1869. /*
  1870. ====================
  1871. Host_UpdateSounds
  1872. Update sound subsystem and cd audio
  1873. ====================
  1874. */
  1875. void Host_UpdateSounds( void )
  1876. {
  1877. #if !defined( SWDS )
  1878. // update audio
  1879. if ( cl.IsActive() )
  1880. {
  1881. S_Update( &s_AudioState );
  1882. }
  1883. else
  1884. {
  1885. S_Update( NULL );
  1886. }
  1887. #endif
  1888. }
  1889. /*
  1890. ==============================
  1891. Host_Speeds
  1892. ==============================
  1893. */
  1894. void CFrameTimer::ResetDeltas()
  1895. {
  1896. for ( int i = 0; i < NUM_FRAME_SEGMENTS; i++ )
  1897. {
  1898. deltas[ i ] = 0.0f;
  1899. }
  1900. }
  1901. void CFrameTimer::MarkFrame()
  1902. {
  1903. double frameTime;
  1904. double fps;
  1905. // ConDMsg("%f %f %f\n", time1, time2, time3 );
  1906. float fs_input = (deltas[FRAME_SEGMENT_INPUT])*1000.0;
  1907. float fs_client = (deltas[FRAME_SEGMENT_CLIENT])*1000.0;
  1908. float fs_server = (deltas[FRAME_SEGMENT_SERVER])*1000.0;
  1909. float fs_render = (deltas[FRAME_SEGMENT_RENDER])*1000.0;
  1910. float fs_sound = (deltas[FRAME_SEGMENT_SOUND])*1000.0;
  1911. float fs_cldll = (deltas[FRAME_SEGMENT_CLDLL])*1000.0;
  1912. float fs_exec = (deltas[FRAME_SEGMENT_CMD_EXECUTE])*1000.0;
  1913. ResetDeltas();
  1914. frameTime = host_frametime;
  1915. //frameTime /= 1000.0;
  1916. if ( frameTime < 0.0001 )
  1917. {
  1918. fps = 999.0;
  1919. }
  1920. else
  1921. {
  1922. fps = 1.0 / frameTime;
  1923. }
  1924. if (host_speeds.GetInt())
  1925. {
  1926. int ent_count = 0;
  1927. int i;
  1928. static int last_host_tickcount;
  1929. int ticks = host_tickcount - last_host_tickcount;
  1930. last_host_tickcount = host_tickcount;
  1931. // count used entities
  1932. for (i=0 ; i<sv.num_edicts ; i++)
  1933. {
  1934. if (!sv.edicts[i].IsFree())
  1935. ent_count++;
  1936. }
  1937. char sz[ 256 ];
  1938. Q_snprintf( sz, sizeof( sz ),
  1939. "%3i fps -- inp(%.2f) sv(%.2f) cl(%.2f) render(%.2f) snd(%.2f) cl_dll(%.2f) exec(%.2f) ents(%d) ticks(%d)",
  1940. (int)fps,
  1941. fs_input,
  1942. fs_server,
  1943. fs_client,
  1944. fs_render,
  1945. fs_sound,
  1946. fs_cldll,
  1947. fs_exec,
  1948. ent_count,
  1949. ticks );
  1950. #ifndef SWDS
  1951. if ( host_speeds.GetInt() >= 2 )
  1952. {
  1953. Con_NPrintf ( 0, sz );
  1954. }
  1955. else
  1956. {
  1957. ConDMsg ( "%s\n", sz );
  1958. }
  1959. #endif
  1960. }
  1961. }
  1962. #define FRAME_TIME_FILTER_TIME 0.5f
  1963. void CFrameTimer::ComputeFrameVariability()
  1964. {
  1965. m_pFrameTimeHistory[m_nFrameTimeHistoryIndex] = frametime;
  1966. if ( ++m_nFrameTimeHistoryIndex >= FRAME_HISTORY_COUNT )
  1967. {
  1968. m_nFrameTimeHistoryIndex = 0;
  1969. }
  1970. // Compute a low-pass filter of the frame time over the last half-second
  1971. // Count the number of samples that live within the last half-second
  1972. int i = m_nFrameTimeHistoryIndex;
  1973. int nMaxSamples = 0;
  1974. float flTotalTime = 0.0f;
  1975. while( (nMaxSamples < FRAME_HISTORY_COUNT) && (flTotalTime <= FRAME_TIME_FILTER_TIME) )
  1976. {
  1977. if ( --i < 0 )
  1978. {
  1979. i = FRAME_HISTORY_COUNT - 1;
  1980. }
  1981. if ( m_pFrameTimeHistory[i] == 0.0f )
  1982. break;
  1983. flTotalTime += m_pFrameTimeHistory[i];
  1984. ++nMaxSamples;
  1985. }
  1986. if ( nMaxSamples == 0 )
  1987. {
  1988. m_flFPSVariability = 0.0f;
  1989. m_flFPSStdDeviationSeconds = 0.0f;
  1990. return;
  1991. }
  1992. float flExponent = -2.0f / (int)nMaxSamples;
  1993. i = m_nFrameTimeHistoryIndex;
  1994. float flAverageTime = 0.0f;
  1995. float flExpCurveArea = 0.0f;
  1996. int n = 0;
  1997. while( n < nMaxSamples )
  1998. {
  1999. if ( --i < 0 )
  2000. {
  2001. i = FRAME_HISTORY_COUNT - 1;
  2002. }
  2003. flExpCurveArea += exp( flExponent * n );
  2004. flAverageTime += m_pFrameTimeHistory[i] * exp( flExponent * n );
  2005. ++n;
  2006. }
  2007. flAverageTime /= flExpCurveArea;
  2008. float flAveFPS = 0.0f;
  2009. if ( flAverageTime != 0.0f )
  2010. {
  2011. flAveFPS = 1.0f / flAverageTime;
  2012. }
  2013. float flCurrentFPS = 0.0f;
  2014. if ( frametime != 0.0f )
  2015. {
  2016. flCurrentFPS = 1.0f / frametime;
  2017. }
  2018. // Now subtract out the current fps to get variability in FPS
  2019. m_flFPSVariability = fabs( flCurrentFPS - flAveFPS );
  2020. // Now compute variance/stddeviation
  2021. double sum = 0.0f;
  2022. int count =0;
  2023. for ( int j = 0; j < FRAME_HISTORY_COUNT; ++j )
  2024. {
  2025. if ( m_pFrameTimeHistory[ j ] == 0.0f )
  2026. continue;
  2027. double ft = min( (double)m_pFrameTimeHistory[ j ], 0.25 );
  2028. sum += ft;
  2029. ++count;
  2030. }
  2031. if ( count <= 1 )
  2032. {
  2033. return;
  2034. }
  2035. double avg = sum / (double)count;
  2036. double devSquared = 0.0f;
  2037. for ( int j = 0; j < FRAME_HISTORY_COUNT; ++j )
  2038. {
  2039. if ( m_pFrameTimeHistory[ j ] == 0.0f )
  2040. continue;
  2041. double ft = min( (double)m_pFrameTimeHistory[ j ], 0.25 );
  2042. double dt = ft - avg;
  2043. devSquared += ( dt * dt );
  2044. }
  2045. double variance = devSquared / (double)( count - 1 );
  2046. m_flFPSStdDeviationSeconds = sqrt( variance );
  2047. }
  2048. void Host_Speeds()
  2049. {
  2050. g_HostTimes.MarkFrame();
  2051. #if !defined(SWDS)
  2052. ToClientDemoPlayer( demoplayer )->MarkFrame( g_HostTimes.m_flFPSVariability );
  2053. #endif
  2054. }
  2055. //-----------------------------------------------------------------------------
  2056. // Purpose: When singlestep == 1, then you must set next == 1 to run to the
  2057. // next frame.
  2058. // Output : Returns true on success, false on failure.
  2059. //-----------------------------------------------------------------------------
  2060. bool Host_ShouldRun( void )
  2061. {
  2062. static int current_tick = -1;
  2063. // See if we are single stepping
  2064. if ( !singlestep.GetInt() )
  2065. {
  2066. return true;
  2067. }
  2068. // Did user set "next" to 1?
  2069. if ( cvarNext.GetInt() )
  2070. {
  2071. // Did we finally finish this frame ( Host_ShouldRun is called in 3 spots to pause
  2072. // three different things ).
  2073. if ( current_tick != (host_tickcount-1) )
  2074. {
  2075. // Okay, time to reset to halt execution again
  2076. cvarNext.SetValue( 0 );
  2077. return false;
  2078. }
  2079. // Otherwise, keep running this one frame since we are still finishing this frame
  2080. return true;
  2081. }
  2082. else
  2083. {
  2084. // Remember last frame without "next" being reset ( time is locked )
  2085. current_tick = host_tickcount;
  2086. // Time is locked
  2087. return false;
  2088. }
  2089. }
  2090. static ConVar mem_periodicdumps( "mem_periodicdumps", "0", 0, "Write periodic memstats dumps every n seconds." );
  2091. static double g_flLastPeriodicMemDump = -1.0f;
  2092. //-----------------------------------------------------------------------------
  2093. // Purpose:
  2094. //-----------------------------------------------------------------------------
  2095. static float g_TimeLastMemTest;
  2096. void Host_CheckDumpMemoryStats( void )
  2097. {
  2098. if ( mem_test_each_frame.GetBool() )
  2099. {
  2100. if ( !MemAlloc_CrtCheckMemory() )
  2101. {
  2102. DebuggerBreakIfDebugging();
  2103. Error( "Heap is corrupt\n" );
  2104. }
  2105. }
  2106. else if ( mem_test_every_n_seconds.GetInt() > 0 )
  2107. {
  2108. float now = Plat_FloatTime();
  2109. if ( now - g_TimeLastMemTest > mem_test_every_n_seconds.GetInt() )
  2110. {
  2111. g_TimeLastMemTest = now;
  2112. if ( !MemAlloc_CrtCheckMemory() )
  2113. {
  2114. DebuggerBreakIfDebugging();
  2115. Error( "Heap is corrupt\n" );
  2116. }
  2117. }
  2118. }
  2119. if ( mem_periodicdumps.GetFloat() > 0.0f )
  2120. {
  2121. double curtime = Plat_FloatTime();
  2122. if ( curtime - g_flLastPeriodicMemDump > mem_periodicdumps.GetFloat() )
  2123. {
  2124. const char *pTest = sv.GetMapName();
  2125. if ( !pTest || !pTest[0] )
  2126. {
  2127. // possibly at menu
  2128. pTest = "nomap";
  2129. }
  2130. char mapname[ 256 ];
  2131. Q_FileBase( pTest, mapname, sizeof( mapname ) );
  2132. #if defined( _MEMTEST )
  2133. MemAlloc_SetStatsExtraInfo( pTest, "" );
  2134. #endif
  2135. MemAlloc_DumpStatsFileBase( mapname );
  2136. g_flLastPeriodicMemDump = curtime;
  2137. }
  2138. }
  2139. #if defined(_WIN32)
  2140. if ( mem_dumpstats.GetInt() <= 0 )
  2141. return;
  2142. if ( mem_dumpstats.GetInt() == 1 )
  2143. mem_dumpstats.SetValue( 0 ); // reset cvar, dump stats only once
  2144. _CrtMemState state;
  2145. Q_memset( &state, 0, sizeof( state ) );
  2146. _CrtMemCheckpoint( &state );
  2147. unsigned int size = 0;
  2148. for ( int use = 0; use < _MAX_BLOCKS; use++)
  2149. {
  2150. size += state.lSizes[ use ];
  2151. }
  2152. Msg("MEMORY: Run-time Heap\n------------------------------------\n");
  2153. Msg( "\tHigh water %s\n", Q_pretifymem( state.lHighWaterCount,4 ) );
  2154. Msg( "\tCurrent mem %s\n", Q_pretifymem( size,4 ) );
  2155. Msg("------------------------------------\n");
  2156. int hunk = Hunk_MallocSize();
  2157. Msg("\tAllocated outside hunk: %s\n", Q_pretifymem( size - hunk ) );
  2158. #endif
  2159. }
  2160. //-----------------------------------------------------------------------------
  2161. // Purpose:
  2162. //-----------------------------------------------------------------------------
  2163. void _Host_SetGlobalTime()
  2164. {
  2165. // Server
  2166. g_ServerGlobalVariables.realtime = realtime;
  2167. g_ServerGlobalVariables.framecount = host_framecount;
  2168. g_ServerGlobalVariables.absoluteframetime = host_frametime;
  2169. g_ServerGlobalVariables.interval_per_tick = host_state.interval_per_tick;
  2170. g_ServerGlobalVariables.serverCount = Host_GetServerCount();
  2171. #ifndef SWDS
  2172. // Client
  2173. g_ClientGlobalVariables.realtime = realtime;
  2174. g_ClientGlobalVariables.framecount = host_framecount;
  2175. g_ClientGlobalVariables.absoluteframetime = host_frametime;
  2176. g_ClientGlobalVariables.interval_per_tick = host_state.interval_per_tick;
  2177. #endif
  2178. }
  2179. /*
  2180. ==================
  2181. _Host_RunFrame
  2182. Runs all active servers
  2183. ==================
  2184. */
  2185. void _Host_RunFrame_Input( float accumulated_extra_samples, bool bFinalTick )
  2186. {
  2187. VPROF_BUDGET( "_Host_RunFrame_Input", _T("Input") );
  2188. // Run a test script?
  2189. static bool bFirstFrame = true;
  2190. if ( bFirstFrame )
  2191. {
  2192. bFirstFrame = false;
  2193. const char *pScriptFilename = CommandLine()->ParmValue( "-testscript" );
  2194. if ( pScriptFilename )
  2195. {
  2196. if ( !GetTestScriptMgr()->StartTestScript( pScriptFilename ) )
  2197. {
  2198. Error( "StartTestScript( %s ) failed.", pScriptFilename );
  2199. }
  2200. }
  2201. }
  2202. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_INPUT );
  2203. #ifndef SWDS
  2204. // Client can process input
  2205. ClientDLL_ProcessInput( );
  2206. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2207. // process console commands
  2208. Cbuf_Execute ();
  2209. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2210. // Send any current movement commands to server and flush reliable buffer even if not moving yet.
  2211. CL_Move( accumulated_extra_samples, bFinalTick );
  2212. #endif
  2213. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_INPUT );
  2214. }
  2215. void _Host_RunFrame_Server( bool finaltick )
  2216. {
  2217. VPROF_BUDGET( "_Host_RunFrame_Server", VPROF_BUDGETGROUP_GAME );
  2218. VPROF_INCREMENT_COUNTER( "ticks", 1 );
  2219. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2220. // Run the Server frame ( read, run physics, respond )
  2221. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_SERVER );
  2222. SV_Frame ( finaltick );
  2223. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_SERVER );
  2224. // Look for connectionless rcon packets on dedicated servers
  2225. // SV_CheckRcom(); TODO
  2226. }
  2227. void _Host_RunFrame_Server_Async( int numticks )
  2228. {
  2229. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d", __FUNCTION__, numticks );
  2230. for ( int tick = 0; tick < numticks; tick++ )
  2231. {
  2232. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2233. g_ServerGlobalVariables.simTicksThisFrame = numticks - tick;
  2234. bool bFinalTick = ( tick == (numticks - 1) );
  2235. _Host_RunFrame_Server( bFinalTick );
  2236. }
  2237. }
  2238. void _Host_RunFrame_Client( bool framefinished )
  2239. {
  2240. #ifndef SWDS
  2241. VPROF( "_Host_RunFrame_Client" );
  2242. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d", __FUNCTION__, framefinished );
  2243. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CLIENT );
  2244. // Get any current state update from server, etc.
  2245. CL_ReadPackets( framefinished );
  2246. #if defined( VOICE_OVER_IP )
  2247. // Send any enqueued voice data to the server
  2248. CL_ProcessVoiceData();
  2249. #endif // VOICE_OVER_IP
  2250. cl.CheckUpdatingSteamResources();
  2251. cl.CheckFileCRCsWithServer();
  2252. // Resend connection request if needed.
  2253. cl.RunFrame();
  2254. if ( CL_IsHL2Demo() || CL_IsPortalDemo() ) // don't need sv.IsDedicated() because ded servers don't run this
  2255. {
  2256. void CL_DemoCheckGameUIRevealTime();
  2257. CL_DemoCheckGameUIRevealTime();
  2258. }
  2259. Steam3Client().RunFrame();
  2260. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CLIENT );
  2261. // This takes 1 usec, so it's pretty cheap...
  2262. CL_SetPagedPoolInfo();
  2263. #endif
  2264. }
  2265. //-----------------------------------------------------------------------------
  2266. // Purpose: Used to set limits on certain convars in multiplayer/sv_cheats mode.
  2267. // Returns true if it was called recursively and it early-outed.
  2268. //-----------------------------------------------------------------------------
  2269. bool CheckVarRange_Generic( ConVar *pVar, int minVal, int maxVal )
  2270. {
  2271. if ( !CanCheat() && !Host_IsSinglePlayerGame() )
  2272. {
  2273. int clampedValue = clamp( pVar->GetInt(), minVal, maxVal );
  2274. if ( clampedValue != pVar->GetInt() )
  2275. {
  2276. Warning( "sv_cheats=0 prevented changing %s outside of the range [%d,%d] (was %d).\n", pVar->GetName(), minVal, maxVal, pVar->GetInt() );
  2277. pVar->SetValue( clampedValue );
  2278. }
  2279. }
  2280. return false;
  2281. }
  2282. void CheckSpecialCheatVars()
  2283. {
  2284. static ConVar *mat_picmip = NULL;
  2285. if ( !mat_picmip )
  2286. mat_picmip = g_pCVar->FindVar( "mat_picmip" );
  2287. // In multiplayer, don't allow them to set mat_picmip > 2.
  2288. if ( mat_picmip )
  2289. CheckVarRange_Generic( mat_picmip, -1, 2 );
  2290. CheckVarRange_r_rootlod();
  2291. CheckVarRange_r_lod();
  2292. HandleServerAllowColorCorrection();
  2293. }
  2294. void _Host_RunFrame_Render()
  2295. {
  2296. #ifndef SWDS
  2297. VPROF( "_Host_RunFrame_Render" );
  2298. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "_Host_RunFrame_Render" );
  2299. CheckSpecialCheatVars();
  2300. int nOrgNoRendering = mat_norendering.GetInt();
  2301. if ( cl_takesnapshot )
  2302. {
  2303. // turn off no-rendering mode, if taking screenshot
  2304. mat_norendering.SetValue( 0 );
  2305. }
  2306. // update video if not running in background
  2307. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_RENDER );
  2308. CL_LatchInterpolationAmount();
  2309. {
  2310. VPROF( "_Host_RunFrame_Render - UpdateScreen" );
  2311. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "_Host_RunFrame_Render - UpdateScreen" );
  2312. Host_UpdateScreen();
  2313. }
  2314. {
  2315. VPROF( "_Host_RunFrame_Render - CL_DecayLights" );
  2316. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "_Host_RunFrame_Render - CL_DecayLights" );
  2317. CL_DecayLights ();
  2318. }
  2319. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_RENDER );
  2320. saverestore->OnFrameRendered();
  2321. #ifdef USE_SDL
  2322. if ( g_pLauncherMgr )
  2323. {
  2324. g_pLauncherMgr->OnFrameRendered();
  2325. }
  2326. #endif
  2327. mat_norendering.SetValue( nOrgNoRendering );
  2328. #endif
  2329. }
  2330. void CL_FindInterpolatedAddAngle( float t, float& frac, AddAngle **prev, AddAngle **next )
  2331. {
  2332. int c = cl.addangle.Count();
  2333. *prev = NULL;
  2334. *next = NULL;
  2335. AddAngle *pentry = NULL;
  2336. for ( int i = 0; i < c; i++ )
  2337. {
  2338. AddAngle *entry = &cl.addangle[ i ];
  2339. *next = entry;
  2340. // Time is earlier
  2341. if ( t < entry->starttime )
  2342. {
  2343. if ( i == 0 )
  2344. {
  2345. *prev = *next;
  2346. frac = 0.0f;
  2347. return;
  2348. }
  2349. // Avoid div by zero
  2350. if ( entry->starttime == pentry->starttime )
  2351. {
  2352. frac = 0.0f;
  2353. return;
  2354. }
  2355. // Time spans the two entries
  2356. frac = ( t - pentry->starttime ) / ( entry->starttime - pentry->starttime );
  2357. frac = clamp( frac, 0.0f, 1.0f );
  2358. return;
  2359. }
  2360. *prev = *next;
  2361. pentry = entry;
  2362. }
  2363. }
  2364. void CL_DiscardOldAddAngleEntries( float t )
  2365. {
  2366. float killtime = t - host_state.interval_per_tick - 0.1f;
  2367. for ( int i = 0; i < cl.addangle.Count(); i++ )
  2368. {
  2369. AddAngle *p = &cl.addangle[ i ];
  2370. if ( p->starttime <= killtime )
  2371. {
  2372. cl.addangle.Remove( i );
  2373. --i;
  2374. }
  2375. }
  2376. // It's safe to reset the master counter once all the entries decay
  2377. if ( cl.addangle.Count() == 0 )
  2378. {
  2379. cl.prevaddangletotal = cl.addangletotal = 0.0f;
  2380. }
  2381. }
  2382. #ifndef SWDS
  2383. void CL_ApplyAddAngle()
  2384. {
  2385. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2386. float curtime = cl.GetTime() - host_state.interval_per_tick;
  2387. AddAngle *prev = NULL, *next = NULL;
  2388. float frac = 0.0f;
  2389. float addangletotal = 0.0f;
  2390. CL_FindInterpolatedAddAngle( curtime, frac, &prev, &next );
  2391. if ( prev && next )
  2392. {
  2393. addangletotal = prev->total + frac * ( next->total - prev->total );
  2394. }
  2395. else
  2396. {
  2397. addangletotal = cl.prevaddangletotal;
  2398. }
  2399. float amove = addangletotal - cl.prevaddangletotal;
  2400. // Update view angles
  2401. cl.viewangles[ 1 ] += amove;
  2402. // Update client .dll view of angles
  2403. g_pClientSidePrediction->SetLocalViewAngles( cl.viewangles );
  2404. // Remember last total
  2405. cl.prevaddangletotal = addangletotal;
  2406. CL_DiscardOldAddAngleEntries( curtime );
  2407. }
  2408. #endif
  2409. void _Host_RunFrame_Sound()
  2410. {
  2411. #ifndef SWDS
  2412. VPROF_BUDGET( "_Host_RunFrame_Sound", VPROF_BUDGETGROUP_OTHER_SOUND );
  2413. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_SOUND );
  2414. Host_UpdateSounds();
  2415. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_SOUND );
  2416. #endif
  2417. }
  2418. float Host_GetSoundDuration( const char *pSample )
  2419. {
  2420. #ifndef SWDS
  2421. if (!sv.IsDedicated())
  2422. {
  2423. extern float SV_GetSoundDuration(const char *pSample);
  2424. extern float AudioSource_GetSoundDuration(CSfxTable *pSfx);
  2425. int index = cl.LookupSoundIndex(pSample);
  2426. if (index >= 0)
  2427. return AudioSource_GetSoundDuration(cl.GetSound(index));
  2428. return SV_GetSoundDuration(pSample);
  2429. }
  2430. #endif
  2431. return 0.0f;
  2432. }
  2433. CON_COMMAND( host_runofftime, "Run off some time without rendering/updating sounds\n" )
  2434. {
  2435. if ( args.ArgC() != 2 )
  2436. {
  2437. ConMsg( "Usage: host_runofftime <seconds>\n" );
  2438. return;
  2439. }
  2440. if ( !sv.IsActive() )
  2441. {
  2442. ConMsg( "host_ruofftime: must be running a server\n" );
  2443. return;
  2444. }
  2445. if ( sv.IsMultiplayer() )
  2446. {
  2447. ConMsg( "host_ruofftime: only valid in single player\n" );
  2448. return;
  2449. }
  2450. float advanceTime = atof( args[1] );
  2451. if ( advanceTime <= 0.0f )
  2452. return;
  2453. // 15 minutes is a _long_ time!!!
  2454. if ( advanceTime > 15.0f * 60.0f )
  2455. {
  2456. ConMsg( "host_runofftime would run off %.2f minutes!!! ignoring\n",
  2457. advanceTime / 60.0f );
  2458. return;
  2459. }
  2460. ConMsg( "Skipping ahead for %f seconds\n", advanceTime );
  2461. SCR_UpdateScreen();
  2462. SCR_UpdateScreen ();
  2463. }
  2464. #if !defined( _X360 )
  2465. S_API int SteamGameServer_GetIPCCallCount();
  2466. #else
  2467. S_API int SteamGameServer_GetIPCCallCount() { return 0; }
  2468. #endif
  2469. void Host_ShowIPCCallCount()
  2470. {
  2471. // If set to 0 then get out.
  2472. if ( host_ShowIPCCallCount.GetInt() == 0 )
  2473. return;
  2474. static float s_flLastTime = 0;
  2475. static int s_nLastTick = host_tickcount;
  2476. static int s_nLastFrame = host_framecount;
  2477. // Figure out how often they want to update.
  2478. double flInterval = 0;
  2479. if ( host_ShowIPCCallCount.GetFloat() > 0 )
  2480. {
  2481. flInterval = 1.0f / host_ShowIPCCallCount.GetFloat();
  2482. }
  2483. // This is called every frame so increment the frame counter.
  2484. double flCurTime = Plat_FloatTime();
  2485. if ( flCurTime - s_flLastTime >= flInterval )
  2486. {
  2487. uint32 callCount;
  2488. ISteamClient *pSteamClient = SteamClient();
  2489. if ( pSteamClient )
  2490. {
  2491. callCount = pSteamClient->GetIPCCallCount();
  2492. }
  2493. else
  2494. {
  2495. // Ok, we're a dedicated server and we need to use this to get it.
  2496. callCount = (uint32)SteamGameServer_GetIPCCallCount();
  2497. }
  2498. // Avoid a divide by zero.
  2499. int frameCount = host_framecount - s_nLastFrame;
  2500. int tickCount = host_tickcount - s_nLastTick;
  2501. if ( frameCount == 0 || tickCount == 0 )
  2502. return;
  2503. Msg( "host_ShowIPCCallCount: %d IPC calls in the past [%d frames, %d ticks] Avg: [%.2f/frame, %.2f/tick]\n",
  2504. callCount, frameCount, tickCount, (float)callCount / frameCount, (float)callCount / tickCount );
  2505. s_flLastTime = flCurTime;
  2506. s_nLastTick = host_tickcount;
  2507. s_nLastFrame = host_framecount;
  2508. }
  2509. }
  2510. void Host_SetClientInSimulation( bool bInSimulation )
  2511. {
  2512. #ifndef SWDS
  2513. // Tracker 77931: If the game is paused, then lock the client clock at the previous tick boundary
  2514. // (otherwise we'll keep interpolating through the "remainder" time causing the paused characters
  2515. // to twitch like they have the shakes)
  2516. // TODO: Since this rounds down on the frame we paused, we could see a slight backsliding. We could remember the last "remainder" before pause and re-use it and
  2517. // set insimulation == false to be mroe exact. We'd still have to deal with the timing difference between
  2518. // when pause/unpause happens on the server versus the client
  2519. cl.insimulation = bInSimulation || cl.IsPaused();
  2520. // Compute absolute/render time stamp
  2521. g_ClientGlobalVariables.curtime = cl.GetTime();
  2522. g_ClientGlobalVariables.frametime = cl.GetFrameTime();
  2523. #endif
  2524. }
  2525. static ConVar host_Sleep( "host_sleep", "0", FCVAR_CHEAT, "Force the host to sleep a certain number of milliseconds each frame." );
  2526. extern ConVar sv_alternateticks;
  2527. #define LOG_FRAME_OUTPUT 0
  2528. void _Host_RunFrame (float time)
  2529. {
  2530. MDLCACHE_COARSE_LOCK_(g_pMDLCache);
  2531. static double host_remainder = 0.0f;
  2532. double prevremainder;
  2533. bool shouldrender;
  2534. #if defined( RAD_TELEMETRY_ENABLED )
  2535. if( g_Telemetry.DemoTickEnd == ( uint32 )-1 )
  2536. {
  2537. Cbuf_AddText( "quit\n" );
  2538. }
  2539. #endif
  2540. int numticks;
  2541. {
  2542. // Profile scope specific to the top of this function, protect from setjmp() problems
  2543. VPROF( "_Host_RunFrame_Upto_MarkFrame" );
  2544. if ( host_checkheap )
  2545. {
  2546. #if defined(_WIN32)
  2547. if ( _heapchk() != _HEAPOK )
  2548. {
  2549. Sys_Error( "_Host_RunFrame (top): _heapchk() != _HEAPOK\n" );
  2550. }
  2551. #endif
  2552. }
  2553. // When playing back a VCR file, don't do host_sleep. That way, if it was recorded with
  2554. // host_sleep on, it'll play back way Faster.
  2555. if ( host_Sleep.GetInt() && VCRGetMode() != VCR_Playback )
  2556. {
  2557. Sys_Sleep( host_Sleep.GetInt() );
  2558. }
  2559. // Slow down the playback?
  2560. if ( g_iVCRPlaybackSleepInterval )
  2561. {
  2562. Sys_Sleep( g_iVCRPlaybackSleepInterval );
  2563. }
  2564. MapReslistGenerator().RunFrame();
  2565. static int lastrunoffsecond = -1;
  2566. if ( setjmp ( host_enddemo ) )
  2567. return; // demo finished.
  2568. // decide the simulation time
  2569. Host_AccumulateTime ( time );
  2570. _Host_SetGlobalTime();
  2571. shouldrender = !sv.IsDedicated();
  2572. // FIXME: Could track remainder as fractional ticks instead of msec
  2573. prevremainder = host_remainder;
  2574. if ( prevremainder < 0 )
  2575. prevremainder = 0;
  2576. #if !defined(SWDS)
  2577. if ( !demoplayer->IsPlaybackPaused() )
  2578. #endif
  2579. {
  2580. host_remainder += host_frametime;
  2581. }
  2582. numticks = 0; // how many ticks we will simulate this frame
  2583. if ( host_remainder >= host_state.interval_per_tick )
  2584. {
  2585. numticks = (int)( floor( host_remainder / host_state.interval_per_tick ) );
  2586. // round to nearest even ending tick in alternate ticks mode so the last
  2587. // tick is always simulated prior to updating the network data
  2588. // NOTE: alternate ticks only applies in SP!!!
  2589. if ( Host_IsSinglePlayerGame() &&
  2590. sv_alternateticks.GetBool() )
  2591. {
  2592. int startTick = g_ServerGlobalVariables.tickcount;
  2593. int endTick = startTick + numticks;
  2594. endTick = AlignValue( endTick, 2 );
  2595. numticks = endTick - startTick;
  2596. }
  2597. host_remainder -= numticks * host_state.interval_per_tick;
  2598. }
  2599. host_nexttick = host_state.interval_per_tick - host_remainder;
  2600. g_pMDLCache->MarkFrame();
  2601. }
  2602. {
  2603. // Profile scope, protect from setjmp() problems
  2604. VPROF( "_Host_RunFrame" );
  2605. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "_Host_RunFrame" );
  2606. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2607. // process console commands
  2608. Cbuf_Execute ();
  2609. // initialize networking for dedicated server after commandline & autoexec.cfg have been parsed
  2610. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  2611. NET_SetMutiplayer( true );
  2612. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CMD_EXECUTE );
  2613. // Msg( "Running %i ticks (%f remainder) for frametime %f total %f tick %f delta %f\n", numticks, remainder, host_frametime, host_time );
  2614. g_ServerGlobalVariables.interpolation_amount = 0.0f;
  2615. #ifndef SWDS
  2616. g_ClientGlobalVariables.interpolation_amount = 0.0f;
  2617. cl.insimulation = true;
  2618. #endif
  2619. host_frameticks = numticks;
  2620. host_currentframetick = 0;
  2621. #if !defined( SWDS )
  2622. // This is to make the tool do both sim + rendering on the initial frame
  2623. // cl.IsActive changes in the loop below, as does scr_nextdrawtick
  2624. // We're just caching off the state here so that we have a consistent return value
  2625. // for enginetool->IsInGame the entire frame
  2626. g_pEngineToolInternal->SetIsInGame( cl.IsActive() && ( scr_nextdrawtick == 0 ) );
  2627. #endif
  2628. CJob *pGameJob = NULL;
  2629. // threaded path only supported in listen server
  2630. #ifndef SWDS
  2631. if ( !IsEngineThreaded() )
  2632. #endif
  2633. {
  2634. #ifndef SWDS
  2635. if ( g_ClientDLL )
  2636. {
  2637. g_ClientDLL->IN_SetSampleTime(host_frametime);
  2638. }
  2639. g_ClientGlobalVariables.simTicksThisFrame = 1;
  2640. #endif
  2641. cl.m_tickRemainder = host_remainder;
  2642. g_ServerGlobalVariables.simTicksThisFrame = 1;
  2643. cl.SetFrameTime( host_frametime );
  2644. for ( int tick = 0; tick < numticks; tick++ )
  2645. {
  2646. // Emit an ETW event every simulation frame.
  2647. ETWSimFrameMark( sv.IsDedicated() );
  2648. double now = Plat_FloatTime();
  2649. float jitter = now - host_idealtime;
  2650. // Track jitter (delta between ideal time and actual tick execution time)
  2651. host_jitterhistory[ host_jitterhistorypos ] = jitter;
  2652. host_jitterhistorypos = ( host_jitterhistorypos + 1 ) % ARRAYSIZE(host_jitterhistory);
  2653. // Very slowly decay "ideal" towards current wall clock unless delta is large
  2654. if ( fabs( jitter ) > 1.0f )
  2655. {
  2656. host_idealtime = now;
  2657. }
  2658. else
  2659. {
  2660. host_idealtime = 0.99 * host_idealtime + 0.01 * now;
  2661. }
  2662. // process any asynchronous network traffic (TCP), set net_time
  2663. NET_RunFrame( now );
  2664. // Only send updates on final tick so we don't re-encode network data multiple times per frame unnecessarily
  2665. bool bFinalTick = ( tick == (numticks - 1) );
  2666. // initialize networking for dedicated server after commandline & autoexec.cfg have been parsed
  2667. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  2668. NET_SetMutiplayer( true );
  2669. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2670. // NOTE: Do we want do this at start or end of this loop?
  2671. ++host_tickcount;
  2672. ++host_currentframetick;
  2673. #ifndef SWDS
  2674. g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
  2675. // Make sure state is correct
  2676. CL_CheckClientState();
  2677. #endif
  2678. //-------------------
  2679. // input processing
  2680. //-------------------
  2681. _Host_RunFrame_Input( prevremainder, bFinalTick );
  2682. prevremainder = 0;
  2683. //-------------------
  2684. //
  2685. // server operations
  2686. //
  2687. //-------------------
  2688. _Host_RunFrame_Server( bFinalTick );
  2689. // Additional networking ops for SPLITPACKET stuff (99.9% of the time this will be an empty list of work)
  2690. NET_SendQueuedPackets();
  2691. //-------------------
  2692. //
  2693. // client operations
  2694. //
  2695. //-------------------
  2696. #ifndef SWDS
  2697. if ( !sv.IsDedicated() )
  2698. {
  2699. _Host_RunFrame_Client( bFinalTick );
  2700. }
  2701. toolframework->Think( bFinalTick );
  2702. #endif
  2703. host_idealtime += host_state.interval_per_tick;
  2704. }
  2705. // run HLTV if active
  2706. if ( hltv )
  2707. {
  2708. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "hltv->RunFrame()" );
  2709. hltv->RunFrame();
  2710. }
  2711. if ( hltvtest )
  2712. {
  2713. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "hltvtest->RunFrame()" );
  2714. hltvtest->RunFrame();
  2715. }
  2716. #if defined( REPLAY_ENABLED )
  2717. // run replay if active
  2718. if ( replay )
  2719. {
  2720. replay->RunFrame();
  2721. }
  2722. // Update server-side replay history manager
  2723. if ( sv.IsDedicated() && g_pServerReplayContext && g_pServerReplayContext->IsInitialized() )
  2724. {
  2725. g_pServerReplayContext->Think();
  2726. }
  2727. #endif
  2728. #ifndef SWDS
  2729. // This is a hack to let timedemo pull messages from the queue faster than every 15 msec
  2730. // Also when demoplayer is skipping packets to a certain tick we should process the queue
  2731. // as quickly as we can.
  2732. if ( numticks == 0 && ( demoplayer->IsPlayingTimeDemo() || demoplayer->IsSkipping() ) )
  2733. {
  2734. _Host_RunFrame_Client( true );
  2735. }
  2736. if ( !sv.IsDedicated() )
  2737. {
  2738. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Host_SetClientInSimulation" );
  2739. // This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
  2740. Host_SetClientInSimulation( false );
  2741. // Now allow for interpolation on client
  2742. g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
  2743. #if defined( REPLAY_ENABLED )
  2744. // Update client-side replay history manager - called here since interpolation_amount is set
  2745. if ( g_pClientReplayContext && g_pClientReplayContext->IsInitialized() )
  2746. {
  2747. g_pClientReplayContext->Think();
  2748. }
  2749. #endif
  2750. //-------------------
  2751. // Run prediction if it hasn't been run yet
  2752. //-------------------
  2753. // If we haven't predicted/simulated the player (multiplayer with prediction enabled and
  2754. // not a listen server with zero frame lag, then go ahead and predict now
  2755. CL_RunPrediction( PREDICTION_NORMAL );
  2756. CL_ApplyAddAngle();
  2757. // The mouse is always simulated for the current frame's time
  2758. // This makes updates smooth in every case
  2759. // continuous controllers affecting the view are also simulated this way
  2760. // but they have a cap applied by IN_SetSampleTime() so they are not also
  2761. // simulated during input gathering
  2762. CL_ExtraMouseUpdate( g_ClientGlobalVariables.frametime );
  2763. }
  2764. #endif
  2765. #if defined( REPLAY_ENABLED )
  2766. // Let the replay system think
  2767. if ( g_pReplay )
  2768. {
  2769. g_pReplay->Think();
  2770. }
  2771. #endif
  2772. #if LOG_FRAME_OUTPUT
  2773. if ( !cl.IsPaused() || !sv.IsPaused() )
  2774. {
  2775. Msg("=============SIM: CLIENT %5d + %d, SERVER %5d + %d\t REM: %.2f\n", cl.GetClientTickCount(), numticks, sv.m_nTickCount, numticks, host_remainder*1000.0f );
  2776. }
  2777. #endif
  2778. }
  2779. #ifndef SWDS
  2780. else
  2781. {
  2782. static int numticks_last_frame = 0;
  2783. static float host_remainder_last_frame = 0, prev_remainder_last_frame = 0, last_frame_time = 0;
  2784. int clientticks;
  2785. int serverticks;
  2786. clientticks = numticks_last_frame;
  2787. cl.m_tickRemainder = host_remainder_last_frame;
  2788. cl.SetFrameTime( last_frame_time );
  2789. if ( g_ClientDLL )
  2790. {
  2791. g_ClientDLL->IN_SetSampleTime(last_frame_time);
  2792. }
  2793. last_frame_time = host_frametime;
  2794. serverticks = numticks;
  2795. g_ClientGlobalVariables.simTicksThisFrame = clientticks;
  2796. g_ServerGlobalVariables.simTicksThisFrame = serverticks;
  2797. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2798. // THREADED: Run Client
  2799. // -------------------
  2800. for ( int tick = 0; tick < clientticks; tick++ )
  2801. {
  2802. // process any asynchronous network traffic (TCP), set net_time
  2803. NET_RunFrame( Plat_FloatTime() );
  2804. // Only send updates on final tick so we don't re-encode network data multiple times per frame unnecessarily
  2805. bool bFinalTick = ( tick == (clientticks - 1) );
  2806. // initialize networking for dedicated server after commandline & autoexec.cfg have been parsed
  2807. if ( NET_IsDedicated() && !NET_IsMultiplayer() )
  2808. NET_SetMutiplayer( true );
  2809. g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
  2810. // Make sure state is correct
  2811. CL_CheckClientState();
  2812. // Additional networking ops for SPLITPACKET stuff (99.9% of the time this will be an empty list of work)
  2813. NET_SendQueuedPackets();
  2814. //-------------------
  2815. //
  2816. // client operations
  2817. //
  2818. //-------------------
  2819. if ( !sv.IsDedicated() )
  2820. {
  2821. _Host_RunFrame_Client( bFinalTick );
  2822. }
  2823. toolframework->Think( bFinalTick );
  2824. }
  2825. // This is a hack to let timedemo pull messages from the queue faster than every 15 msec
  2826. // Also when demoplayer is skipping packets to a certain tick we should process the queue
  2827. // as quickly as we can.
  2828. if ( clientticks == 0 && ( demoplayer->IsPlayingTimeDemo() || demoplayer->IsSkipping() ) )
  2829. {
  2830. _Host_RunFrame_Client( true );
  2831. }
  2832. // This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
  2833. Host_SetClientInSimulation( false );
  2834. // Now allow for interpolation on client
  2835. g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
  2836. //-------------------
  2837. // Run prediction if it hasn't been run yet
  2838. //-------------------
  2839. // If we haven't predicted/simulated the player (multiplayer with prediction enabled and
  2840. // not a listen server with zero frame lag, then go ahead and predict now
  2841. CL_RunPrediction( PREDICTION_NORMAL );
  2842. CL_ApplyAddAngle();
  2843. Host_SetClientInSimulation( true );
  2844. // THREADED: Run Input
  2845. // -------------------
  2846. int saveTick = g_ClientGlobalVariables.tickcount;
  2847. for ( int tick = 0; tick < serverticks; tick++ )
  2848. {
  2849. // NOTE: Do we want do this at start or end of this loop?
  2850. ++host_tickcount;
  2851. ++host_currentframetick;
  2852. g_ClientGlobalVariables.tickcount = host_tickcount;
  2853. bool bFinalTick = tick==(serverticks-1) ? true : false;
  2854. _Host_RunFrame_Input( prevremainder, bFinalTick );
  2855. prevremainder = 0;
  2856. // process any asynchronous network traffic (TCP), set net_time
  2857. NET_RunFrame( Plat_FloatTime() );
  2858. }
  2859. Host_SetClientInSimulation( false );
  2860. // The mouse is always simulated for the current frame's time
  2861. // This makes updates smooth in every case
  2862. // continuous controllers affecting the view are also simulated this way
  2863. // but they have a cap applied by IN_SetSampleTime() so they are not also
  2864. // simulated during input gathering
  2865. CL_ExtraMouseUpdate( g_ClientGlobalVariables.frametime );
  2866. g_ClientGlobalVariables.tickcount = saveTick;
  2867. numticks_last_frame = numticks;
  2868. host_remainder_last_frame = host_remainder;
  2869. // THREADED: Run Server
  2870. // -------------------
  2871. // set net_time once before running the server
  2872. NET_SetTime( Plat_FloatTime() );
  2873. pGameJob = new CFunctorJob( CreateFunctor( _Host_RunFrame_Server_Async, serverticks ) );
  2874. if ( IsX360() )
  2875. {
  2876. pGameJob->SetServiceThread( g_nServerThread );
  2877. }
  2878. g_pThreadPool->AddJob( pGameJob );
  2879. #if LOG_FRAME_OUTPUT
  2880. if ( !cl.IsPaused() || !sv.IsPaused() )
  2881. {
  2882. Msg("=============SIM: CLIENT %5d + %d, SERVER %5d + %d\t REM: %.2f\n", cl.GetClientTickCount(), clientticks, sv.m_nTickCount, serverticks, host_remainder*1000.0f );
  2883. }
  2884. #endif
  2885. }
  2886. #endif // SWDS
  2887. g_Log.RunFrame();
  2888. if ( shouldrender )
  2889. {
  2890. #if LOG_FRAME_OUTPUT
  2891. if ( !cl.IsPaused() || !sv.IsPaused() )
  2892. {
  2893. static float lastFrameTime = 0;
  2894. float frametime = g_ClientGlobalVariables.curtime - lastFrameTime;
  2895. Msg("RENDER AT: %6.4f: %.2fms [%.2fms implicit] frametime\n",
  2896. g_ClientGlobalVariables.curtime, g_ClientGlobalVariables.frametime*1000.0f, frametime * 1000.0f);
  2897. lastFrameTime = g_ClientGlobalVariables.curtime;
  2898. }
  2899. #endif
  2900. //-------------------
  2901. // rendering
  2902. //-------------------
  2903. _Host_RunFrame_Render();
  2904. //-------------------
  2905. // sound
  2906. //-------------------
  2907. _Host_RunFrame_Sound();
  2908. if ( g_bVCRSingleStep )
  2909. {
  2910. VCR_EnterPausedState();
  2911. }
  2912. }
  2913. else
  2914. {
  2915. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "modelloader->UpdateDynamicModels" );
  2916. VPROF( "UpdateDynamicModels" );
  2917. CMDLCacheCriticalSection critsec( g_pMDLCache );
  2918. modelloader->UpdateDynamicModels();
  2919. }
  2920. //-------------------
  2921. // simulation
  2922. //-------------------
  2923. g_HostTimes.MarkSwapTime( );
  2924. #ifndef SWDS
  2925. if ( !sv.IsDedicated() )
  2926. {
  2927. VPROF( "_Host_RunFrame - ClientDLL_Update" );
  2928. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "_Host_RunFrame - ClientDLL_Update" );
  2929. // Client-side simulation
  2930. g_HostTimes.StartFrameSegment( FRAME_SEGMENT_CLDLL );
  2931. ClientDLL_Update();
  2932. g_HostTimes.EndFrameSegment( FRAME_SEGMENT_CLDLL );
  2933. }
  2934. #endif
  2935. if ( pGameJob )
  2936. {
  2937. {
  2938. VPROF_BUDGET( "WaitForAsyncServer", "AsyncServer" );
  2939. if ( Host_IsSinglePlayerGame() )
  2940. {
  2941. // This should change to a YieldWait if the server starts wanting to parallel process. If
  2942. // so, will need some route for the server to queue up work it wants to execute outside
  2943. // its frame, otherwise some of it would be performed during the yield. Right now
  2944. // need to wait for server so we don't stall on queued AI operations (toml 7/3/2007)
  2945. pGameJob->ExecuteAndRelease();
  2946. }
  2947. else
  2948. {
  2949. pGameJob->WaitForFinishAndRelease();
  2950. }
  2951. }
  2952. SV_FrameExecuteThreadDeferred();
  2953. }
  2954. //-------------------
  2955. // time
  2956. //-------------------
  2957. Host_Speeds();
  2958. Host_UpdateMapList();
  2959. host_framecount++;
  2960. #if !defined(SWDS)
  2961. if ( !demoplayer->IsPlaybackPaused() )
  2962. #endif
  2963. {
  2964. host_time = host_tickcount * host_state.interval_per_tick + cl.m_tickRemainder;
  2965. }
  2966. Host_PostFrameRate( host_frametime );
  2967. if ( host_checkheap )
  2968. {
  2969. #ifdef _WIN32
  2970. if ( _heapchk() != _HEAPOK )
  2971. {
  2972. Sys_Error( "_Host_RunFrame (bottom): _heapchk() != _HEAPOK\n" );
  2973. }
  2974. #endif
  2975. }
  2976. Host_CheckDumpMemoryStats();
  2977. GetTestScriptMgr()->CheckPoint( "frame_end" );
  2978. } // Profile scope, protect from setjmp() problems
  2979. Host_ShowIPCCallCount();
  2980. }
  2981. /*
  2982. ==============================
  2983. Host_Frame
  2984. ==============================
  2985. */
  2986. void Host_RunFrame( float time )
  2987. {
  2988. static double timetotal = 0;
  2989. static int timecount = 0;
  2990. static double timestart = 0;
  2991. #ifndef SWDS
  2992. if ( !scr_drawloading && sv.IsActive() && cl.IsActive() && !sv.m_bLoadgame)
  2993. {
  2994. switch ( host_thread_mode.GetInt() )
  2995. {
  2996. case HTM_DISABLED: g_bThreadedEngine = false; break;
  2997. case HTM_DEFAULT: g_bThreadedEngine = ( g_pThreadPool->NumThreads() > 0 ); break;
  2998. case HTM_FORCED: g_bThreadedEngine = true; break;
  2999. }
  3000. }
  3001. else
  3002. #endif
  3003. {
  3004. g_bThreadedEngine = false;
  3005. }
  3006. if ( !host_profile.GetBool() )
  3007. {
  3008. _Host_RunFrame( time );
  3009. return;
  3010. }
  3011. double time1 = Sys_FloatTime();
  3012. _Host_RunFrame( time );
  3013. double time2 = Sys_FloatTime();
  3014. timetotal += time2 - time1; // time in seconds
  3015. timecount++;
  3016. if (timecount < 1000)
  3017. return;
  3018. float fps = 1000/(time2 - timestart);
  3019. ConMsg ("host_profile : %i clients, %.1f msec, %.1f fps\n",
  3020. sv.GetNumClients(), timetotal, fps );
  3021. timecount = 0;
  3022. timetotal = 0;
  3023. timestart = time2;
  3024. }
  3025. //-----------------------------------------------------------------------------
  3026. // A more secure means of enforcing low violence.
  3027. //-----------------------------------------------------------------------------
  3028. bool IsLowViolence_Secure()
  3029. {
  3030. #ifndef DEDICATED
  3031. if ( !IsX360() && Steam3Client().SteamApps() )
  3032. {
  3033. // let Steam determine current violence settings
  3034. return Steam3Client().SteamApps()->BIsLowViolence();
  3035. }
  3036. else if ( IsX360() )
  3037. {
  3038. // Low violence for the 360 is enabled by the presence of a file.
  3039. if ( g_pFileSystem->FileExists( "cfg/violence.cfg" ) )
  3040. {
  3041. return true;
  3042. }
  3043. return false;
  3044. }
  3045. #endif
  3046. return false;
  3047. }
  3048. //-----------------------------------------------------------------------------
  3049. // If "User Token 2" exists in HKEY_CURRENT_USER/Software/Valve/Half-Life/Settings
  3050. // then we disable gore. Obviously not very secure.
  3051. //-----------------------------------------------------------------------------
  3052. bool IsLowViolence_Registry()
  3053. {
  3054. char szSubKey[128];
  3055. int nBufferLen;
  3056. char szBuffer[128];
  3057. bool bReducedGore = false;
  3058. memset( szBuffer, 0, 128 );
  3059. char const *appname = "Source";
  3060. Q_snprintf(szSubKey, sizeof( szSubKey ), "Software\\Valve\\%s\\Settings", appname );
  3061. nBufferLen = 127;
  3062. Q_strncpy( szBuffer, "", sizeof( szBuffer ) );
  3063. Sys_GetRegKeyValue( szSubKey, "User Token 2", szBuffer, nBufferLen, szBuffer );
  3064. // Gore reduction active?
  3065. bReducedGore = ( Q_strlen( szBuffer ) > 0 ) ? true : false;
  3066. if ( !bReducedGore )
  3067. {
  3068. Sys_GetRegKeyValue( szSubKey, "User Token 3", szBuffer, nBufferLen, szBuffer );
  3069. bReducedGore = ( Q_strlen( szBuffer ) > 0 ) ? true : false;
  3070. }
  3071. char gamedir[MAX_OSPATH];
  3072. Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
  3073. // also check mod specific directories for LV changes
  3074. Q_snprintf(szSubKey, sizeof( szSubKey ), "Software\\Valve\\%s\\%s\\Settings", appname, gamedir );
  3075. nBufferLen = 127;
  3076. Q_strncpy( szBuffer, "", sizeof( szBuffer ) );
  3077. Sys_GetRegKeyValue( szSubKey, "User Token 2", szBuffer, nBufferLen, szBuffer );
  3078. if ( Q_strlen( szBuffer ) > 0 )
  3079. {
  3080. bReducedGore = true;
  3081. }
  3082. Sys_GetRegKeyValue( szSubKey, "User Token 3", szBuffer, nBufferLen, szBuffer );
  3083. if ( Q_strlen( szBuffer ) > 0 )
  3084. {
  3085. bReducedGore = true;
  3086. }
  3087. return bReducedGore;
  3088. }
  3089. //-----------------------------------------------------------------------------
  3090. //-----------------------------------------------------------------------------
  3091. void Host_CheckGore( void )
  3092. {
  3093. bool bLowViolenceRegistry = false;
  3094. bool bLowViolenceSecure = false;
  3095. //
  3096. // First check the old method of enabling low violence via the registry.
  3097. //
  3098. #ifdef WIN32
  3099. bLowViolenceRegistry = IsLowViolence_Registry();
  3100. #endif
  3101. //
  3102. // Next check the new method of enabling low violence based on country of purchase
  3103. // and other means that are inaccessible by the user.
  3104. //
  3105. if ( GetCurrentMod() && Q_stricmp( GetCurrentMod(), "cstrike" ) != 0 )
  3106. bLowViolenceSecure = IsLowViolence_Secure();
  3107. //
  3108. // If either method says "yes" to low violence, we're in low violence mode.
  3109. //
  3110. if ( bLowViolenceRegistry || bLowViolenceSecure )
  3111. {
  3112. g_bLowViolence = true;
  3113. if ( bLowViolenceRegistry )
  3114. {
  3115. violence_hblood.SetValue( 0 );
  3116. violence_hgibs.SetValue( 0 );
  3117. violence_ablood.SetValue( 0 );
  3118. violence_agibs.SetValue( 0 );
  3119. }
  3120. }
  3121. else
  3122. {
  3123. g_bLowViolence = false;
  3124. }
  3125. }
  3126. //-----------------------------------------------------------------------------
  3127. // Purpose:
  3128. //-----------------------------------------------------------------------------
  3129. void Host_InitProcessor( void )
  3130. {
  3131. const CPUInformation& pi = *GetCPUInformation();
  3132. // Compute Frequency in Mhz:
  3133. char* szFrequencyDenomination = "Mhz";
  3134. double fFrequency = pi.m_Speed / 1000000.0;
  3135. // Adjust to Ghz if nessecary:
  3136. if( fFrequency > 1000.0 )
  3137. {
  3138. fFrequency /= 1000.0;
  3139. szFrequencyDenomination = "Ghz";
  3140. }
  3141. char szFeatureString[256];
  3142. Q_strncpy( szFeatureString, pi.m_szProcessorID, sizeof( szFeatureString ) );
  3143. Q_strncat( szFeatureString, " ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3144. if( pi.m_bSSE )
  3145. {
  3146. if( MathLib_SSEEnabled() ) Q_strncat(szFeatureString, "SSE ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3147. else Q_strncat(szFeatureString, "(SSE) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3148. }
  3149. if( pi.m_bSSE2 )
  3150. {
  3151. if( MathLib_SSE2Enabled() ) Q_strncat(szFeatureString, "SSE2 ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3152. else Q_strncat(szFeatureString, "(SSE2) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3153. }
  3154. if( pi.m_bMMX )
  3155. {
  3156. if( MathLib_MMXEnabled() ) Q_strncat(szFeatureString, "MMX ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3157. else Q_strncat(szFeatureString, "(MMX) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3158. }
  3159. if( pi.m_b3DNow )
  3160. {
  3161. if( MathLib_3DNowEnabled() ) Q_strncat(szFeatureString, "3DNow ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3162. else Q_strncat(szFeatureString, "(3DNow) ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3163. }
  3164. if( pi.m_bRDTSC ) Q_strncat(szFeatureString, "RDTSC ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3165. if( pi.m_bCMOV ) Q_strncat(szFeatureString, "CMOV ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3166. if( pi.m_bFCMOV ) Q_strncat(szFeatureString, "FCMOV ", sizeof( szFeatureString ), COPY_ALL_CHARACTERS );
  3167. // Remove the trailing space. There will always be one.
  3168. szFeatureString[Q_strlen(szFeatureString)-1] = '\0';
  3169. // Dump CPU information:
  3170. if( pi.m_nLogicalProcessors == 1 )
  3171. {
  3172. ConDMsg( "1 CPU, Frequency: %.01f %s, Features: %s\n",
  3173. fFrequency,
  3174. szFrequencyDenomination,
  3175. szFeatureString
  3176. );
  3177. }
  3178. else
  3179. {
  3180. char buffer[256] = "";
  3181. if( pi.m_nPhysicalProcessors != pi.m_nLogicalProcessors )
  3182. {
  3183. Q_snprintf(buffer, sizeof( buffer ), " (%i physical)", (int) pi.m_nPhysicalProcessors );
  3184. }
  3185. ConDMsg( "%i CPUs%s, Frequency: %.01f %s, Features: %s\n",
  3186. (int)pi.m_nLogicalProcessors,
  3187. buffer,
  3188. fFrequency,
  3189. szFrequencyDenomination,
  3190. szFeatureString
  3191. );
  3192. }
  3193. #if defined( _WIN32 )
  3194. if ( s_bInitPME )
  3195. {
  3196. // Initialize the performance monitoring events code.
  3197. InitPME();
  3198. }
  3199. #endif
  3200. }
  3201. //-----------------------------------------------------------------------------
  3202. // Specifically used by the model loading code to mark models
  3203. // touched by the current map
  3204. //-----------------------------------------------------------------------------
  3205. int Host_GetServerCount( void )
  3206. {
  3207. if (cl.m_nSignonState >= SIGNONSTATE_NEW)
  3208. {
  3209. // the server count cannot be relied on until the server info message
  3210. // the new state guarantees its validity
  3211. return cl.m_nServerCount;
  3212. }
  3213. else if (sv.m_State >= ss_loading)
  3214. {
  3215. return sv.GetSpawnCount();
  3216. }
  3217. // this is unfortunate, and happens, but the caller is too early in the protocol or a demo
  3218. // cannot identify the correct server count
  3219. // return the same count that demo will use
  3220. return gHostSpawnCount;
  3221. }
  3222. //-----------------------------------------------------------------------------
  3223. // Purpose:
  3224. //-----------------------------------------------------------------------------
  3225. void Host_PostInit()
  3226. {
  3227. if ( serverGameDLL )
  3228. {
  3229. serverGameDLL->PostInit();
  3230. }
  3231. #if !defined( SWDS )
  3232. if ( g_ClientDLL )
  3233. {
  3234. g_ClientDLL->PostInit();
  3235. }
  3236. toolframework->PostInit();
  3237. if ( !sv.IsDedicated() )
  3238. {
  3239. // vgui needs other systems to finalize
  3240. EngineVGui()->PostInit();
  3241. }
  3242. #if defined( LINUX )
  3243. const char en_US[] = "en_US.UTF-8";
  3244. const char *CurrentLocale = setlocale( LC_ALL, NULL );
  3245. if ( !CurrentLocale )
  3246. CurrentLocale = "c";
  3247. if ( Q_stricmp( CurrentLocale, en_US ) )
  3248. {
  3249. char MessageText[ 512 ];
  3250. V_sprintf_safe( MessageText, "SetLocale('%s') failed. Using '%s'.\n"
  3251. "You may have limited glyph support.\n"
  3252. "Please install '%s' locale.",
  3253. en_US, CurrentLocale, en_US );
  3254. SDL_ShowSimpleMessageBox( 0, "Warning", MessageText, GetAssertDialogParent() );
  3255. }
  3256. #endif // LINUX
  3257. #endif
  3258. }
  3259. void HLTV_Init()
  3260. {
  3261. Assert ( hltv == NULL );
  3262. Assert ( hltvtest == NULL );
  3263. }
  3264. void HLTV_Shutdown()
  3265. {
  3266. if ( hltv )
  3267. {
  3268. hltv->Shutdown();
  3269. delete hltv;
  3270. hltv = NULL;
  3271. }
  3272. if ( hltvtest )
  3273. {
  3274. delete hltvtest;
  3275. hltvtest = NULL;
  3276. }
  3277. }
  3278. // Check with steam to see if the requested file (requires full path) is a valid, signed binary
  3279. bool DLL_LOCAL Host_IsValidSignature( const char *pFilename, bool bAllowUnknown )
  3280. {
  3281. #if defined( SWDS ) || defined(_X360)
  3282. return true;
  3283. #else
  3284. if ( sv.IsDedicated() || IsOSX() || IsLinux() )
  3285. {
  3286. // dedicated servers and Mac and Linux binaries don't check signatures
  3287. return true;
  3288. }
  3289. else
  3290. {
  3291. if ( Steam3Client().SteamUtils() )
  3292. {
  3293. SteamAPICall_t hAPICall = Steam3Client().SteamUtils()->CheckFileSignature( pFilename );
  3294. bool bAPICallFailed = true;
  3295. while ( !Steam3Client().SteamUtils()->IsAPICallCompleted(hAPICall, &bAPICallFailed) )
  3296. {
  3297. SteamAPI_RunCallbacks();
  3298. ThreadSleep( 1 );
  3299. }
  3300. if( bAPICallFailed )
  3301. {
  3302. Warning( "CheckFileSignature API call on %s failed", pFilename );
  3303. }
  3304. else
  3305. {
  3306. CheckFileSignature_t result;
  3307. Steam3Client().SteamUtils()->GetAPICallResult( hAPICall, &result, sizeof(result), result.k_iCallback, &bAPICallFailed );
  3308. if( bAPICallFailed )
  3309. {
  3310. Warning( "CheckFileSignature API call on %s failed\n", pFilename );
  3311. }
  3312. else
  3313. {
  3314. if( result.m_eCheckFileSignature == k_ECheckFileSignatureValidSignature || result.m_eCheckFileSignature == k_ECheckFileSignatureNoSignaturesFoundForThisApp )
  3315. return true;
  3316. if ( bAllowUnknown && result.m_eCheckFileSignature == k_ECheckFileSignatureNoSignaturesFoundForThisFile )
  3317. return true;
  3318. Warning( "No valid signature found for %s\n", pFilename );
  3319. }
  3320. }
  3321. }
  3322. }
  3323. return false;
  3324. #endif // SWDS
  3325. }
  3326. // Ask steam if it is ok to load this DLL. Unsigned DLLs should not be loaded unless
  3327. // the client is running -insecure (testing a plugin for example)
  3328. // This keeps legitimate users with modified binaries from getting VAC banned because of them
  3329. bool DLL_LOCAL Host_AllowLoadModule( const char *pFilename, const char *pPathID, bool bAllowUnknown, bool bIsServerOnly /* = false */ )
  3330. {
  3331. #if defined( SWDS ) || defined ( OSX ) || defined( LINUX )
  3332. // dedicated servers and Mac and Linux binaries don't check signatures
  3333. return true;
  3334. #else
  3335. if ( sv.IsDedicated() || bIsServerOnly )
  3336. {
  3337. // dedicated servers and Mac binaries don't check signatures
  3338. return true;
  3339. }
  3340. else
  3341. {
  3342. // check signature
  3343. bool bSignatureIsValid = false;
  3344. // Do we need to do the signature checking? If secure servers are disabled, just skip it.
  3345. if ( Host_IsSecureServerAllowed() )
  3346. {
  3347. if ( Steam3Client().SteamUtils() )
  3348. {
  3349. char szDllname[512];
  3350. V_strncpy( szDllname, pFilename, sizeof(szDllname) );
  3351. V_SetExtension( szDllname, g_pModuleExtension, sizeof(szDllname) );
  3352. if ( pPathID )
  3353. {
  3354. char szFullPath[ 512 ];
  3355. const char *pFullPath = g_pFileSystem->RelativePathToFullPath( szDllname, pPathID, szFullPath, sizeof(szFullPath) );
  3356. if ( !pFullPath )
  3357. {
  3358. Warning("Can't find %s on disk\n", szDllname );
  3359. bSignatureIsValid = false;
  3360. }
  3361. else
  3362. {
  3363. bSignatureIsValid = Host_IsValidSignature( pFullPath, bAllowUnknown );
  3364. }
  3365. }
  3366. else
  3367. {
  3368. bSignatureIsValid = Host_IsValidSignature( szDllname, bAllowUnknown );
  3369. }
  3370. }
  3371. else
  3372. {
  3373. Warning("Steam is not active, running in -insecure mode.\n");
  3374. Host_DisallowSecureServers();
  3375. }
  3376. }
  3377. else
  3378. {
  3379. Warning("Loading unsigned module %s\nAccess to secure servers is disabled.\n", pFilename );
  3380. return true;
  3381. }
  3382. return bSignatureIsValid;
  3383. }
  3384. #endif // SWDS
  3385. }
  3386. bool DLL_LOCAL Host_IsSecureServerAllowed()
  3387. {
  3388. if ( CommandLine()->FindParm( "-insecure" ) || CommandLine()->FindParm( "-textmode" ) )
  3389. g_bAllowSecureServers = false;
  3390. return g_bAllowSecureServers;
  3391. }
  3392. //-----------------------------------------------------------------------------
  3393. // Purpose:
  3394. //-----------------------------------------------------------------------------
  3395. void Host_Init( bool bDedicated )
  3396. {
  3397. realtime = 0;
  3398. host_idealtime = 0;
  3399. #if defined(_WIN32)
  3400. if ( CommandLine()->FindParm( "-pme" ) )
  3401. {
  3402. s_bInitPME = true;
  3403. }
  3404. #endif
  3405. if ( Host_IsSecureServerAllowed() )
  3406. {
  3407. // double check the engine's signature in case it was hooked/modified
  3408. if ( !Host_AllowLoadModule( "engine" DLL_EXT_STRING, "EXECUTABLE_PATH", false, bDedicated ) )
  3409. {
  3410. // not supposed to load this but we will anyway
  3411. Host_DisallowSecureServers();
  3412. }
  3413. }
  3414. ThreadPoolStartParams_t startParams;
  3415. if ( IsX360() )
  3416. {
  3417. // 360 overrides defaults, 2 computation threads distributed to core 1 and 2
  3418. startParams.nThreads = 2;
  3419. startParams.nStackSize = 256*1024;
  3420. startParams.fDistribute = TRS_TRUE;
  3421. startParams.bUseAffinityTable = true;
  3422. startParams.iAffinityTable[0] = XBOX_PROCESSOR_2;
  3423. startParams.iAffinityTable[1] = XBOX_PROCESSOR_4;
  3424. ThreadSetAffinity( NULL, 1 );
  3425. }
  3426. if ( g_pThreadPool )
  3427. g_pThreadPool->Start( startParams, "CmpJob" );
  3428. // From const.h, the loaded game .dll will give us the correct value which is transmitted to the client
  3429. host_state.interval_per_tick = DEFAULT_TICK_INTERVAL;
  3430. InstallBitBufErrorHandler();
  3431. TRACEINIT( Memory_Init(), Memory_Shutdown() );
  3432. TRACEINIT( Con_Init(), Con_Shutdown() );
  3433. TRACEINIT( Cbuf_Init(), Cbuf_Shutdown() );
  3434. TRACEINIT( Cmd_Init(), Cmd_Shutdown() );
  3435. TRACEINIT( g_pCVar->Init(), g_pCVar->Shutdown() ); // So we can list cvars with "cvarlst"
  3436. #ifndef SWDS
  3437. TRACEINIT( V_Init(), V_Shutdown() );
  3438. #endif
  3439. TRACEINIT( COM_Init(), COM_Shutdown() );
  3440. #ifndef SWDS
  3441. TRACEINIT( saverestore->Init(), saverestore->Shutdown() );
  3442. #endif
  3443. TRACEINIT( Filter_Init(), Filter_Shutdown() );
  3444. #ifndef SWDS
  3445. TRACEINIT( Key_Init(), Key_Shutdown() );
  3446. #endif
  3447. // Check for special -dev flag
  3448. if ( CommandLine()->FindParm( "-dev" ) || ( CommandLine()->FindParm( "-allowdebug" ) && !CommandLine()->FindParm( "-nodev" ) ) )
  3449. {
  3450. sv_cheats.SetValue( 1 );
  3451. developer.SetValue( 1 );
  3452. }
  3453. #ifdef _DEBUG
  3454. developer.SetValue( 1 );
  3455. #endif
  3456. // Should have read info from steam.inf by now.
  3457. Assert( GetSteamInfIDVersionInfo().AppID != k_uAppIdInvalid );
  3458. if ( CommandLine()->FindParm( "-nocrashdialog" ) )
  3459. {
  3460. // stop the various windows error message boxes from showing up (used by the auto-builder so it doesn't block on error)
  3461. Sys_NoCrashDialog();
  3462. }
  3463. TRACEINIT( NET_Init( bDedicated ), NET_Shutdown() );
  3464. TRACEINIT( g_GameEventManager.Init(), g_GameEventManager.Shutdown() );
  3465. TRACEINIT( sv.Init( bDedicated ), sv.Shutdown() );
  3466. #if defined( REPLAY_ENABLED )
  3467. if ( Replay_IsSupportedModAndPlatform() )
  3468. {
  3469. TRACEINIT( ReplaySystem_Init( bDedicated ), ReplaySystem_Shutdown() );
  3470. }
  3471. #endif
  3472. if ( !CommandLine()->FindParm( "-nogamedll" ) )
  3473. {
  3474. SV_InitGameDLL();
  3475. }
  3476. TRACEINIT( g_Log.Init(), g_Log.Shutdown() );
  3477. TRACEINIT( HLTV_Init(), HLTV_Shutdown() );
  3478. ConDMsg( "Heap: %5.2f Mb\n", host_parms.memsize/(1024.0f*1024.0f) );
  3479. #if !defined( SWDS )
  3480. if ( !bDedicated )
  3481. {
  3482. TRACEINIT( CL_Init(), CL_Shutdown() );
  3483. // NOTE: This depends on the mod search path being set up
  3484. TRACEINIT( InitMaterialSystem(), ShutdownMaterialSystem() );
  3485. TRACEINIT( modelloader->Init(), modelloader->Shutdown() );
  3486. TRACEINIT( StaticPropMgr()->Init(), StaticPropMgr()->Shutdown() );
  3487. TRACEINIT( InitStudioRender(), ShutdownStudioRender() );
  3488. //startup vgui
  3489. TRACEINIT( EngineVGui()->Init(), EngineVGui()->Shutdown() );
  3490. TRACEINIT( TextMessageInit(), TextMessageShutdown() );
  3491. TRACEINIT( ClientDLL_Init(), ClientDLL_Shutdown() );
  3492. TRACEINIT( SCR_Init(), SCR_Shutdown() );
  3493. TRACEINIT( R_Init(), R_Shutdown() );
  3494. TRACEINIT( Decal_Init(), Decal_Shutdown() );
  3495. // hookup interfaces
  3496. EngineVGui()->Connect();
  3497. }
  3498. else
  3499. #endif
  3500. {
  3501. TRACEINIT( InitMaterialSystem(), ShutdownMaterialSystem() );
  3502. TRACEINIT( modelloader->Init(), modelloader->Shutdown() );
  3503. TRACEINIT( StaticPropMgr()->Init(), StaticPropMgr()->Shutdown() );
  3504. TRACEINIT( InitStudioRender(), ShutdownStudioRender() );
  3505. TRACEINIT( Decal_Init(), Decal_Shutdown() );
  3506. cl.m_nSignonState = SIGNONSTATE_NONE; // disable client
  3507. }
  3508. #ifndef SWDS
  3509. Host_ReadConfiguration();
  3510. TRACEINIT( S_Init(), S_Shutdown() );
  3511. #endif
  3512. // Execute valve.rc
  3513. Cbuf_AddText( "exec valve.rc\n" );
  3514. #if defined( REPLAY_ENABLED )
  3515. // Execute replay.cfg if this is TF and they want to use the replay system
  3516. if ( Replay_IsSupportedModAndPlatform() && CommandLine()->CheckParm( "-replay" ) )
  3517. {
  3518. const char *pConfigName = CommandLine()->ParmValue( "-replay", "replay.cfg" );
  3519. Cbuf_AddText( va( "exec %s\n", pConfigName ) );
  3520. }
  3521. #endif
  3522. // Execute mod-specfic settings, without falling back based on search path.
  3523. // This lets us set overrides for games while letting mods of those games
  3524. // use the default settings.
  3525. if ( g_pFileSystem->FileExists( "//mod/cfg/modsettings.cfg" ) )
  3526. {
  3527. Cbuf_AddText( "exec modsettings.cfg mod\n" );
  3528. }
  3529. // Mark DLL as active
  3530. // eng->SetNextState( InEditMode() ? IEngine::DLL_PAUSED : IEngine::DLL_ACTIVE );
  3531. // Deal with Gore Settings
  3532. Host_CheckGore();
  3533. TelemetryTick();
  3534. // Initialize processor subsystem, and print relevant information:
  3535. Host_InitProcessor();
  3536. // Mark hunklevel at end of startup
  3537. Hunk_AllocName( 0, "-HOST_HUNKLEVEL-" );
  3538. host_hunklevel = Hunk_LowMark();
  3539. #ifdef SOURCE_MT
  3540. if ( CommandLine()->FindParm( "-swapcores" ) )
  3541. {
  3542. g_nMaterialSystemThread = 1;
  3543. g_nServerThread = 0;
  3544. }
  3545. #endif
  3546. Host_AllowQueuedMaterialSystem( false );
  3547. // Finished initializing
  3548. host_initialized = true;
  3549. host_checkheap = CommandLine()->FindParm( "-heapcheck" ) ? true : false;
  3550. if ( host_checkheap )
  3551. {
  3552. #if defined( _WIN32 )
  3553. if ( _heapchk() != _HEAPOK )
  3554. {
  3555. Sys_Error( "Host_Init: _heapchk() != _HEAPOK\n" );
  3556. }
  3557. #endif
  3558. }
  3559. // go directly to run state with no active game
  3560. HostState_Init();
  3561. // check for reslist generation
  3562. if ( CommandLine()->FindParm( "-makereslists" ) )
  3563. {
  3564. MapReslistGenerator().StartReslistGeneration();
  3565. }
  3566. // check for devshot generation
  3567. if ( CommandLine()->FindParm( "-makedevshots" ) )
  3568. {
  3569. DevShotGenerator().StartDevShotGeneration();
  3570. }
  3571. // if running outside of steam and NOT a dedicated server then phone home (or if "-phonehome" is passed on the command line)
  3572. if ( !sv.IsDedicated() || CommandLine()->FindParm( "-phonehome" ) )
  3573. {
  3574. // In debug, only run this check if -phonehome is on the command line (so a debug build will "just work").
  3575. if ( IsDebug() && CommandLine()->FindParm( "-phonehome" ) )
  3576. {
  3577. phonehome->Init();
  3578. phonehome->Message( IPhoneHome::PHONE_MSG_ENGINESTART, NULL );
  3579. }
  3580. }
  3581. #ifndef SWDS
  3582. // Rebuild audio caches
  3583. if ( !sv.IsDedicated() && S_IsInitted() )
  3584. {
  3585. if ( !MapReslistGenerator().IsEnabled() )
  3586. {
  3587. // only build caches if we aren't' generating reslists (you need reslists to make the caches)
  3588. extern void CheckCacheBuild();
  3589. CheckCacheBuild();
  3590. }
  3591. }
  3592. #endif
  3593. Host_PostInit();
  3594. EndLoadingUpdates( );
  3595. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  3596. pRenderContext->SetNonInteractiveTempFullscreenBuffer( NULL, MATERIAL_NON_INTERACTIVE_MODE_STARTUP );
  3597. pRenderContext->SetNonInteractivePacifierTexture( NULL, 0, 0, 0 );
  3598. }
  3599. //-----------------------------------------------------------------------------
  3600. // Adds hints to the loader to keep resources that are in the transition volume,
  3601. // as they may not be part of the next map's reslist.
  3602. //-----------------------------------------------------------------------------
  3603. void AddTransitionResources( CSaveRestoreData *pSaveData, const char *pLevelName, const char *pLandmarkName )
  3604. {
  3605. if ( !IsX360() || ( g_pFileSystem->GetDVDMode() != DVDMODE_STRICT ) )
  3606. {
  3607. return;
  3608. }
  3609. // get the bit marked for the next level
  3610. int transitionMask = 0;
  3611. for ( int i = 0; i < pSaveData->levelInfo.connectionCount; i++ )
  3612. {
  3613. if ( !Q_stricmp( pLevelName, pSaveData->levelInfo.levelList[i].mapName ) && !Q_stricmp( pLandmarkName, pSaveData->levelInfo.levelList[i].landmarkName ) )
  3614. {
  3615. transitionMask = 1<<i;
  3616. break;
  3617. }
  3618. }
  3619. if ( !transitionMask )
  3620. {
  3621. // nothing to do
  3622. return;
  3623. }
  3624. const char *pModelName;
  3625. bool bHasHumans = false;
  3626. for ( int i = 0; i < pSaveData->NumEntities(); i++ )
  3627. {
  3628. if ( pSaveData->GetEntityInfo(i)->flags & transitionMask )
  3629. {
  3630. // this entity will cross the transition and needs to be preserved
  3631. // add to the next map's resource list which effectively keeps it from being purged
  3632. // only care about the actual mdl and not any of its dependants
  3633. pModelName = pSaveData->GetEntityInfo(i)->modelname.ToCStr();
  3634. g_pQueuedLoader->AddMapResource( pModelName );
  3635. // humans require a post pass
  3636. if ( !bHasHumans && V_stristr( pModelName, "models/humans" ) )
  3637. {
  3638. bHasHumans = true;
  3639. }
  3640. }
  3641. }
  3642. if ( bHasHumans )
  3643. {
  3644. // the presence of any human entity in the transition needs to ensure all the human mdls stay
  3645. int count = modelloader->GetCount();
  3646. for ( int i = 0; i < count; i++ )
  3647. {
  3648. pModelName = modelloader->GetName( modelloader->GetModelForIndex( i ) );
  3649. if ( V_stristr( pModelName, "models/humans" ) )
  3650. {
  3651. g_pQueuedLoader->AddMapResource( pModelName );
  3652. }
  3653. }
  3654. }
  3655. }
  3656. bool Host_Changelevel( bool loadfromsavedgame, const char *mapname, const char *start )
  3657. {
  3658. char _startspot[MAX_QPATH];
  3659. char *startspot;
  3660. char oldlevel[MAX_PATH];
  3661. #if !defined(SWDS)
  3662. CSaveRestoreData *pSaveData = NULL;
  3663. #endif
  3664. bool bTransitionBySave = false;
  3665. if ( !sv.IsActive() )
  3666. {
  3667. ConMsg("Only the server may changelevel\n");
  3668. return false;
  3669. }
  3670. #ifndef SWDS
  3671. // FIXME: Even needed?
  3672. if ( demoplayer->IsPlayingBack() )
  3673. {
  3674. ConMsg("Changelevel invalid during demo playback\n");
  3675. SCR_EndLoadingPlaque();
  3676. return false;
  3677. }
  3678. #endif
  3679. #ifndef SWDS
  3680. SCR_BeginLoadingPlaque();
  3681. // stop sounds (especially looping!)
  3682. S_StopAllSounds(true);
  3683. #endif
  3684. // Prepare new level
  3685. sv.InactivateClients();
  3686. // The qualified name of the map, excluding path/extension
  3687. char szMapName[MAX_PATH] = { 0 };
  3688. // The file to load the map from.
  3689. char szMapFile[MAX_PATH] = { 0 };
  3690. Q_strncpy( szMapName, mapname, sizeof( szMapName ) );
  3691. Host_DefaultMapFileName( szMapName, szMapFile, sizeof( szMapFile ) );
  3692. // Ask serverDLL to prepare this load
  3693. if ( g_iServerGameDLLVersion >= 10 )
  3694. {
  3695. serverGameDLL->PrepareLevelResources( szMapName, sizeof( szMapName ), szMapFile, sizeof( szMapFile ) );
  3696. }
  3697. if ( !modelloader->Map_IsValid( szMapFile ) )
  3698. {
  3699. #ifndef SWDS
  3700. SCR_EndLoadingPlaque();
  3701. #endif
  3702. // We have already inactivated clients at this point due to PrepareLevelResources being blocking, false alarm,
  3703. // tell them to reconnect (which doesn't mean full reconnect, just start rejoining the map)
  3704. //
  3705. // In the likely case that the game DLL tries another map this is harmless, they'll wait on the game server in
  3706. // the connect process if its in another level change by time they get there.
  3707. sv.ReconnectClients();
  3708. return false;
  3709. }
  3710. // If changing from the same map to the same map, optimize by not closing and reopening
  3711. // the packfile which is embedded in the .bsp; we do this by incrementing the packfile's
  3712. // refcount via BeginMapAccess()/EndMapAccess() through the base filesystem API.
  3713. struct LocalMapAccessScope
  3714. {
  3715. LocalMapAccessScope() : bEnabled( false ) { }
  3716. ~LocalMapAccessScope() { if ( bEnabled ) g_pFileSystem->EndMapAccess(); }
  3717. bool bEnabled;
  3718. };
  3719. LocalMapAccessScope mapscope;
  3720. if ( V_strcmp( sv.GetMapName(), szMapName ) == 0 )
  3721. {
  3722. g_pFileSystem->BeginMapAccess();
  3723. mapscope.bEnabled = true;
  3724. }
  3725. g_pFileSystem->AsyncFinishAll();
  3726. if ( !start )
  3727. startspot = NULL;
  3728. else
  3729. {
  3730. Q_strncpy (_startspot, start, sizeof( _startspot ) );
  3731. startspot = _startspot;
  3732. }
  3733. Warning( "---- Host_Changelevel ----\n" );
  3734. CheckForFlushMemory( sv.GetMapName(), szMapName );
  3735. #if !defined( SWDS )
  3736. // Always save as an xsave if we're on the X360
  3737. saverestore->SetIsXSave( IsX360() );
  3738. // Add on time passed since the last time we kept track till this transition
  3739. int iAdditionalSeconds = g_ServerGlobalVariables.curtime - saverestore->GetMostRecentElapsedTimeSet();
  3740. int iElapsedSeconds = saverestore->GetMostRecentElapsedSeconds() + iAdditionalSeconds;
  3741. int iElapsedMinutes = saverestore->GetMostRecentElapsedMinutes() + ( iElapsedSeconds / 60 );
  3742. saverestore->SetMostRecentElapsedMinutes( iElapsedMinutes );
  3743. saverestore->SetMostRecentElapsedSeconds( ( iElapsedSeconds % 60 ) );
  3744. if ( bTransitionBySave )
  3745. {
  3746. char comment[80];
  3747. // Pass in the total elapsed time so it gets added to the elapsed time for this map.
  3748. serverGameDLL->GetSaveComment(
  3749. comment,
  3750. sizeof( comment ),
  3751. saverestore->GetMostRecentElapsedMinutes(),
  3752. saverestore->GetMostRecentElapsedSeconds() );
  3753. if ( !saverestore->SaveGameSlot( "_transition", comment, false, true, szMapName, startspot ) )
  3754. {
  3755. Warning( "Failed to save data for transition\n" );
  3756. SCR_EndLoadingPlaque();
  3757. return false;
  3758. }
  3759. // Not going to load a save after the transition, so add this map's elapsed time to the total elapsed time
  3760. int totalSeconds = g_ServerGlobalVariables.curtime + saverestore->GetMostRecentElapsedSeconds();
  3761. saverestore->SetMostRecentElapsedMinutes( (int)( totalSeconds / 60.0f ) + saverestore->GetMostRecentElapsedMinutes() );
  3762. saverestore->SetMostRecentElapsedSeconds( (int)fmod( totalSeconds, 60.0f ) );
  3763. }
  3764. #endif
  3765. Q_strncpy( oldlevel, sv.GetMapName(), sizeof( oldlevel ) );
  3766. #if !defined(SWDS)
  3767. if ( loadfromsavedgame )
  3768. {
  3769. if ( !bTransitionBySave )
  3770. {
  3771. // save the current level's state
  3772. saverestore->SaveGameState( true, &pSaveData );
  3773. if ( !pSaveData )
  3774. {
  3775. Warning( "Failed to save data for transition\n" );
  3776. SCR_EndLoadingPlaque();
  3777. return false;
  3778. }
  3779. }
  3780. // ensure resources in the transition volume stay
  3781. AddTransitionResources( pSaveData, szMapName, startspot );
  3782. }
  3783. #endif
  3784. g_pServerPluginHandler->LevelShutdown();
  3785. #if !defined(SWDS)
  3786. audiosourcecache->LevelShutdown();
  3787. #endif
  3788. #if !defined(SWDS)
  3789. saverestore->FinishAsyncSave();
  3790. #endif
  3791. if ( sv.RestartOnLevelChange() )
  3792. {
  3793. Cbuf_Clear();
  3794. Cbuf_AddText( "quit\n" );
  3795. return false;
  3796. }
  3797. DownloadListGenerator().OnLevelLoadStart( szMapName );
  3798. if ( !sv.SpawnServer( szMapName, szMapFile, startspot ) )
  3799. {
  3800. #ifndef SWDS
  3801. SCR_EndLoadingPlaque();
  3802. #endif
  3803. return false;
  3804. }
  3805. #ifndef SWDS
  3806. if ( loadfromsavedgame )
  3807. {
  3808. if ( !bTransitionBySave )
  3809. {
  3810. // Finish saving gamestate
  3811. saverestore->Finish( pSaveData );
  3812. }
  3813. g_ServerGlobalVariables.curtime = sv.GetTime();
  3814. audiosourcecache->LevelInit( szMapName );
  3815. g_pServerPluginHandler->LevelInit( szMapName, CM_EntityString(), oldlevel, startspot, true, false );
  3816. sv.SetPaused( true ); // pause until client connects
  3817. sv.m_bLoadgame = true;
  3818. }
  3819. else
  3820. #endif
  3821. {
  3822. g_ServerGlobalVariables.curtime = sv.GetTime();
  3823. #if !defined(SWDS)
  3824. audiosourcecache->LevelInit( szMapName );
  3825. #endif
  3826. g_pServerPluginHandler->LevelInit( szMapName, CM_EntityString(), NULL, NULL, false, false );
  3827. }
  3828. SV_ActivateServer();
  3829. #if !defined(SWDS)
  3830. // Offset stored elapsed time by the current elapsed time for this new map
  3831. int maptime = sv.GetTime();
  3832. int minutes = (int)( maptime / 60.0f );
  3833. int seconds = (int)fmod( maptime, 60.0f );
  3834. saverestore->SetMostRecentElapsedMinutes( saverestore->GetMostRecentElapsedMinutes() - minutes );
  3835. saverestore->SetMostRecentElapsedSeconds( saverestore->GetMostRecentElapsedSeconds() - seconds );
  3836. #endif
  3837. NotifyDedicatedServerUI("UpdateMap");
  3838. DownloadListGenerator().OnLevelLoadEnd();
  3839. return true;
  3840. }
  3841. /*
  3842. ===============================================================================
  3843. SERVER TRANSITIONS
  3844. ===============================================================================
  3845. */
  3846. bool Host_NewGame( char *mapName, bool loadGame, bool bBackgroundLevel, const char *pszOldMap, const char *pszLandmark, bool bOldSave )
  3847. {
  3848. VPROF( "Host_NewGame" );
  3849. COM_TimestampedLog( "Host_NewGame" );
  3850. char previousMapName[MAX_PATH] = { 0 };
  3851. Q_strncpy( previousMapName, host_map.GetString(), sizeof( previousMapName ) );
  3852. #ifndef SWDS
  3853. SCR_BeginLoadingPlaque();
  3854. #endif
  3855. // The qualified name of the map, excluding path/extension
  3856. char szMapName[MAX_PATH] = { 0 };
  3857. // The file to load the map from.
  3858. char szMapFile[MAX_PATH] = { 0 };
  3859. Q_strncpy( szMapName, mapName, sizeof( szMapName ) );
  3860. Host_DefaultMapFileName( szMapName, szMapFile, sizeof( szMapFile ) );
  3861. // Steam may not have been started yet, ensure it is available to the game DLL before we ask it to prepare level
  3862. // resources
  3863. SV_InitGameServerSteam();
  3864. // Ask serverDLL to prepare this load
  3865. if ( g_iServerGameDLLVersion >= 10 )
  3866. {
  3867. serverGameDLL->PrepareLevelResources( szMapName, sizeof( szMapName ), szMapFile, sizeof( szMapFile ) );
  3868. }
  3869. if ( !modelloader->Map_IsValid( szMapFile ) )
  3870. {
  3871. #ifndef SWDS
  3872. SCR_EndLoadingPlaque();
  3873. #endif
  3874. return false;
  3875. }
  3876. DevMsg( "---- Host_NewGame ----\n" );
  3877. host_map.SetValue( szMapName );
  3878. CheckForFlushMemory( previousMapName, szMapName );
  3879. if (MapReslistGenerator().IsEnabled())
  3880. {
  3881. // uncache all the materials, so their files get referenced again for the reslists
  3882. // undone for now, since we're just trying to get a global reslist, not per-map accurate
  3883. // materials->UncacheAllMaterials();
  3884. MapReslistGenerator().OnLevelLoadStart(szMapName);
  3885. // cache 'em back in!
  3886. // materials->CacheUsedMaterials();
  3887. }
  3888. DownloadListGenerator().OnLevelLoadStart(szMapName);
  3889. if ( !loadGame )
  3890. {
  3891. VPROF( "Host_NewGame_HostState_RunGameInit" );
  3892. HostState_RunGameInit();
  3893. }
  3894. // init network mode
  3895. VPROF_SCOPE_BEGIN( "Host_NewGame_SpawnServer" );
  3896. NET_SetMutiplayer( sv.IsMultiplayer() );
  3897. NET_ListenSocket( sv.m_Socket, true ); // activated server TCP socket
  3898. // let's not have any servers with no name
  3899. if ( host_name.GetString()[0] == 0 )
  3900. {
  3901. host_name.SetValue( serverGameDLL->GetGameDescription() );
  3902. }
  3903. if ( !sv.SpawnServer ( szMapName, szMapFile, NULL ) )
  3904. {
  3905. return false;
  3906. }
  3907. sv.m_bIsLevelMainMenuBackground = bBackgroundLevel;
  3908. VPROF_SCOPE_END();
  3909. // make sure the time is set
  3910. g_ServerGlobalVariables.curtime = sv.GetTime();
  3911. COM_TimestampedLog( "serverGameDLL->LevelInit" );
  3912. #ifndef SWDS
  3913. EngineVGui()->UpdateProgressBar(PROGRESS_LEVELINIT);
  3914. audiosourcecache->LevelInit( szMapName );
  3915. #endif
  3916. g_pServerPluginHandler->LevelInit( szMapName, CM_EntityString(), pszOldMap, pszLandmark, loadGame && !bOldSave, bBackgroundLevel );
  3917. if ( loadGame && !bOldSave )
  3918. {
  3919. sv.SetPaused( true ); // pause until all clients connect
  3920. sv.m_bLoadgame = true;
  3921. g_ServerGlobalVariables.curtime = sv.GetTime();
  3922. }
  3923. if( !SV_ActivateServer() )
  3924. {
  3925. return false;
  3926. }
  3927. // Connect the local client when a "map" command is issued.
  3928. if ( !sv.IsDedicated() )
  3929. {
  3930. COM_TimestampedLog( "Stuff 'connect localhost' to console" );
  3931. char str[512];
  3932. Q_snprintf( str, sizeof( str ), "connect localhost:%d listenserver", sv.GetUDPPort() );
  3933. Cbuf_AddText( str );
  3934. }
  3935. else
  3936. {
  3937. // Dedicated server triggers map load here.
  3938. GetTestScriptMgr()->CheckPoint( "FinishedMapLoad" );
  3939. }
  3940. #ifndef SWDS
  3941. if ( !loadGame || bOldSave )
  3942. {
  3943. // clear the most recent remember save, so the level will just restart if the player dies
  3944. saverestore->ForgetRecentSave();
  3945. }
  3946. saverestore->SetMostRecentElapsedMinutes( 0 );
  3947. saverestore->SetMostRecentElapsedSeconds( 0 );
  3948. #endif
  3949. if (MapReslistGenerator().IsEnabled())
  3950. {
  3951. MapReslistGenerator().OnLevelLoadEnd();
  3952. }
  3953. DownloadListGenerator().OnLevelLoadEnd();
  3954. return true;
  3955. }
  3956. void Host_FreeStateAndWorld( bool server )
  3957. {
  3958. bool bNeedsPurge = false;
  3959. Assert( host_initialized );
  3960. Assert( host_hunklevel );
  3961. // If called by the client and we are running a listen server, just ignore
  3962. if ( !server && sv.IsActive() )
  3963. return;
  3964. // HACKHACK: You can't clear the hunk unless the client data is free
  3965. // since this gets called by the server, it's necessary to wipe the client
  3966. // in case we are on a listen server
  3967. #ifndef SWDS
  3968. if ( server && !sv.IsDedicated() )
  3969. {
  3970. CL_ClearState();
  3971. }
  3972. #endif
  3973. // The world model relies on the low hunk, so we need to force it to unload
  3974. if ( host_state.worldmodel )
  3975. {
  3976. modelloader->UnreferenceModel( host_state.worldmodel, IModelLoader::FMODELLOADER_SERVER );
  3977. modelloader->UnreferenceModel( host_state.worldmodel, IModelLoader::FMODELLOADER_CLIENT );
  3978. host_state.SetWorldModel( NULL );
  3979. bNeedsPurge = server && true;
  3980. }
  3981. // Unload and reset dynamic models
  3982. if ( server )
  3983. {
  3984. extern IVModelInfo* modelinfo;
  3985. modelinfo->OnLevelChange();
  3986. }
  3987. #ifndef SWDS
  3988. else
  3989. {
  3990. extern IVModelInfoClient* modelinfoclient;
  3991. modelinfoclient->OnLevelChange();
  3992. }
  3993. #endif
  3994. modelloader->UnloadUnreferencedModels();
  3995. g_TimeLastMemTest = 0;
  3996. }
  3997. //-----------------------------------------------------------------------------
  3998. // Purpose:
  3999. //-----------------------------------------------------------------------------
  4000. void Host_FreeToLowMark( bool server )
  4001. {
  4002. Assert( host_initialized );
  4003. Assert( host_hunklevel );
  4004. // If called by the client and we are running a listen server, just ignore
  4005. if ( !server && sv.IsActive() )
  4006. return;
  4007. CM_FreeMap();
  4008. if ( host_hunklevel )
  4009. {
  4010. // See if we are going to obliterate any malloc'd pointers
  4011. Hunk_FreeToLowMark(host_hunklevel);
  4012. }
  4013. }
  4014. //-----------------------------------------------------------------------------
  4015. // Purpose:
  4016. //-----------------------------------------------------------------------------
  4017. void Host_Shutdown(void)
  4018. {
  4019. extern void ShutdownMixerControls();
  4020. if ( host_checkheap )
  4021. {
  4022. #ifdef _WIN32
  4023. if ( _heapchk() != _HEAPOK )
  4024. {
  4025. Sys_Error( "Host_Shutdown (top): _heapchk() != _HEAPOK\n" );
  4026. }
  4027. #endif
  4028. }
  4029. // Check for recursive shutdown, should never happen
  4030. static bool shutting_down = false;
  4031. if ( shutting_down )
  4032. {
  4033. Msg( "Recursive shutdown!!!\n" );
  4034. return;
  4035. }
  4036. shutting_down = true;
  4037. phonehome->Message( IPhoneHome::PHONE_MSG_ENGINEEND, NULL );
  4038. phonehome->Shutdown();
  4039. #ifndef SWDS
  4040. // Store active configuration settings
  4041. Host_WriteConfiguration();
  4042. #endif
  4043. // Disconnect from server
  4044. Host_Disconnect(true);
  4045. #ifndef SWDS
  4046. // keep ConMsg from trying to update the screen
  4047. scr_disabled_for_loading = true;
  4048. #endif
  4049. #if defined VOICE_OVER_IP && !defined SWDS && !defined( NO_VOICE ) //!defined(_XBOX)
  4050. Voice_Deinit();
  4051. #endif // VOICE_OVER_IP
  4052. // TODO, Trace this
  4053. CM_FreeMap();
  4054. host_initialized = false;
  4055. #if defined(VPROF_ENABLED)
  4056. VProfRecord_Shutdown();
  4057. #endif
  4058. #if !defined SWDS
  4059. if ( !sv.IsDedicated() )
  4060. {
  4061. TRACESHUTDOWN( Decal_Shutdown() );
  4062. TRACESHUTDOWN( R_Shutdown() );
  4063. TRACESHUTDOWN( SCR_Shutdown() );
  4064. TRACESHUTDOWN( S_Shutdown() );
  4065. TRACESHUTDOWN( ClientDLL_Shutdown() );
  4066. TRACESHUTDOWN( TextMessageShutdown() );
  4067. TRACESHUTDOWN( EngineVGui()->Shutdown() );
  4068. TRACESHUTDOWN( StaticPropMgr()->Shutdown() );
  4069. // Model loader must shutdown before StudioRender
  4070. // because it calls into StudioRender
  4071. TRACESHUTDOWN( modelloader->Shutdown() );
  4072. TRACESHUTDOWN( ShutdownStudioRender() );
  4073. TRACESHUTDOWN( ShutdownMaterialSystem() );
  4074. TRACESHUTDOWN( CL_Shutdown() );
  4075. }
  4076. else
  4077. #endif
  4078. {
  4079. TRACESHUTDOWN( Decal_Shutdown() );
  4080. TRACESHUTDOWN( modelloader->Shutdown() );
  4081. TRACESHUTDOWN( ShutdownStudioRender() );
  4082. TRACESHUTDOWN( StaticPropMgr()->Shutdown() );
  4083. TRACESHUTDOWN( ShutdownMaterialSystem() );
  4084. }
  4085. #if defined( REPLAY_ENABLED )
  4086. if ( Replay_IsSupportedModAndPlatform() )
  4087. {
  4088. TRACESHUTDOWN( ReplaySystem_Shutdown() );
  4089. }
  4090. #endif
  4091. TRACESHUTDOWN( HLTV_Shutdown() );
  4092. TRACESHUTDOWN( g_Log.Shutdown() );
  4093. TRACESHUTDOWN( g_GameEventManager.Shutdown() );
  4094. TRACESHUTDOWN( sv.Shutdown() );
  4095. TRACESHUTDOWN( NET_Shutdown() );
  4096. #ifndef SWDS
  4097. TRACESHUTDOWN( Key_Shutdown() );
  4098. #ifndef _X360
  4099. TRACESHUTDOWN( ShutdownMixerControls() );
  4100. #endif
  4101. #endif
  4102. TRACESHUTDOWN( Filter_Shutdown() );
  4103. #ifndef SWDS
  4104. TRACESHUTDOWN( saverestore->Shutdown() );
  4105. #endif
  4106. TRACESHUTDOWN( COM_Shutdown() );
  4107. // TRACESHUTDOWN( Host_ShutdownVCR() );
  4108. #ifndef SWDS
  4109. TRACESHUTDOWN( V_Shutdown() );
  4110. #endif
  4111. TRACESHUTDOWN( g_pCVar->Shutdown() );
  4112. TRACESHUTDOWN( Cmd_Shutdown() );
  4113. TRACESHUTDOWN( Cbuf_Shutdown() );
  4114. TRACESHUTDOWN( Con_Shutdown() );
  4115. TRACESHUTDOWN( Memory_Shutdown() );
  4116. if ( g_pThreadPool )
  4117. g_pThreadPool->Stop();
  4118. DTI_Term();
  4119. ServerDTI_Term();
  4120. #if defined(_WIN32)
  4121. if ( s_bInitPME )
  4122. {
  4123. ShutdownPME();
  4124. }
  4125. #endif
  4126. if ( host_checkheap )
  4127. {
  4128. #ifdef _WIN32
  4129. if ( _heapchk() != _HEAPOK )
  4130. {
  4131. Sys_Error( "Host_Shutdown (bottom): _heapchk() != _HEAPOK\n" );
  4132. }
  4133. #endif
  4134. }
  4135. }
  4136. //-----------------------------------------------------------------------------
  4137. // Centralize access to enabling QMS.
  4138. //-----------------------------------------------------------------------------
  4139. bool Host_AllowQueuedMaterialSystem( bool bAllow )
  4140. {
  4141. #if !defined DEDICATED
  4142. // g_bAllowThreadedSound = bAllow;
  4143. // NOTE: Moved this to materialsystem for integrating with other mqm changes
  4144. return g_pMaterialSystem->AllowThreading( bAllow, g_nMaterialSystemThread );
  4145. #endif
  4146. return false;
  4147. }