Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3541 lines
108 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #include "server_pch.h"
  9. #include "decal.h"
  10. #include "host_cmd.h"
  11. #include "cmodel_engine.h"
  12. #include "sv_log.h"
  13. #include "zone.h"
  14. #include "sound.h"
  15. #include "vox.h"
  16. #include "EngineSoundInternal.h"
  17. #include "checksum_engine.h"
  18. #include "master.h"
  19. #include "host.h"
  20. #include "keys.h"
  21. #include "vengineserver_impl.h"
  22. #include "sv_filter.h"
  23. #include "pr_edict.h"
  24. #include "screen.h"
  25. #include "sys_dll.h"
  26. #include "world.h"
  27. #include "sv_main.h"
  28. #include "networkstringtableserver.h"
  29. #include "datamap.h"
  30. #include "filesystem_engine.h"
  31. #include "string_t.h"
  32. #include "vstdlib/random.h"
  33. #include "networkstringtable.h"
  34. #include "dt_send_eng.h"
  35. #include "sv_packedentities.h"
  36. #include "testscriptmgr.h"
  37. #include "PlayerState.h"
  38. #include "saverestoretypes.h"
  39. #include "tier0/vprof.h"
  40. #include "proto_oob.h"
  41. #include "staticpropmgr.h"
  42. #include "checksum_crc.h"
  43. #include "console.h"
  44. #include "tier0/icommandline.h"
  45. #include "host_state.h"
  46. #include "gl_matsysiface.h"
  47. #include "GameEventManager.h"
  48. #include "sys.h"
  49. #include "tier3/tier3.h"
  50. #include "voice.h"
  51. #ifndef DEDICATED
  52. #include "vgui_baseui_interface.h"
  53. #endif
  54. #include "cbenchmark.h"
  55. #include "client.h"
  56. #include "hltvserver.h"
  57. #if defined( REPLAY_ENABLED )
  58. #include "replay.h"
  59. #include "replayserver.h"
  60. #include "replayhistorymanager.h"
  61. #endif
  62. #include "keyvalues.h"
  63. #include "sv_logofile.h"
  64. #include "cl_steamauth.h"
  65. #include "sv_steamauth.h"
  66. #include "sv_plugin.h"
  67. #include "DownloadListGenerator.h"
  68. #include "sv_steamauth.h"
  69. #include "LocalNetworkBackdoor.h"
  70. #include "cvar.h"
  71. #include "enginethreads.h"
  72. #include "tier1/functors.h"
  73. #include "vstdlib/jobthread.h"
  74. #include "pure_server.h"
  75. #include "datacache/idatacache.h"
  76. #include "filesystem/IQueuedLoader.h"
  77. #include "vstdlib/jobthread.h"
  78. #include "SourceAppInfo.h"
  79. #include "cl_rcon.h"
  80. #include "toolframework/itoolframework.h"
  81. #include "snd_audio_source.h"
  82. #include "SoundEmitterSystem/isoundemittersystembase.h"
  83. #include "serializedentity.h"
  84. #include "matchmaking/imatchframework.h"
  85. // memdbgon must be the last include file in a .cpp file!!!
  86. #include "tier0/memdbgon.h"
  87. #ifdef _LINUX
  88. #include <syscall.h>
  89. #endif
  90. #ifdef _PS3
  91. #include <sys/memory.h>
  92. #endif
  93. extern CNetworkStringTableContainer *networkStringTableContainerServer;
  94. extern CNetworkStringTableContainer *networkStringTableContainerClient;
  95. extern void Host_EnsureHostNameSet();
  96. void OnHibernateWhenEmptyChanged( IConVar *var, const char *pOldValue, float flOldValue );
  97. extern ConVar deathmatch;
  98. extern ConVar sv_sendtables;
  99. ConVar sv_hibernate_when_empty( "sv_hibernate_when_empty", "1", FCVAR_RELEASE, "Puts the server into extremely low CPU usage mode when no clients connected", OnHibernateWhenEmptyChanged );
  100. ConVar sv_hibernate_punt_tv_clients( "sv_hibernate_punt_tv_clients", "0", FCVAR_RELEASE, "When enabled will punt all GOTV clients during hibernation" );
  101. ConVar sv_hibernate_ms( "sv_hibernate_ms", "20", FCVAR_RELEASE, "# of milliseconds to sleep per frame while hibernating" );
  102. ConVar sv_hibernate_ms_vgui( "sv_hibernate_ms_vgui", "20", FCVAR_RELEASE, "# of milliseconds to sleep per frame while hibernating but running the vgui dedicated server frontend" );
  103. static ConVar sv_hibernate_postgame_delay( "sv_hibernate_postgame_delay", "5", FCVAR_RELEASE, "# of seconds to wait after final client leaves before hibernating.");
  104. ConVar host_flush_threshold( "host_flush_threshold", "12", FCVAR_RELEASE, "Memory threshold below which the host should flush caches between server instances" );
  105. extern ConVar fps_max;
  106. static ConVar sv_pausable_dev( "sv_pausable_dev", IsGameConsole() ? "0" : "1", FCVAR_DEVELOPMENTONLY, "Whether listen server is pausable when running -dev and playing solo against bots" );
  107. static ConVar sv_pausable_dev_ds( "sv_pausable_dev_ds", "0", FCVAR_DEVELOPMENTONLY, "Whether dedicated server is pausable when running -dev and playing solo against bots" );
  108. // Server default maxplayers value
  109. #define DEFAULT_SERVER_CLIENTS 6
  110. // This many players on a Lan with same key, is ok.
  111. #define MAX_IDENTICAL_CDKEYS 5
  112. CGameServer sv;
  113. CGlobalVars g_ServerGlobalVariables( false );
  114. static int current_skill;
  115. extern bool UseCDKeyAuth();
  116. void RevertAllModifiedLocalState()
  117. {
  118. // cheats were disabled, revert all cheat cvars to their default values
  119. g_pCVar->RevertFlaggedConVars( FCVAR_CHEAT );
  120. #ifndef DEDICATED
  121. // Reload all sound mixers that might have been tampered with
  122. extern bool MXR_LoadAllSoundMixers( void );
  123. MXR_LoadAllSoundMixers();
  124. #endif
  125. DevMsg( "FCVAR_CHEAT cvars reverted to defaults.\n" );
  126. extern bool g_bHasIssuedMatSuppressOrDebug;
  127. if ( g_bHasIssuedMatSuppressOrDebug )
  128. {
  129. // Reload all materials in case the user has tried to cheat by using mat_suppress.
  130. if ( materials )
  131. {
  132. materials->ReloadMaterials( NULL );
  133. }
  134. g_bHasIssuedMatSuppressOrDebug = false;
  135. }
  136. }
  137. static void SV_CheatsChanged_f( IConVar *pConVar, const char *pOldString, float flOldValue )
  138. {
  139. if ( IsGameConsole() ) // Cheats are always on for console, don't care reverting convars
  140. return;
  141. ConVarRef var( pConVar );
  142. if ( var.GetInt() == 0 )
  143. {
  144. RevertAllModifiedLocalState();
  145. }
  146. if ( g_pMatchFramework )
  147. {
  148. // Raise an event for other system to notice cheats state being manipulated
  149. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  150. "sv_cheats_changed", "value", var.GetInt() ) );
  151. }
  152. }
  153. static int g_sv_pure_mode = 1; // default to on
  154. static void SV_Pure_f( const CCommand &args )
  155. {
  156. int pure_mode = -1;
  157. if ( args.ArgC() == 2 )
  158. {
  159. pure_mode = atoi( args[1] );
  160. }
  161. Msg( "--------------------------------------------------------\n" );
  162. if ( pure_mode == 0 || pure_mode == 1 || pure_mode == 2 )
  163. {
  164. // you can turn off pure mode after specifying on the command line ( allow 0 here )
  165. int pure_mode_cmd_line = 1; // default is on
  166. if ( CommandLine()->CheckParm("+sv_pure") )
  167. pure_mode_cmd_line = CommandLine()->ParmValue( "+sv_pure", 1 );
  168. else if ( CommandLine()->CheckParm("-sv_pure") )
  169. pure_mode_cmd_line = CommandLine()->ParmValue( "-sv_pure", 1 );
  170. if ( pure_mode_cmd_line == 0 && pure_mode != 0 )
  171. {
  172. // if it wasn't set on the command line
  173. Msg( "sv_pure must be specified on the command line to function properly. sv_pure mode not changed\n" );
  174. return;
  175. }
  176. if ( pure_mode == 2 )
  177. {
  178. Msg( "sv_pure 2 is obsolete. Changed to 1.\n" );
  179. pure_mode = 1;
  180. }
  181. // Set the value.
  182. if ( pure_mode == g_sv_pure_mode )
  183. {
  184. Msg( "sv_pure value unchanged (current value is %d).\n", g_sv_pure_mode );
  185. }
  186. else
  187. {
  188. g_sv_pure_mode = pure_mode;
  189. Msg( "sv_pure set to %d.\n", g_sv_pure_mode );
  190. if ( sv.IsActive() )
  191. {
  192. Msg( "Note: Changes to sv_pure take effect when the next map is loaded.\n" );
  193. }
  194. }
  195. }
  196. else
  197. {
  198. Msg( "sv_pure:"
  199. "\n\nIf set to 1, the server will force all client files except the whitelisted ones "
  200. "(in pure_server_whitelist.txt) to match the server's files. " );
  201. }
  202. if ( pure_mode == -1 )
  203. {
  204. // If we're a client on a server with sv_pure = 1, display the current whitelist.
  205. #ifndef DEDICATED
  206. if ( GetBaseLocalClient().IsConnected() )
  207. {
  208. Msg( "\n\n" );
  209. extern void CL_PrintWhitelistInfo(); // from cl_main.cpp
  210. CL_PrintWhitelistInfo();
  211. }
  212. else
  213. #endif
  214. {
  215. Msg( "\nCurrent sv_pure value is %d.\n", g_sv_pure_mode );
  216. }
  217. }
  218. Msg( "--------------------------------------------------------\n" );
  219. }
  220. static ConCommand sv_pure( "sv_pure", SV_Pure_f, "Show user data." );
  221. ConVar sv_pure_kick_clients( "sv_pure_kick_clients", "1", FCVAR_RELEASE, "If set to 1, the server will kick clients with mismatching files. Otherwise, it will issue a warning to the client." );
  222. ConVar sv_pure_trace( "sv_pure_trace", "0", FCVAR_RELEASE, "If set to 1, the server will print a message whenever a client is verifying a CRC for a file." );
  223. ConVar sv_pure_consensus( "sv_pure_consensus", "99999999", FCVAR_RELEASE, "Minimum number of file hashes to agree to form a consensus." );
  224. ConVar sv_pure_retiretime( "sv_pure_retiretime", "900", FCVAR_RELEASE, "Seconds of server idle time to flush the sv_pure file hash cache." );
  225. ConVar sv_cheats( "sv_cheats", "0", FCVAR_NOTIFY|FCVAR_REPLICATED | FCVAR_RELEASE, "Allow cheats on server", SV_CheatsChanged_f );
  226. ConVar sv_lan( "sv_lan", "0", FCVAR_RELEASE, "Server is a lan server ( no heartbeat, no authentication, no non-class C addresses )" );
  227. static ConVar sv_pausable( "sv_pausable","0", FCVAR_RELEASE, "Is the server pausable." );
  228. static ConVar sv_contact( "sv_contact", "", FCVAR_NOTIFY | FCVAR_RELEASE, "Contact email for server sysop" );
  229. static ConVar sv_cacheencodedents("sv_cacheencodedents", "1", 0, "If set to 1, does an optimization to prevent extra SendTable_Encode calls.");
  230. ConVar sv_voicecodec("sv_voicecodec", "vaudio_celt", FCVAR_RELEASE | FCVAR_REPLICATED, "Specifies which voice codec DLL to use in a game. Set to the name of the DLL without the extension.");
  231. static ConVar sv_voiceenable( "sv_voiceenable", "1", FCVAR_ARCHIVE|FCVAR_NOTIFY | FCVAR_RELEASE ); // set to 0 to disable all voice forwarding.
  232. ConVar sv_downloadurl( "sv_downloadurl", "", FCVAR_REPLICATED | FCVAR_RELEASE, "Location from which clients can download missing files" );
  233. ConVar sv_consistency( "sv_consistency", "0", FCVAR_REPLICATED | FCVAR_RELEASE, "Whether the server enforces file consistency for critical files" );
  234. ConVar sv_maxreplay("sv_maxreplay", "0", 0, "Maximum replay time in seconds", true, 0, true, 30 );
  235. ConVar sv_mincmdrate( "sv_mincmdrate", "64", FCVAR_REPLICATED | FCVAR_RELEASE, "This sets the minimum value for cl_cmdrate. 0 == unlimited." );
  236. ConVar sv_maxcmdrate( "sv_maxcmdrate", "64", FCVAR_REPLICATED, "(If sv_mincmdrate is > 0), this sets the maximum value for cl_cmdrate." );
  237. ConVar sv_client_cmdrate_difference( "sv_client_cmdrate_difference", "0", FCVAR_REPLICATED | FCVAR_RELEASE,
  238. "cl_cmdrate is moved to within sv_client_cmdrate_difference units of cl_updaterate before it "
  239. "is clamped between sv_mincmdrate and sv_maxcmdrate." );
  240. ConVar sv_client_min_interp_ratio( "sv_client_min_interp_ratio", "1", FCVAR_REPLICATED,
  241. "This can be used to limit the value of cl_interp_ratio for connected clients "
  242. "(only while they are connected).\n"
  243. " -1 = let clients set cl_interp_ratio to anything\n"
  244. " any other value = set minimum value for cl_interp_ratio"
  245. );
  246. ConVar sv_client_max_interp_ratio( "sv_client_max_interp_ratio", "5", FCVAR_REPLICATED,
  247. "This can be used to limit the value of cl_interp_ratio for connected clients "
  248. "(only while they are connected). If sv_client_min_interp_ratio is -1, "
  249. "then this cvar has no effect."
  250. );
  251. ConVar sv_client_predict( "sv_client_predict", "-1", FCVAR_REPLICATED,
  252. "This can be used to force the value of cl_predict for connected clients "
  253. "(only while they are connected).\n"
  254. " -1 = let clients set cl_predict to anything\n"
  255. " 0 = force cl_predict to 0\n"
  256. " 1 = force cl_predict to 1"
  257. );
  258. void OnTVEnablehanged( IConVar *pConVar, const char *pOldString, float flOldValue )
  259. {
  260. ConVarRef var( pConVar );
  261. //Let's check maxclients and make sure we have room for SourceTV
  262. if ( var.GetBool() == true )
  263. {
  264. sv.InitMaxClients();
  265. }
  266. }
  267. ConVar tv_enable( "tv_enable", "0", FCVAR_NOTIFY | FCVAR_RELEASE, "Activates GOTV on server (0=off;1=on;2=on when reserved)", OnTVEnablehanged );
  268. ConVar tv_enable1( "tv_enable1", "0", FCVAR_NOTIFY | FCVAR_RELEASE, "Activates GOTV[1] on server (0=off;1=on;2=on when reserved)", OnTVEnablehanged );
  269. extern ConVar *sv_noclipduringpause;
  270. static bool s_bForceSend = false;
  271. void SV_ForceSend()
  272. {
  273. s_bForceSend = true;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Set the flush trigger.
  277. //-----------------------------------------------------------------------------
  278. bool g_bFlushMemoryOnNextServer;
  279. int g_FlushMemoryOnNextServerCounter;
  280. void SV_FlushMemoryOnNextServer()
  281. {
  282. g_bFlushMemoryOnNextServer = true;
  283. g_FlushMemoryOnNextServerCounter++;
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Check and possibly set the flush trigger.
  287. //-----------------------------------------------------------------------------
  288. void SV_CheckForFlushMemory( const char *pCurrentMapName, const char *pDestMapName )
  289. {
  290. #ifdef _GAMECONSOLE
  291. if ( host_flush_threshold.GetInt() == 0 )
  292. return;
  293. // There are three cases in which we flush memory
  294. // Case 1: changing from one map to another
  295. // -> flush temp data caches
  296. // Case 2: loading any map (inc. A to A) and free memory is below host_flush_threshold MB
  297. // -> flush everything
  298. // Case 3: loading a 'blacklisted' map (the known biggest memory users, or where texture sets change)
  299. // -> flush everything
  300. static const char *mapBlackList[] =
  301. {
  302. ""
  303. };
  304. char szCurrentMapName[MAX_PATH];
  305. char szDestMapName[MAX_PATH];
  306. if ( pCurrentMapName )
  307. {
  308. V_FileBase( pCurrentMapName, szCurrentMapName, sizeof( szCurrentMapName ) );
  309. }
  310. else
  311. {
  312. szCurrentMapName[0] = '\0';
  313. }
  314. pCurrentMapName = szCurrentMapName;
  315. if ( pDestMapName )
  316. {
  317. V_FileBase( pDestMapName, szDestMapName, sizeof( szDestMapName ) );
  318. }
  319. else
  320. {
  321. szDestMapName[0] = '\0';
  322. }
  323. pDestMapName = szDestMapName;
  324. bool bIsMapChanging = pCurrentMapName[0] && V_stricmp( pCurrentMapName, pDestMapName );
  325. bool bIsDestMapBlacklisted = false;
  326. for ( int i = 0; i < ARRAYSIZE( mapBlackList ); i++ )
  327. {
  328. if ( pDestMapName && !V_stricmp( pDestMapName, mapBlackList[i] ) )
  329. {
  330. bIsDestMapBlacklisted = true;
  331. }
  332. }
  333. size_t dwSizePhysical = 0xffffffff;
  334. #ifdef _WIN32
  335. {
  336. MEMORYSTATUS stat;
  337. GlobalMemoryStatus( &stat );
  338. dwSizePhysical = stat.dwAvailPhys;
  339. }
  340. #elif defined( _PS3 )
  341. {
  342. sys_memory_info_t smi = {0,0};
  343. sys_memory_get_user_memory_size( &smi );
  344. dwSizePhysical = smi.available_user_memory;
  345. }
  346. #endif
  347. // console csgo wants a full flush always for fragmentation concerns
  348. bool bFullFlush = ( ( dwSizePhysical < host_flush_threshold.GetInt() * 1024 * 1024 ) || ( bIsDestMapBlacklisted && bIsMapChanging ) ) || ( IsGameConsole() && !V_stricmp( COM_GetModDirectory(), "csgo" ) );
  349. bool bPartialFlush = !bFullFlush && bIsMapChanging;
  350. const char *pReason = "No Flush";
  351. if ( bFullFlush )
  352. {
  353. // Flush everything; all map data should get reloaded
  354. SV_FlushMemoryOnNextServer();
  355. g_pDataCache->Flush();
  356. wavedatacache->Flush();
  357. pReason = "Full Flush";
  358. }
  359. else if ( bPartialFlush )
  360. {
  361. // Flush temporary data (async anim, non-locked async audio)
  362. g_pMDLCache->Flush( MDLCACHE_FLUSH_ANIMBLOCK );
  363. wavedatacache->Flush();
  364. pReason = "Partial Flush";
  365. }
  366. Msg( "Current Map: (%s), Next Map: (%s), %s\n", (pCurrentMapName[0] ? pCurrentMapName : ""), (pDestMapName[0] ? pDestMapName : ""), pReason );
  367. #endif // console
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Returns true if flush occured, false otherwise.
  371. //-----------------------------------------------------------------------------
  372. bool SV_FlushMemoryIfMarked()
  373. {
  374. if ( g_bFlushMemoryOnNextServer )
  375. {
  376. g_bFlushMemoryOnNextServer = false;
  377. if ( IsGameConsole() )
  378. {
  379. g_pQueuedLoader->PurgeAll();
  380. }
  381. g_pDataCache->Flush();
  382. g_pMaterialSystem->CompactMemory();
  383. g_pFileSystem->AsyncFinishAll();
  384. #if !defined( DEDICATED )
  385. extern CThreadMutex g_SndMutex;
  386. g_SndMutex.Lock();
  387. g_pFileSystem->AsyncSuspend();
  388. g_pThreadPool->SuspendExecution();
  389. g_pMemAlloc->CompactHeap();
  390. g_pThreadPool->ResumeExecution();
  391. g_pFileSystem->AsyncResume();
  392. g_SndMutex.Unlock();
  393. #endif // DEDICATED
  394. return true;
  395. }
  396. else
  397. {
  398. g_pMemAlloc->CompactHeap();
  399. if ( IsPlatformOpenGL() )
  400. {
  401. // Frees all memory associated with models and their material
  402. // This function is usually called at the end of loading but on OSX we are calling
  403. // it before loading the next level in an attempt to free as much memory as possible.
  404. // Could easily get over the 4GB virtual mem limit when transition from cs_thunder to
  405. // de_cbble for example.
  406. modelloader->PurgeUnusedModels();
  407. }
  408. }
  409. return false;
  410. }
  411. // Prints important entity creation/deletion events to console
  412. #if defined( _DEBUG )
  413. ConVar sv_deltatrace( "sv_deltatrace", "0", 0, "For debugging, print entity creation/deletion info to console." );
  414. #define TRACE_DELTA( text ) if ( sv_deltatrace.GetInt() ) { ConMsg( text ); };
  415. #else
  416. #define TRACE_DELTA( funcs )
  417. #endif
  418. #if defined( DEBUG_NETWORKING )
  419. //-----------------------------------------------------------------------------
  420. // Opens the recording file
  421. //-----------------------------------------------------------------------------
  422. static FILE* OpenRecordingFile()
  423. {
  424. FILE* fp = 0;
  425. static bool s_CantOpenFile = false;
  426. static bool s_NeverOpened = true;
  427. if (!s_CantOpenFile)
  428. {
  429. fp = fopen( "svtrace.txt", s_NeverOpened ? "wt" : "at" );
  430. if (!fp)
  431. {
  432. s_CantOpenFile = true;
  433. }
  434. s_NeverOpened = false;
  435. }
  436. return fp;
  437. }
  438. //-----------------------------------------------------------------------------
  439. // Records an argument for a command, flushes when the command is done
  440. //-----------------------------------------------------------------------------
  441. /*
  442. void SpewToFile( char const* pFmt, ... )
  443. static void SpewToFile( const char* pFmt, ... )
  444. {
  445. static CUtlVector<unsigned char> s_RecordingBuffer;
  446. char temp[2048];
  447. va_list args;
  448. va_start( args, pFmt );
  449. int len = Q_vsnprintf( temp, sizeof( temp ), pFmt, args );
  450. va_end( args );
  451. Assert( len < 2048 );
  452. int idx = s_RecordingBuffer.AddMultipleToTail( len );
  453. memcpy( &s_RecordingBuffer[idx], temp, len );
  454. if ( 1 ) //s_RecordingBuffer.Size() > 8192)
  455. {
  456. FILE* fp = OpenRecordingFile();
  457. fwrite( s_RecordingBuffer.Base(), 1, s_RecordingBuffer.Size(), fp );
  458. fclose( fp );
  459. s_RecordingBuffer.RemoveAll();
  460. }
  461. }
  462. */
  463. #endif // #if defined( DEBUG_NETWORKING )
  464. /*void SV_Init(bool isDedicated)
  465. {
  466. sv.Init( isDedicated );
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose:
  470. //-----------------------------------------------------------------------------
  471. void SV_Shutdown( void )
  472. {
  473. sv.Shutdown();
  474. }*/
  475. void CGameServer::Clear( void )
  476. {
  477. m_pModelPrecacheTable = NULL;
  478. m_pDynamicModelTable = NULL;
  479. m_pGenericPrecacheTable = NULL;
  480. m_pSoundPrecacheTable = NULL;
  481. m_pDecalPrecacheTable = NULL;
  482. m_bIsLevelMainMenuBackground = false;
  483. m_bLoadgame = false;
  484. host_state.SetWorldModel( NULL );
  485. Q_memset( m_szStartspot, 0, sizeof( m_szStartspot ) );
  486. num_edicts = 0;
  487. max_edicts = 0;
  488. edicts = NULL;
  489. g_ServerGlobalVariables.maxEntities = 0;
  490. g_ServerGlobalVariables.pEdicts = NULL;
  491. // Clear the instance baseline indices in the ServerClasses.
  492. if ( serverGameDLL )
  493. {
  494. for( ServerClass *pCur = serverGameDLL->GetAllServerClasses(); pCur; pCur=pCur->m_pNext )
  495. {
  496. pCur->m_InstanceBaselineIndex = INVALID_STRING_INDEX;
  497. }
  498. }
  499. for ( int i = 0; i < m_TempEntities.Count(); i++ )
  500. {
  501. delete m_TempEntities[i];
  502. }
  503. m_TempEntities.Purge();
  504. BaseClass::Clear();
  505. }
  506. //-----------------------------------------------------------------------------
  507. // Purpose: Create any client/server string tables needed internally by the engine
  508. //-----------------------------------------------------------------------------
  509. ASSERT_INVARIANT( ABSOLUTE_PLAYER_LIMIT <= 2048 ); // must be reasonable number that has a power-of-2 value not less than it
  510. void CGameServer::CreateEngineStringTables( void )
  511. {
  512. int i,j;
  513. m_StringTables->SetTick( m_nTickCount ); // set first tick
  514. int fileFlags = NSF_DICTIONARY_ENABLED;
  515. m_pDownloadableFileTable = m_StringTables->CreateStringTable(
  516. DOWNLOADABLE_FILE_TABLENAME,
  517. MAX_DOWNLOADABLE_FILES,
  518. 0,
  519. 0,
  520. fileFlags );
  521. m_pModelPrecacheTable = m_StringTables->CreateStringTable(
  522. MODEL_PRECACHE_TABLENAME,
  523. MAX_MODELS,
  524. sizeof ( CPrecacheUserData ),
  525. PRECACHE_USER_DATA_NUMBITS,
  526. fileFlags );
  527. m_pGenericPrecacheTable = m_StringTables->CreateStringTable(
  528. GENERIC_PRECACHE_TABLENAME,
  529. MAX_GENERIC,
  530. sizeof ( CPrecacheUserData ),
  531. PRECACHE_USER_DATA_NUMBITS,
  532. fileFlags );
  533. m_pSoundPrecacheTable = m_StringTables->CreateStringTable(
  534. SOUND_PRECACHE_TABLENAME,
  535. MAX_SOUNDS,
  536. sizeof ( CPrecacheUserData ),
  537. PRECACHE_USER_DATA_NUMBITS,
  538. fileFlags );
  539. m_pDecalPrecacheTable = m_StringTables->CreateStringTable(
  540. DECAL_PRECACHE_TABLENAME,
  541. MAX_BASE_DECALS,
  542. sizeof ( CPrecacheUserData ),
  543. PRECACHE_USER_DATA_NUMBITS,
  544. fileFlags );
  545. m_pInstanceBaselineTable = m_StringTables->CreateStringTable(
  546. INSTANCE_BASELINE_TABLENAME,
  547. MAX_DATATABLES );
  548. m_pLightStyleTable = m_StringTables->CreateStringTable(
  549. LIGHT_STYLES_TABLENAME,
  550. MAX_LIGHTSTYLES );
  551. int nAbsolutePlayerLimitPowerOf2 = 1;
  552. while ( nAbsolutePlayerLimitPowerOf2 < ABSOLUTE_PLAYER_LIMIT )
  553. nAbsolutePlayerLimitPowerOf2 <<= 1;
  554. m_pUserInfoTable = m_StringTables->CreateStringTable(
  555. USER_INFO_TABLENAME,
  556. nAbsolutePlayerLimitPowerOf2 );
  557. m_pDynamicModelTable = m_StringTables->CreateStringTable(
  558. DYNAMIC_MODEL_TABLENAME,
  559. MAX_MODELS,
  560. 1, // Single bit of userdata: is this model loaded on the server yet
  561. 1 );
  562. // Send the query info..
  563. m_pServerStartupTable = m_StringTables->CreateStringTable(
  564. SERVER_STARTUP_DATA_TABLENAME,
  565. 4 );
  566. SetQueryPortFromSteamServer();
  567. CopyPureServerWhitelistToStringTable();
  568. Assert ( m_pModelPrecacheTable &&
  569. m_pGenericPrecacheTable &&
  570. m_pSoundPrecacheTable &&
  571. m_pDecalPrecacheTable &&
  572. m_pInstanceBaselineTable &&
  573. m_pLightStyleTable &&
  574. m_pUserInfoTable &&
  575. m_pServerStartupTable &&
  576. m_pDownloadableFileTable );
  577. // create an empty lightstyle table with unique index names
  578. for ( i = 0; i<MAX_LIGHTSTYLES; i++ )
  579. {
  580. char name[8]; Q_snprintf( name, 8, "%i", i );
  581. j = m_pLightStyleTable->AddString( true, name );
  582. Assert( j==i ); // indices must match
  583. }
  584. for ( i = 0; i<ABSOLUTE_PLAYER_LIMIT; i++ )
  585. {
  586. char name[8]; Q_snprintf( name, 8, "%i", i );
  587. j = m_pUserInfoTable->AddString( true, name );
  588. Assert( j==i ); // indices must match
  589. }
  590. // set up the downloadable files generator
  591. DownloadListGenerator().SetStringTable( m_pDownloadableFileTable );
  592. }
  593. void CGameServer::SetQueryPortFromSteamServer()
  594. {
  595. if ( !m_pServerStartupTable )
  596. return;
  597. int queryPort = Steam3Server().GetQueryPort();
  598. m_pServerStartupTable->AddString( true, "QueryPort", sizeof( queryPort ), &queryPort );
  599. }
  600. void CGameServer::CopyPureServerWhitelistToStringTable()
  601. {
  602. if ( !m_pPureServerWhitelist )
  603. return;
  604. CUtlBuffer buf;
  605. m_pPureServerWhitelist->Encode( buf );
  606. m_pServerStartupTable->AddString( true, "PureServerWhitelist", buf.TellPut(), buf.Base() );
  607. }
  608. void SV_InstallClientStringTableMirrors( void )
  609. {
  610. #ifndef DEDICATED
  611. #ifndef SHARED_NET_STRING_TABLES
  612. int numTables = networkStringTableContainerServer->GetNumTables();
  613. for ( int i =0; i<numTables; i++)
  614. {
  615. // iterate through server tables
  616. CNetworkStringTable *serverTable =
  617. (CNetworkStringTable*)networkStringTableContainerServer->GetTable( i );
  618. if ( !serverTable )
  619. continue;
  620. // get mathcing client table
  621. CNetworkStringTable *clientTable =
  622. (CNetworkStringTable*)networkStringTableContainerClient->FindTable( serverTable->GetTableName() );
  623. if ( !clientTable )
  624. {
  625. DevMsg("SV_InstallClientStringTableMirrors! Missing client table \"%s\".\n ", serverTable->GetTableName() );
  626. continue;
  627. }
  628. // link client table to server table
  629. serverTable->SetMirrorTable( 0, clientTable );
  630. }
  631. #endif
  632. #endif
  633. }
  634. //-----------------------------------------------------------------------------
  635. // user <name or userid>
  636. //
  637. // Dump userdata / masterdata for a user
  638. //-----------------------------------------------------------------------------
  639. CON_COMMAND( user, "Show user data." )
  640. {
  641. int uid;
  642. int i;
  643. if ( !sv.IsActive() )
  644. {
  645. ConMsg( "Can't 'user', not running a server\n" );
  646. return;
  647. }
  648. if (args.ArgC() != 2)
  649. {
  650. ConMsg ("Usage: user <username / userid>\n");
  651. return;
  652. }
  653. uid = atoi(args[1]);
  654. for (i=0 ; i< sv.GetClientCount() ; i++)
  655. {
  656. IClient *cl = sv.GetClient( i );
  657. if ( !cl->IsConnected() )
  658. continue;
  659. if ( ( cl->GetPlayerSlot()== uid ) || !Q_strcmp( cl->GetClientName(), args[1]) )
  660. {
  661. ConMsg ("TODO: SV_User_f.\n");
  662. return;
  663. }
  664. }
  665. ConMsg ("User not in server.\n");
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Dump userids for all current players
  669. //-----------------------------------------------------------------------------
  670. CON_COMMAND( users, "Show user info for players on server." )
  671. {
  672. if ( !sv.IsActive() )
  673. {
  674. ConMsg( "Can't 'users', not running a server\n" );
  675. return;
  676. }
  677. int c = 0;
  678. ConMsg ("<slot:userid:\"name\">\n");
  679. for ( int i=0 ; i< sv.GetClientCount() ; i++ )
  680. {
  681. IClient *cl = sv.GetClient( i );
  682. if ( cl->IsConnected() )
  683. {
  684. ConMsg ("%i:%i:\"%s\"\n", cl->GetPlayerSlot(), cl->GetUserID(), cl->GetClientName() );
  685. c++;
  686. }
  687. }
  688. ConMsg ( "%i users\n", c );
  689. }
  690. //-----------------------------------------------------------------------------
  691. // Purpose: Determine the value of sv.maxclients
  692. //-----------------------------------------------------------------------------
  693. bool CL_IsHL2Demo(); // from cl_main.cpp
  694. bool CL_IsPortalDemo(); // from cl_main.cpp
  695. void CGameServer::InitMaxClients( void )
  696. {
  697. int minmaxplayers = 1;
  698. int maxmaxplayers = ABSOLUTE_PLAYER_LIMIT;
  699. int defaultmaxplayers = 1;
  700. if ( serverGameClients )
  701. {
  702. serverGameClients->GetPlayerLimits( minmaxplayers, maxmaxplayers, defaultmaxplayers );
  703. if ( minmaxplayers < 1 )
  704. {
  705. Sys_Error( "GetPlayerLimits: min maxplayers must be >= 1 (%i)", minmaxplayers );
  706. }
  707. else if ( defaultmaxplayers < 1 )
  708. {
  709. Sys_Error( "GetPlayerLimits: default maxplayers must be >= 1 (%i)", minmaxplayers );
  710. }
  711. if ( minmaxplayers > maxmaxplayers || defaultmaxplayers > maxmaxplayers )
  712. {
  713. Sys_Error( "GetPlayerLimits: min maxplayers %i > max %i", minmaxplayers, maxmaxplayers );
  714. }
  715. if ( maxmaxplayers > ABSOLUTE_PLAYER_LIMIT )
  716. {
  717. Sys_Error( "GetPlayerLimits: max players limited to %i", ABSOLUTE_PLAYER_LIMIT );
  718. }
  719. }
  720. // Determine absolute limit
  721. m_nMinClientsLimit = minmaxplayers;
  722. m_nMaxClientsLimit = maxmaxplayers;
  723. // Check for command line override
  724. #if defined( CSTRIKE15 )
  725. int newmaxplayers = -HLTV_SERVER_MAX_COUNT; // CStrike doesn't allow command line override for maxplayers
  726. #else
  727. int newmaxplayers = CommandLine()->ParmValue( "-maxplayers", -1 );
  728. #endif
  729. for ( int nHltvServerIndex = 0; nHltvServerIndex < HLTV_SERVER_MAX_COUNT; ++nHltvServerIndex )
  730. {
  731. #if defined( REPLAY_ENABLED )
  732. if ( GetIndexedConVar( tv_enable, nHltvServerIndex ).GetBool() || Replay_IsEnabled() )
  733. #else
  734. if ( GetIndexedConVar( tv_enable, nHltvServerIndex ).GetBool() )
  735. #endif
  736. {
  737. newmaxplayers += 1;
  738. m_nMaxClientsLimit += 1;
  739. }
  740. }
  741. if ( newmaxplayers >= 1 )
  742. {
  743. // Never go above/below what the game .dll can handle
  744. newmaxplayers = MIN( newmaxplayers, maxmaxplayers );
  745. m_nMaxClientsLimit = MAX( m_nMinClientsLimit, newmaxplayers );
  746. }
  747. else
  748. {
  749. newmaxplayers = defaultmaxplayers;
  750. }
  751. newmaxplayers = clamp( newmaxplayers, m_nMinClientsLimit, m_nMaxClientsLimit );
  752. if ( ( CL_IsHL2Demo() || CL_IsPortalDemo() ) && !IsDedicated() )
  753. {
  754. newmaxplayers = 1;
  755. m_nMinClientsLimit = 1;
  756. m_nMaxClientsLimit = 1;
  757. }
  758. SetMaxClients( newmaxplayers );
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Purpose: Changes the maximum # of players allowed on the server.
  762. // Server cannot be running when command is issued.
  763. //-----------------------------------------------------------------------------
  764. CON_COMMAND( maxplayers, "Change the maximum number of players allowed on this server." )
  765. {
  766. #if defined( CSTRIKE15 )
  767. ConMsg( "Maxplayers is deprecated, set it in gamemodes_server.txt.example or use -maxplayers_override instead.\n");
  768. return;
  769. #endif
  770. if ( args.ArgC () != 2 )
  771. {
  772. ConMsg ("\"maxplayers\" is \"%u\"\n", sv.GetMaxClients() );
  773. if ( serverGameClients )
  774. {
  775. int minmaxplayers = 1;
  776. int maxmaxplayers = 1;
  777. int defaultmaxplayers = 1;
  778. serverGameClients->GetPlayerLimits( minmaxplayers, maxmaxplayers, defaultmaxplayers );
  779. ConMsg ("\"mininum_maxplayers\" is \"%u\"\n", minmaxplayers );
  780. ConMsg ("\"absolute_maxplayers\" is \"%u\"\n", maxmaxplayers );
  781. ConMsg ("\"default_maxplayers\" is \"%u\"\n", defaultmaxplayers );
  782. #ifndef DEDICATED
  783. if ( toolframework->InToolMode() )
  784. {
  785. ConMsg ("\"max_splitscreen_players\" is \"%u\" (limited by -tools mode)\n", host_state.max_splitscreen_players );
  786. }
  787. else
  788. #endif
  789. {
  790. ConMsg ("\"max_splitscreen_players\" is \"%u\"\n", host_state.max_splitscreen_players );
  791. }
  792. }
  793. return;
  794. }
  795. // Allow maxplayers to change if server is hibernating so matchmaking servers can switch to accomodate different
  796. // player limits for different game modes.
  797. if ( sv.IsActive() && !sv.IsHibernating() )
  798. {
  799. ConMsg( "Maxplayers can only be changed while server is hibernating.\n");
  800. return;
  801. }
  802. sv.SetMaxClients( Q_atoi( args[ 1 ] ) );
  803. }
  804. int SV_BuildSendTablesArray( ServerClass *pClasses, SendTable **pTables, int nMaxTables )
  805. {
  806. int nTables = 0;
  807. for( ServerClass *pCur=pClasses; pCur; pCur=pCur->m_pNext )
  808. {
  809. ErrorIfNot( nTables < nMaxTables, ("SV_BuildSendTablesArray: too many SendTables!") );
  810. pTables[nTables] = pCur->m_pTable;
  811. ++nTables;
  812. }
  813. return nTables;
  814. }
  815. // Builds an alternate copy of the datatable for any classes that have datatables with props excluded.
  816. void SV_InitSendTables( ServerClass *pClasses )
  817. {
  818. SendTable *pTables[MAX_DATATABLES];
  819. int nTables = SV_BuildSendTablesArray( pClasses, pTables, ARRAYSIZE( pTables ) );
  820. SendTable_Init( pTables, nTables );
  821. }
  822. void SV_TermSendTables( ServerClass *pClasses )
  823. {
  824. SendTable_Term();
  825. }
  826. //-----------------------------------------------------------------------------
  827. // Purpose: returns which games/mods we're allowed to play
  828. //-----------------------------------------------------------------------------
  829. struct ModDirPermissions_t
  830. {
  831. int m_iAppID;
  832. const char *m_pchGameDir;
  833. };
  834. static ModDirPermissions_t g_ModDirPermissions[] =
  835. {
  836. { GetAppSteamAppId( k_App_CSS ), GetAppModName( k_App_CSS ) },
  837. { GetAppSteamAppId( k_App_DODS ), GetAppModName( k_App_DODS ) },
  838. { GetAppSteamAppId( k_App_HL2MP ), GetAppModName( k_App_HL2MP ) },
  839. { GetAppSteamAppId( k_App_LOST_COAST ), GetAppModName( k_App_LOST_COAST ) },
  840. { GetAppSteamAppId( k_App_HL1DM ), GetAppModName( k_App_HL1DM ) },
  841. { GetAppSteamAppId( k_App_PORTAL ), GetAppModName( k_App_PORTAL ) },
  842. { GetAppSteamAppId( k_App_HL2 ), GetAppModName( k_App_HL2 ) },
  843. { GetAppSteamAppId( k_App_HL2_EP1 ), GetAppModName( k_App_HL2_EP1 ) },
  844. { GetAppSteamAppId( k_App_HL2_EP2 ), GetAppModName( k_App_HL2_EP2 ) },
  845. { GetAppSteamAppId( k_App_TF2 ), GetAppModName( k_App_TF2 ) },
  846. { GetAppSteamAppId( k_App_L4D ), GetAppModName( k_App_L4D ) },
  847. };
  848. bool ServerDLL_Load( bool bServerOnly )
  849. {
  850. // Load in the game .dll
  851. LoadEntityDLLs( GetBaseDirectory(), bServerOnly );
  852. return g_ServerFactory != NULL;
  853. }
  854. void ServerDLL_Unload()
  855. {
  856. UnloadEntityDLLs();
  857. }
  858. //-----------------------------------------------------------------------------
  859. // Purpose: Loads the game .dll
  860. //-----------------------------------------------------------------------------
  861. void SV_InitGameDLL( void )
  862. {
  863. COM_TimestampedLog( "SV_InitGameDLL" );
  864. SV_SetSteamCrashComment();
  865. // Clear out the command buffer.
  866. Cbuf_Execute();
  867. // Don't initialize a second time
  868. if ( sv.dll_initialized )
  869. {
  870. return;
  871. }
  872. #if !defined(DEDICATED) && !defined( _GAMECONSOLE )
  873. bool CL_IsHL2Demo();
  874. if ( CL_IsHL2Demo() && !sv.IsDedicated() && Q_stricmp( COM_GetModDirectory(), "hl2" ) )
  875. {
  876. Error( "The HL2 demo is unable to run Mods.\n" );
  877. return;
  878. }
  879. if ( CL_IsPortalDemo() && !sv.IsDedicated() && Q_stricmp( COM_GetModDirectory(), "portal" ) )
  880. {
  881. Error( "The Portal demo is unable to run Mods.\n" );
  882. return;
  883. }
  884. // check permissions
  885. if ( Steam3Client().SteamApps() && g_pFileSystem->IsSteam() && !CL_IsHL2Demo() && !CL_IsPortalDemo() )
  886. {
  887. bool bVerifiedMod = false;
  888. // find the game dir we're running
  889. for ( int i = 0; i < ARRAYSIZE( g_ModDirPermissions ); i++ )
  890. {
  891. if ( !Q_stricmp( COM_GetModDirectory(), g_ModDirPermissions[i].m_pchGameDir ) )
  892. {
  893. // we've found the mod, make sure we own the app
  894. if ( Steam3Client().SteamApps()->BIsSubscribedApp( g_ModDirPermissions[i].m_iAppID ) )
  895. {
  896. bVerifiedMod = true;
  897. }
  898. else
  899. {
  900. Error( "No permissions to run '%s'\n", COM_GetModDirectory() );
  901. return;
  902. }
  903. break;
  904. }
  905. }
  906. if ( !bVerifiedMod )
  907. {
  908. // make sure they can run the Source engine
  909. if ( ! Steam3Client().SteamApps()->BIsSubscribedApp( 215 ) )
  910. {
  911. Error( "A Source engine game is required to run mods\n" );
  912. return;
  913. }
  914. }
  915. }
  916. #endif
  917. if ( !serverGameDLL )
  918. {
  919. Warning( "Failed to load server binary\n" );
  920. return;
  921. }
  922. // Flag that we've started the game .dll
  923. sv.dll_initialized = true;
  924. COM_TimestampedLog( "serverGameDLL->DLLInit - Start" );
  925. // Tell the game DLL to start up
  926. if ( !serverGameDLL->DLLInit( g_GameSystemFactory, g_AppSystemFactory, g_AppSystemFactory, &g_ServerGlobalVariables ) )
  927. {
  928. Sys_Error( "serverGameDLL->DLLInit() failed.\n");
  929. }
  930. COM_TimestampedLog( "serverGameDLL->DLLInit - Finish" );
  931. if ( CommandLine()->FindParm( "-NoLoadPluginsForClient" ) == 0 )
  932. g_pServerPluginHandler->LoadPlugins(); // load 3rd party plugins
  933. // let's not have any servers with no name
  934. Host_EnsureHostNameSet();
  935. sv_noclipduringpause = ( ConVar * )g_pCVar->FindVar( "sv_noclipduringpause" );
  936. COM_TimestampedLog( "SV_InitSendTables" );
  937. // Make extra copies of data tables if they have SendPropExcludes.
  938. SV_InitSendTables( serverGameDLL->GetAllServerClasses() );
  939. host_state.interval_per_tick = serverGameDLL->GetTickInterval();
  940. if ( host_state.interval_per_tick < MINIMUM_TICK_INTERVAL ||
  941. host_state.interval_per_tick > MAXIMUM_TICK_INTERVAL )
  942. {
  943. Sys_Error( "GetTickInterval returned bogus tick interval (%f)[%f to %f is valid range]", host_state.interval_per_tick,
  944. MINIMUM_TICK_INTERVAL, MAXIMUM_TICK_INTERVAL );
  945. }
  946. extern ConVar sv_maxupdaterate;
  947. sv_maxupdaterate.SetValue(1.0f / host_state.interval_per_tick);
  948. sv_maxcmdrate.SetValue(1.0f / host_state.interval_per_tick);
  949. host_state.max_splitscreen_players_clientdll = clamp( serverGameClients->GetMaxSplitscreenPlayers(), 1, MAX_SPLITSCREEN_CLIENTS );
  950. host_state.max_splitscreen_players = host_state.max_splitscreen_players_clientdll;
  951. if ( CommandLine()->CheckParm( "-tools" ) )
  952. {
  953. Msg( "Clamping split screen users to 1 due to -tools mode\n" );
  954. host_state.max_splitscreen_players = 1;
  955. }
  956. if ( host_state.max_splitscreen_players > 1 )
  957. {
  958. Msg( "Game supporting (%d) split screen players\n", host_state.max_splitscreen_players );
  959. }
  960. g_pCVar->SetMaxSplitScreenSlots( host_state.max_splitscreen_players );
  961. // set maxclients limit based on Mod or commandline settings
  962. sv.InitMaxClients();
  963. // Execute and server commands the game .dll added at startup
  964. Cbuf_Execute();
  965. }
  966. //
  967. // Release resources associated with extension DLLs.
  968. //
  969. void SV_ShutdownGameDLL( void )
  970. {
  971. if ( !sv.dll_initialized )
  972. {
  973. return;
  974. }
  975. // Delete any extra SendTable copies we've attached to the game DLL's classes, if any.
  976. SV_TermSendTables( serverGameDLL->GetAllServerClasses() );
  977. g_pServerPluginHandler->UnloadPlugins();
  978. serverGameDLL->DLLShutdown();
  979. UnloadEntityDLLs();
  980. sv.dll_initialized = false;
  981. // Shutdown the steam interfaces
  982. Steam3Server().Shutdown();
  983. }
  984. static bool s_bExitWhenEmpty = false;
  985. static void sv_ShutDownMsg( char const *szReason )
  986. {
  987. s_bExitWhenEmpty = true;
  988. extern char const *g_szHostStateDelayedMessage;
  989. g_szHostStateDelayedMessage = szReason;
  990. if ( sv.IsHibernating() && !sv.IsReserved() )
  991. {
  992. HostState_Shutdown();
  993. }
  994. }
  995. static void sv_ShutDown( void )
  996. {
  997. if ( sv.IsHibernating() && !sv.IsReserved() )
  998. {
  999. sv_ShutDownMsg( "sv_shutdown hibernating server right now." );
  1000. }
  1001. else
  1002. {
  1003. sv_ShutDownMsg( "sv_shutdown live server, delaying request." );
  1004. }
  1005. }
  1006. bool sv_ShutDown_WasRequested( void )
  1007. {
  1008. return s_bExitWhenEmpty;
  1009. }
  1010. static ConCommand sv_shutdown( "sv_shutdown", sv_ShutDown, "Sets the server to shutdown when all games have completed", FCVAR_RELEASE );
  1011. ServerClass* SV_FindServerClass( const char *pName )
  1012. {
  1013. ServerClass *pCur = serverGameDLL->GetAllServerClasses();
  1014. while ( pCur )
  1015. {
  1016. if ( Q_stricmp( pCur->GetName(), pName ) == 0 )
  1017. return pCur;
  1018. pCur = pCur->m_pNext;
  1019. }
  1020. return NULL;
  1021. }
  1022. ServerClass* SV_FindServerClass( int index )
  1023. {
  1024. ServerClass *pCur = serverGameDLL->GetAllServerClasses();
  1025. int count = 0;
  1026. while ( (count < index) && (pCur != NULL) )
  1027. {
  1028. count++;
  1029. pCur = pCur->m_pNext;
  1030. }
  1031. return pCur;
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. // Purpose: General initialization of the server
  1035. //-----------------------------------------------------------------------------
  1036. void CGameServer::Init (bool isDedicated)
  1037. {
  1038. BaseClass::Init( isDedicated );
  1039. m_FullSendTables.SetDebugName( "m_FullSendTables" );
  1040. dll_initialized = false;
  1041. if ( isDedicated )
  1042. {
  1043. // if dedicated server, hibernate until first client connects
  1044. UpdateHibernationState( );
  1045. }
  1046. // Install signal handlers for the dedicated server
  1047. #ifdef POSIX
  1048. if ( isDedicated )
  1049. {
  1050. signal( SIGINT,
  1051. [](int) -> void
  1052. {
  1053. char const *szMsg;
  1054. if ( sv.IsHibernating() && !sv.IsReserved() )
  1055. {
  1056. szMsg = "SIGINT received, hibernating server, shutting down now.";
  1057. }
  1058. else
  1059. {
  1060. szMsg = "SIGINT received, live server, delaying request.";
  1061. }
  1062. sv_ShutDownMsg( szMsg );
  1063. }
  1064. );
  1065. signal( SIGTERM,
  1066. [](int) -> void
  1067. {
  1068. extern char const *g_szHostStateDelayedMessage;
  1069. g_szHostStateDelayedMessage = "SIGTERM received, forcing immediate shutdown.";
  1070. HostState_Shutdown();
  1071. }
  1072. );
  1073. }
  1074. #endif
  1075. }
  1076. bool CGameServer::IsPausable( void ) const
  1077. {
  1078. if ( IsSinglePlayerGame() )
  1079. return true;
  1080. // In developer mode when there are no remote clients connected
  1081. // allow the server to be pausable too
  1082. if ( !NET_IsDedicated() && sv_pausable_dev.GetBool() && developer.GetInt() && IsPlayingSoloAgainstBots() )
  1083. return true;
  1084. if ( NET_IsDedicated() && sv_pausable_dev_ds.GetBool() && developer.GetInt() && IsPlayingSoloAgainstBots() )
  1085. return true;
  1086. // Normally only single player game can be pausable,
  1087. // but we allow if sv_pausable is set on the server:
  1088. return sv_pausable.GetBool();
  1089. }
  1090. void CGameServer::Shutdown( void )
  1091. {
  1092. m_bIsLevelMainMenuBackground = false;
  1093. if ( IGameEvent *event = g_GameEventManager.CreateEvent( "server_pre_shutdown" ) )
  1094. {
  1095. event->SetString( "reason", "quit" );
  1096. g_GameEventManager.FireEvent( event );
  1097. }
  1098. BaseClass::Shutdown();
  1099. // Actually performs a shutdown.
  1100. framesnapshotmanager->LevelChanged();
  1101. if ( IGameEvent *event = g_GameEventManager.CreateEvent( "server_shutdown" ) )
  1102. {
  1103. event->SetString( "reason", "quit" );
  1104. g_GameEventManager.FireEvent( event );
  1105. }
  1106. // Log_Printf( "Server shutdown.\n" );
  1107. g_Log.Close();
  1108. }
  1109. /*
  1110. ==================
  1111. SV_StartSound
  1112. Each entity can have eight independant sound sources, like voice,
  1113. weapon, feet, etc.
  1114. Channel 0 is an auto-allocate channel, the others override anything
  1115. already running on that entity/channel pair.
  1116. An attenuation of 0 will play full volume everywhere in the level.
  1117. Larger attenuations will drop off. (max 4 attenuation)
  1118. Pitch should be PITCH_NORM (100) for no pitch shift. Values over 100 (up to 255)
  1119. shift pitch higher, values lower than 100 lower the pitch.
  1120. ==================
  1121. */
  1122. void SV_StartSound ( IRecipientFilter& filter, edict_t *pSoundEmittingEntity, int iChannel,
  1123. const char *pSoundEntry, HSOUNDSCRIPTHASH iSoundEntryHash, const char *pSample, float flVolume, soundlevel_t iSoundLevel, int iFlags,
  1124. int iPitch, const Vector *pOrigin, float soundtime, int speakerentity, CUtlVector< Vector >* pUtlVecOrigins, int nSeed )
  1125. {
  1126. SoundInfo_t sound;
  1127. sound.SetDefault();
  1128. sound.nEntityIndex = pSoundEmittingEntity ? NUM_FOR_EDICT( pSoundEmittingEntity ) : 0;
  1129. sound.nChannel = iChannel;
  1130. sound.fVolume = flVolume;
  1131. sound.Soundlevel = iSoundLevel;
  1132. sound.nFlags = iFlags;
  1133. sound.nPitch = iPitch;
  1134. sound.nSpeakerEntity = speakerentity;
  1135. sound.nRandomSeed = nSeed;
  1136. // just for debug spew
  1137. sound.pszName = pSoundEntry;
  1138. if ( iFlags & SND_STOP )
  1139. {
  1140. Assert( filter.IsReliable() );
  1141. }
  1142. // Compute the sound origin
  1143. if ( pOrigin )
  1144. {
  1145. VectorCopy( *pOrigin, sound.vOrigin );
  1146. }
  1147. else if ( pSoundEmittingEntity )
  1148. {
  1149. IServerEntity *serverEntity = pSoundEmittingEntity->GetIServerEntity();
  1150. if ( serverEntity )
  1151. {
  1152. CM_WorldSpaceCenter( serverEntity->GetCollideable(), &sound.vOrigin );
  1153. }
  1154. }
  1155. // Add actual sound origin to vector if requested
  1156. if ( pUtlVecOrigins )
  1157. {
  1158. (*pUtlVecOrigins).AddToTail( sound.vOrigin );
  1159. }
  1160. // set sound delay
  1161. if ( soundtime != 0.0f )
  1162. {
  1163. // add one tick since server time ends at the current tick
  1164. // we'd rather delay sounds slightly than skip the beginning samples
  1165. // so add one tick of latency
  1166. soundtime += sv.GetTickInterval();
  1167. sound.fTickTime = sv.GetFinalTickTime();
  1168. sound.fDelay = soundtime - sv.GetFinalTickTime();
  1169. sound.nFlags |= SND_DELAY;
  1170. #if 0
  1171. static float lastSoundTime = 0;
  1172. Msg("SV: [%.3f] Play %s at %.3f\n", soundtime - lastSoundTime, pSample, soundtime );
  1173. lastSoundTime = soundtime;
  1174. #endif
  1175. }
  1176. // find precache number for sound
  1177. // if this is a sentence, get sentence number
  1178. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  1179. {
  1180. sound.bIsSentence = true;
  1181. sound.nSoundNum = Q_atoi( PSkipSoundChars(pSample) );
  1182. if ( sound.nSoundNum >= VOX_SentenceCount() )
  1183. {
  1184. ConMsg("SV_StartSound: invalid sentence number: %s", PSkipSoundChars(pSample));
  1185. return;
  1186. }
  1187. }
  1188. else
  1189. {
  1190. sound.bIsSentence = false;
  1191. if( sound.nFlags & SND_IS_SCRIPTHANDLE )
  1192. {
  1193. sound.nSoundNum = iSoundEntryHash;
  1194. }
  1195. else
  1196. {
  1197. sound.nSoundNum = sv.LookupSoundIndex( pSample );
  1198. if ( !sound.nSoundNum || !sv.GetSound( sound.nSoundNum ) )
  1199. {
  1200. ConMsg ("SV_StartSound: %s not precached (%d)\n", pSample, sound.nSoundNum );
  1201. return;
  1202. }
  1203. }
  1204. }
  1205. // now sound message is complete, send to clients in filter
  1206. sv.BroadcastSound( sound, filter );
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. // Purpose: Sets bits of playerbits based on valid multicast recipients
  1210. // Input : usepas -
  1211. // origin -
  1212. // playerbits -
  1213. //-----------------------------------------------------------------------------
  1214. void SV_DetermineMulticastRecipients( bool usepas, const Vector& origin, CPlayerBitVec& playerbits )
  1215. {
  1216. // determine cluster for origin
  1217. int cluster = CM_LeafCluster( CM_PointLeafnum( origin ) );
  1218. byte pvs[MAX_MAP_LEAFS/8];
  1219. int visType = usepas ? DVIS_PAS : DVIS_PVS;
  1220. const byte *pMask = CM_Vis( pvs, sizeof(pvs), cluster, visType );
  1221. playerbits.ClearAll();
  1222. // Check for relevent clients
  1223. for (int i = 0; i < sv.GetClientCount(); i++ )
  1224. {
  1225. CGameClient *pClient = sv.Client( i );
  1226. if ( !pClient->IsActive() )
  1227. continue;
  1228. // HACK: Should above also check pClient->spawned instead of this
  1229. if ( !pClient->edict || pClient->edict->IsFree() || pClient->edict->GetUnknown() == NULL )
  1230. continue;
  1231. // Always add the HLTV or Replay client
  1232. #if defined( REPLAY_ENABLED )
  1233. if ( pClient->IsHLTV() || pClient->IsReplay() )
  1234. #else
  1235. if ( pClient->IsHLTV() )
  1236. #endif
  1237. {
  1238. playerbits.Set( i );
  1239. continue;
  1240. }
  1241. Vector vecEarPosition;
  1242. serverGameClients->ClientEarPosition( pClient->edict, &vecEarPosition );
  1243. int iBitNumber = CM_LeafCluster( CM_PointLeafnum( vecEarPosition ) );
  1244. if ( !(pMask[iBitNumber>>3] & (1<<(iBitNumber&7)) ) )
  1245. continue;
  1246. if ( pClient->IsSplitScreenUser() )
  1247. {
  1248. playerbits.Set( pClient->m_pAttachedTo->GetPlayerSlot() );
  1249. continue;
  1250. }
  1251. playerbits.Set( i );
  1252. }
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // Purpose: Write single ConVar change to all connected clients
  1256. // Input : *var -
  1257. // *newValue -
  1258. //-----------------------------------------------------------------------------
  1259. void SV_ReplicateConVarChange( ConVar const *var, const char *newValue )
  1260. {
  1261. Assert( var );
  1262. Assert( var->IsFlagSet( FCVAR_REPLICATED ) );
  1263. Assert( newValue );
  1264. if ( !sv.IsActive() || !sv.IsMultiplayer() )
  1265. return;
  1266. CNETMsg_SetConVar_t cvarMsg( var->GetName(), Host_CleanupConVarStringValue( newValue ) );
  1267. sv.BroadcastMessage( cvarMsg );
  1268. }
  1269. //-----------------------------------------------------------------------------
  1270. // Purpose: Execute a command on all clients or a particular client
  1271. // Input : *var -
  1272. // *newValue -
  1273. //-----------------------------------------------------------------------------
  1274. void SV_ExecuteRemoteCommand( const char *pCommand, int nClientSlot )
  1275. {
  1276. if ( !sv.IsActive() || !sv.IsMultiplayer() )
  1277. return;
  1278. CNETMsg_StringCmd_t cmdMsg( pCommand );
  1279. if ( nClientSlot >= 0 )
  1280. {
  1281. CEngineSingleUserFilter filter( nClientSlot + 1, true );
  1282. sv.BroadcastMessage( cmdMsg, filter );
  1283. }
  1284. else
  1285. {
  1286. sv.BroadcastMessage( cmdMsg );
  1287. }
  1288. }
  1289. /*
  1290. ==============================================================================
  1291. CLIENT SPAWNING
  1292. ==============================================================================
  1293. */
  1294. CGameServer::CGameServer()
  1295. {
  1296. m_nMinClientsLimit = 0;
  1297. m_nMaxClientsLimit = 0;
  1298. m_pPureServerWhitelist = NULL;
  1299. m_bHibernating = false;
  1300. m_bLoadedPlugins = false;
  1301. m_bUpdateHibernationStateDeferred = false;
  1302. }
  1303. CGameServer::~CGameServer()
  1304. {
  1305. if ( m_pPureServerWhitelist )
  1306. {
  1307. m_pPureServerWhitelist->Release();
  1308. }
  1309. }
  1310. //-----------------------------------------------------------------------------
  1311. // Purpose: Disconnects the client and cleans out the m_pEnt CBasePlayer container object
  1312. // Input : *clientedict -
  1313. //-----------------------------------------------------------------------------
  1314. void CGameServer::RemoveClientFromGame( CBaseClient *client )
  1315. {
  1316. CGameClient *cl = (CGameClient*)client;
  1317. // we must have an active server and a spawned client
  1318. if ( !cl->edict || !cl->IsSpawned() || !IsActive() )
  1319. return;
  1320. Assert( g_pServerPluginHandler );
  1321. g_pServerPluginHandler->ClientDisconnect( cl->edict );
  1322. // release the DLL entity that's attached to this edict, if any
  1323. serverGameEnts->FreeContainingEntity( cl->edict );
  1324. }
  1325. CBaseClient *CGameServer::CreateNewClient(int slot )
  1326. {
  1327. CBaseClient *cl = new CGameClient( slot, this );
  1328. const char *pszValue = NULL;
  1329. if ( cl && CommandLine()->CheckParm( "-netspike", &pszValue ) &&
  1330. pszValue )
  1331. {
  1332. cl->SetTraceThreshold( Q_atoi( pszValue ) );
  1333. }
  1334. return cl;
  1335. }
  1336. /*
  1337. ================
  1338. SV_FinishCertificateCheck
  1339. For LAN connections, make sure we don't have too many people with same cd key hash
  1340. For Authenticated net connections, check the certificate and also double check won userid
  1341. from that certificate
  1342. ================
  1343. */
  1344. bool CGameServer::FinishCertificateCheck( netadr_t &adr, int nAuthProtocol, const char *szRawCertificate )
  1345. {
  1346. // Now check auth information
  1347. switch ( nAuthProtocol )
  1348. {
  1349. default:
  1350. case PROTOCOL_AUTHCERTIFICATE:
  1351. RejectConnection( adr, "Authentication disabled!!!\n");
  1352. return false;
  1353. case PROTOCOL_STEAM:
  1354. return true; // the SteamAuthServer() state machine checks this
  1355. break;
  1356. case PROTOCOL_HASHEDCDKEY:
  1357. if ( !UseCDKeyAuth() )
  1358. {
  1359. RejectConnection( adr, "#Valve_Reject_CD_Key_Auth_Invalid" );
  1360. return false;
  1361. }
  1362. if ( Q_strlen( szRawCertificate ) != 32 )
  1363. {
  1364. RejectConnection( adr, "#Valve_Reject_Invalid_CD_Key" );
  1365. return false;
  1366. }
  1367. int nHashCount = 0;
  1368. // Now make sure that this hash isn't "overused"
  1369. for ( int i=0; i< GetClientCount(); i++ )
  1370. {
  1371. CBaseClient *cl = Client(i);
  1372. if ( !cl->IsConnected() )
  1373. continue;
  1374. if ( Q_strnicmp ( szRawCertificate, cl->m_GUID, SIGNED_GUID_LEN ) )
  1375. continue;
  1376. nHashCount++;
  1377. }
  1378. if ( nHashCount >= MAX_IDENTICAL_CDKEYS )
  1379. {
  1380. RejectConnection( adr, "#Valve_Reject_CD_Key_In_Use" );
  1381. return false;
  1382. }
  1383. break;
  1384. }
  1385. return true;
  1386. }
  1387. /*
  1388. =============================================================================
  1389. The PVS must include a small area around the client to allow head bobbing
  1390. or other small motion on the client side. Otherwise, a bob might cause an
  1391. entity that should be visible to not show up, especially when the bob
  1392. crosses a waterline.
  1393. =============================================================================
  1394. */
  1395. static int s_FatBytes;
  1396. static byte* s_pFatPVS = 0;
  1397. CUtlVector<int> g_AreasNetworked;
  1398. CUtlVector<int> g_ClustersNetworked;
  1399. static void SV_AddToFatPVS( int nClusterIndex )
  1400. {
  1401. int i;
  1402. byte pvs[MAX_MAP_LEAFS/8];
  1403. CM_Vis( pvs, sizeof(pvs), nClusterIndex, DVIS_PVS );
  1404. int nLastInt = s_FatBytes & (~3);
  1405. for ( i = 0; i < nLastInt; i +=4 )
  1406. {
  1407. uint *pOut = (uint *)(s_pFatPVS + i);
  1408. uint *pIn = (uint *)(pvs + i);
  1409. *pOut |= *pIn;
  1410. }
  1411. for (; i<s_FatBytes ; i++)
  1412. {
  1413. s_pFatPVS[i] |= pvs[i];
  1414. }
  1415. }
  1416. //-----------------------------------------------------------------------------
  1417. // Purpose: Zeroes out pvs, this way we can or together multiple pvs's for a player
  1418. //-----------------------------------------------------------------------------
  1419. void SV_ResetPVS( byte* pvs, int nPVSSize )
  1420. {
  1421. s_pFatPVS = pvs;
  1422. s_FatBytes = Bits2Bytes(CM_NumClusters());
  1423. if ( s_FatBytes > nPVSSize )
  1424. {
  1425. Sys_Error( "SV_ResetPVS: Size %i too big for buffer %i\n", s_FatBytes, nPVSSize );
  1426. }
  1427. Q_memset (s_pFatPVS, 0, s_FatBytes);
  1428. g_ClustersNetworked.RemoveAll();
  1429. g_AreasNetworked.RemoveAll();
  1430. }
  1431. /*
  1432. =============
  1433. Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
  1434. given point.
  1435. =============
  1436. */
  1437. void SV_AddOriginToPVS( const Vector& vOrigin )
  1438. {
  1439. int nLeafIndex = CM_PointLeafnum( vOrigin );
  1440. int nClusterIndex = CM_LeafCluster( nLeafIndex );
  1441. // already included this cluster in the PVS?
  1442. if ( g_ClustersNetworked.Find( nClusterIndex ) != -1 )
  1443. return;
  1444. // mark as included
  1445. g_ClustersNetworked.AddToTail( nClusterIndex );
  1446. SV_AddToFatPVS( nClusterIndex );
  1447. int nArea = CM_LeafArea( nLeafIndex );
  1448. if ( g_AreasNetworked.Find( nArea ) != -1 )
  1449. return;
  1450. g_AreasNetworked.AddToTail( nArea );
  1451. }
  1452. void CGameServer::BroadcastSound( SoundInfo_t &sound, IRecipientFilter &filter )
  1453. {
  1454. int num = filter.GetRecipientCount();
  1455. // don't add sounds while paused, unless we're in developer mode
  1456. if ( IsPaused() && !developer.GetInt() )
  1457. return;
  1458. for ( int i = 0; i < num; i++ )
  1459. {
  1460. int index = filter.GetRecipientIndex( i );
  1461. if ( index < 1 || index > GetClientCount() )
  1462. {
  1463. Msg( "CGameServer::BroadcastSound: Recipient Filter for sound (reliable: %s, init: %s) with bogus client index (%i) in list of %i clients\n",
  1464. filter.IsReliable() ? "yes" : "no",
  1465. filter.IsInitMessage() ? "yes" : "no",
  1466. index, num );
  1467. continue;
  1468. }
  1469. CGameClient *cl = Client( index - 1 );
  1470. // client must be fully connect to hear sounds
  1471. if ( !cl->IsActive() )
  1472. {
  1473. continue;
  1474. }
  1475. cl->SendSound( sound, filter.IsReliable() );
  1476. }
  1477. }
  1478. bool CGameServer::IsInPureServerMode() const
  1479. {
  1480. return (m_pPureServerWhitelist != NULL);
  1481. }
  1482. CPureServerWhitelist * CGameServer::GetPureServerWhitelist() const
  1483. {
  1484. return m_pPureServerWhitelist;
  1485. }
  1486. void OnHibernateWhenEmptyChanged( IConVar *var, const char *pOldValue, float flOldValue )
  1487. {
  1488. // We only need to do something special if we were preventing hibernation
  1489. // with sv_hibernate_when_empty but we would otherwise have been hibernating.
  1490. // In that case, punt all connected clients.
  1491. sv.UpdateHibernationState( );
  1492. }
  1493. bool CGameServer::IsHibernating() const
  1494. {
  1495. return m_bHibernating;
  1496. }
  1497. void Heartbeat_f();
  1498. static ConVar sv_memlimit( "sv_memlimit", "0", FCVAR_RELEASE,
  1499. "If set, whenever a game ends, if the total memory used by the server is "
  1500. "greater than this # of megabytes, the server will exit." );
  1501. static ConVar sv_minuptimelimit( "sv_minuptimelimit", "0", FCVAR_RELEASE,
  1502. "If set, whenever a game ends, if the server uptime is less than "
  1503. "this number of hours, the server will continue running regardless of sv_memlimit." );
  1504. static ConVar sv_maxuptimelimit( "sv_maxuptimelimit", "0", FCVAR_RELEASE,
  1505. "If set, whenever a game ends, if the server uptime exceeds "
  1506. "this number of hours, the server will exit." );
  1507. #if 0
  1508. static void sv_WasteMemory( void )
  1509. {
  1510. uint8 *pWastedRam = new uint8[ 100 * 1024 * 1024 ];
  1511. memset( pWastedRam, 0xff, 100 * 1024 * 1024 ); // make sure it gets committed
  1512. Msg( "waste 100mb. using %dMB with an sv_memory_limit of %dMB\n", ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1513. }
  1514. static ConCommand sv_wastememory( "sv_wastememory", sv_WasteMemory, "Causes the server to allocate 100MB of ram and never free it", FCVAR_CHEAT );
  1515. #endif
  1516. void CGameServer::SetHibernating( bool bHibernating )
  1517. {
  1518. static bool s_bPlatFloatTimeInitialized = false;
  1519. static double s_flPlatFloatTimeBeginUptime = 0.0;
  1520. if ( !s_bPlatFloatTimeInitialized )
  1521. {
  1522. s_bPlatFloatTimeInitialized = true;
  1523. s_flPlatFloatTimeBeginUptime = Plat_FloatTime();
  1524. }
  1525. if ( m_bHibernating != bHibernating )
  1526. {
  1527. m_bHibernating = bHibernating;
  1528. Msg( m_bHibernating ? "Server is hibernating\n" : "Server waking up from hibernation\n" );
  1529. if ( m_bHibernating )
  1530. {
  1531. // if we are hibernating we also might want to punt all GOTV clients
  1532. if ( sv_hibernate_punt_tv_clients.GetBool() )
  1533. {
  1534. for ( CHltvServerIterator hltv; hltv; hltv.Next() )
  1535. {
  1536. hltv->Shutdown();
  1537. }
  1538. }
  1539. // see if we have any other connected bot clients
  1540. for ( int iClient = 0; iClient < m_Clients.Count(); iClient++ )
  1541. {
  1542. CBaseClient *pClient = m_Clients[iClient];
  1543. if ( pClient->IsFakeClient() && pClient->IsConnected() && !pClient->IsSplitScreenUser() )
  1544. {
  1545. pClient->Disconnect( "Punting bot, server is hibernating" );
  1546. }
  1547. }
  1548. // if we are hibernating, and we want to quit, quit
  1549. bool bExit = false;
  1550. if ( sv_ShutDown_WasRequested() )
  1551. {
  1552. bExit = true;
  1553. Warning( "Server shutting down because sv_shutdown was done and a game has ended.\n" );
  1554. }
  1555. else
  1556. {
  1557. // Also check to see if we're supposed to restart on level change due to being out of date.
  1558. // Catches the cases where the server is out of date on first launch and when players
  1559. // connect and then disconnected without ever changing levels.
  1560. if ( sv.RestartOnLevelChange() )
  1561. {
  1562. bExit = true;
  1563. Warning( "Server is shutting down to update.");
  1564. }
  1565. if ( sv_memlimit.GetInt() )
  1566. {
  1567. if ( ApproximateProcessMemoryUsage() > 1024 * 1024 * sv_memlimit.GetInt() )
  1568. {
  1569. if ( ( sv_minuptimelimit.GetFloat() > 0 ) &&
  1570. ( ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 < sv_minuptimelimit.GetFloat() ) )
  1571. {
  1572. Warning( "Server is using %dMB with an sv_memory_limit of %dMB, but will not shutdown because sv_minuptimelimit is %.3f hr while current uptime is %.3f\n",
  1573. ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt(),
  1574. sv_minuptimelimit.GetFloat(), ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 );
  1575. }
  1576. else
  1577. {
  1578. Warning( "Server shutting down because of using %dMB with an sv_memory_limit of %dMB\n", ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1579. bExit = true;
  1580. }
  1581. }
  1582. }
  1583. if ( ( sv_maxuptimelimit.GetFloat() > 0 ) &&
  1584. ( ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 > sv_maxuptimelimit.GetFloat() ) )
  1585. {
  1586. Warning( "Server will shutdown because sv_maxuptimelimit is %.3f hr while current uptime is %.3f, using %dMB with an sv_memory_limit of %dMB\n",
  1587. sv_maxuptimelimit.GetFloat(), ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0,
  1588. ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1589. bExit = true;
  1590. }
  1591. }
  1592. #ifdef _LINUX
  1593. // if we are a child process running forked, we want to exit now. We want to "really" exit. no destructors, no nothing
  1594. if ( IsChildProcess() ) // are we a subprocess?
  1595. {
  1596. syscall( SYS_exit, 0 ); // we are not going to perform a normal c++ exit. We _dont_ want to run destructors, etc.
  1597. }
  1598. #endif
  1599. if ( bExit )
  1600. {
  1601. HostState_Shutdown();
  1602. }
  1603. ResetGameConVarsToDefaults();
  1604. // Reset gametype based on map
  1605. ExecGameTypeCfg( m_szMapname );
  1606. SetReservationCookie( 0u, "SetHibernating(true)" );
  1607. m_flReservationExpiryTime = 0.0f;
  1608. }
  1609. UpdateGameData();
  1610. // Force a heartbeat to update the master servers
  1611. Heartbeat_f();
  1612. if ( serverGameDLL )
  1613. serverGameDLL->ServerHibernationUpdate( m_bHibernating );
  1614. SV_SetSteamCrashComment();
  1615. }
  1616. }
  1617. void CGameServer::UpdateReservedState()
  1618. {
  1619. if ( m_bUpdateHibernationStateDeferred )
  1620. {
  1621. m_bUpdateHibernationStateDeferred = false;
  1622. UpdateHibernationState();
  1623. }
  1624. CBaseServer::UpdateReservedState();
  1625. }
  1626. void CGameServer::UpdateHibernationStateDeferred()
  1627. {
  1628. m_bUpdateHibernationStateDeferred = true;
  1629. }
  1630. void CGameServer::UpdateHibernationState()
  1631. {
  1632. if ( !IsDedicated() )
  1633. return;
  1634. // is this the last client disconnecting?
  1635. bool bHaveAnyClients = false;
  1636. // see if we have any other connected clients
  1637. for ( int iClient = 0; iClient < m_Clients.Count(); iClient++ )
  1638. {
  1639. CBaseClient *pClient = m_Clients[ iClient ];
  1640. // don't consider the client being removed, it still shows as connected but won't be in a moment
  1641. if ( pClient->IsConnected() && ( pClient->IsSplitScreenUser() || !pClient->IsFakeClient() ) )
  1642. {
  1643. bHaveAnyClients = true;
  1644. break;
  1645. }
  1646. }
  1647. float flMaxDirectorDelay = 0.0f;
  1648. // if we are a relay that has an active reservation then hold off from hibernating
  1649. // as long as we are connected
  1650. for ( CActiveHltvServerIterator hltv; hltv; hltv.Next() )
  1651. {
  1652. if ( hltv->IsTVRelay() )
  1653. {
  1654. bHaveAnyClients = true;
  1655. }
  1656. else
  1657. {
  1658. if ( ( hltv->m_nGlobalClients > 0 ) || hltv->m_Broadcast.IsRecording() )
  1659. {
  1660. flMaxDirectorDelay = Max( flMaxDirectorDelay, hltv->GetDirector()->GetDelay() );
  1661. }
  1662. }
  1663. }
  1664. bool bSufficientTimeWithoutClients = false;
  1665. if ( bHaveAnyClients )
  1666. {
  1667. // Clear timer
  1668. m_flTimeLastClientLeft = -1.0f;
  1669. }
  1670. else
  1671. {
  1672. if ( IsReserved() )
  1673. {
  1674. if ( m_flTimeLastClientLeft == -1.0f )
  1675. {
  1676. // Start timer
  1677. m_flTimeLastClientLeft = Plat_FloatTime();
  1678. }
  1679. // Check timer
  1680. float flElapsed = Plat_FloatTime() - m_flTimeLastClientLeft;
  1681. // If we have connected TV clients then reduce the elapsed time by tv delay
  1682. flElapsed -= flMaxDirectorDelay;
  1683. if ( flElapsed > sv_hibernate_postgame_delay.GetFloat() )
  1684. {
  1685. // Act like we still have some clients
  1686. bSufficientTimeWithoutClients = true;
  1687. // If game server requests to hold reservation for longer then don't unreserve
  1688. if ( serverGameDLL && serverGameDLL->ShouldHoldGameServerReservation( flElapsed ) )
  1689. bSufficientTimeWithoutClients = false;
  1690. }
  1691. }
  1692. }
  1693. // If we had some clients and now don't, unreserve right away.
  1694. if ( IsReserved() &&
  1695. !bHaveAnyClients &&
  1696. bSufficientTimeWithoutClients &&
  1697. ( m_flReservationExpiryTime == 0.0f || m_flReservationExpiryTime < net_time ) )
  1698. {
  1699. SetReservationCookie( 0ull, "reserved(%s), clients(%s), reservationexpires(%.2f)",
  1700. IsReserved() ? "yes" : "no", bHaveAnyClients ? "yes" : "no", m_flReservationExpiryTime );
  1701. //
  1702. // Automatically stop recording on Valve official servers
  1703. // when the server gets unreserved
  1704. //
  1705. if ( serverGameDLL && serverGameDLL->IsValveDS() )
  1706. {
  1707. for ( CHltvServerIterator hltv; hltv; hltv.Next() )
  1708. {
  1709. if ( hltv->IsRecording() )
  1710. {
  1711. hltv->StopRecording( );
  1712. }
  1713. }
  1714. }
  1715. }
  1716. SetHibernating( sv_hibernate_when_empty.GetBool() && !IsReserved() && !bHaveAnyClients );
  1717. }
  1718. void CGameServer::FinishRestore()
  1719. {
  1720. #ifndef DEDICATED
  1721. CSaveRestoreData currentLevelData;
  1722. char name[MAX_OSPATH];
  1723. if ( !m_bLoadgame )
  1724. return;
  1725. g_ServerGlobalVariables.pSaveData = &currentLevelData;
  1726. // Build the adjacent map list
  1727. serverGameDLL->BuildAdjacentMapList();
  1728. if ( !saverestore->IsXSave() )
  1729. {
  1730. Q_snprintf( name, sizeof( name ), "%s%s.HL2", saverestore->GetSaveDir(), m_szMapname );
  1731. }
  1732. else
  1733. {
  1734. Q_snprintf( name, sizeof( name ), "%s:\\%s.HL2", GetCurrentMod(), m_szMapname );
  1735. }
  1736. Q_FixSlashes( name );
  1737. saverestore->RestoreClientState( name, false );
  1738. if ( g_ServerGlobalVariables.eLoadType == MapLoad_Transition )
  1739. {
  1740. for ( int i = 0; i < currentLevelData.levelInfo.connectionCount; i++ )
  1741. {
  1742. saverestore->RestoreAdjacenClientState( currentLevelData.levelInfo.levelList[i].mapName );
  1743. }
  1744. }
  1745. saverestore->OnFinishedClientRestore();
  1746. g_ServerGlobalVariables.pSaveData = NULL;
  1747. // Reset
  1748. m_bLoadgame = false;
  1749. saverestore->SetIsXSave( IsX360() );
  1750. #endif
  1751. }
  1752. void CGameServer::CopyTempEntities( CFrameSnapshot* pSnapshot )
  1753. {
  1754. Assert( pSnapshot->m_pTempEntities == NULL );
  1755. if ( m_TempEntities.Count() > 0 )
  1756. {
  1757. // copy temp entities if any
  1758. pSnapshot->m_nTempEntities = m_TempEntities.Count();
  1759. pSnapshot->m_pTempEntities = new CEventInfo*[pSnapshot->m_nTempEntities];
  1760. Q_memcpy( pSnapshot->m_pTempEntities, m_TempEntities.Base(), m_TempEntities.Count() * sizeof( CEventInfo * ) );
  1761. // clear server list
  1762. m_TempEntities.RemoveAll();
  1763. }
  1764. }
  1765. static ConVar sv_parallel_sendsnapshot( "sv_parallel_sendsnapshot",
  1766. #ifndef DEDICATED
  1767. "1",
  1768. #else //DEDICATED
  1769. "0",
  1770. #endif //DEDICATED
  1771. FCVAR_RELEASE );
  1772. void SV_ParallelSendSnapshot( CGameClient *& pClient )
  1773. {
  1774. CClientFrame *pFrame = pClient->GetSendFrame();
  1775. if ( !pFrame )
  1776. return;
  1777. pClient->SendSnapshot( pFrame );
  1778. pClient->UpdateSendState();
  1779. }
  1780. void CGameServer::SendClientMessages ( bool bSendSnapshots )
  1781. {
  1782. VPROF_BUDGET( "SendClientMessages", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1783. // build individual updates
  1784. int receivingClientCount = 0;
  1785. CGameClient* pReceivingClients[ABSOLUTE_PLAYER_LIMIT];
  1786. bool bHLTVOnly = true; // true when there's no HLTV; which will mean there's no IsHLTV clients, so it'll get reset
  1787. int nHltvMaxAckCount = -1;
  1788. for ( CHltvServerIterator hltv; hltv; hltv.Next() )
  1789. {
  1790. if ( hltv->m_MasterClient )
  1791. {
  1792. nHltvMaxAckCount = Max( hltv->m_MasterClient->GetMaxAckTickCount(), nHltvMaxAckCount );
  1793. }
  1794. if ( hltv->m_MasterClient && ( hltv->GetClientCount() != 0 ) || hltv->IsRecording() )
  1795. {
  1796. bHLTVOnly = false; // we have clients connected to this HLTV server, keep sending snapshots
  1797. }
  1798. }
  1799. for (int i=0; i< GetClientCount(); i++ )
  1800. {
  1801. CGameClient* client = Client(i);
  1802. // Update Host client send state...
  1803. if ( !client->ShouldSendMessages() )
  1804. {
  1805. // For split screen users, adds this into parent stream
  1806. // This works since this user is always "ready" to receive data since they don't
  1807. // exist while the parent entity isn't good for receiving data
  1808. if ( client->IsSplitScreenUser() )
  1809. {
  1810. client->WriteViewAngleUpdate();
  1811. }
  1812. continue;
  1813. }
  1814. client->StepHltvReplayStatus( m_nTickCount );
  1815. // Append the unreliable data (player updates and packet entities)
  1816. if ( bSendSnapshots && client->IsActive() )
  1817. {
  1818. // Add this client to the list of clients we're gonna send to.
  1819. pReceivingClients[receivingClientCount] = client;
  1820. ++receivingClientCount;
  1821. bHLTVOnly = bHLTVOnly && client->IsHLTV() && client->m_pLastSnapshot.IsValid();
  1822. }
  1823. else
  1824. {
  1825. // Connected, but inactive, just send reliable, sequenced info.
  1826. if ( client->IsFakeClient() )
  1827. continue;
  1828. // if client never send a netchannl packet yet, send S2C_CONNECTION
  1829. // because it could get lost in multiplayer
  1830. if ( NET_IsMultiplayer() && client->m_NetChannel->GetSequenceNr(FLOW_INCOMING) == 0 )
  1831. {
  1832. NET_OutOfBandPrintf ( m_Socket, client->m_NetChannel->GetRemoteAddress(), "%c00000000000000", S2C_CONNECTION );
  1833. }
  1834. #ifdef SHARED_NET_STRING_TABLES
  1835. sv.m_StringTables->TriggerCallbacks( client->m_nDeltaTick );
  1836. #endif
  1837. client->m_NetChannel->Transmit();
  1838. client->UpdateSendState();
  1839. }
  1840. }
  1841. if ( receivingClientCount )
  1842. {
  1843. // Don't send a snapshot if there is only 1 client and it is the HLTV client!
  1844. if ( !bHLTVOnly )
  1845. {
  1846. // if any client wants an update, take new snapshot now
  1847. CFrameSnapshot* pSnapshot = framesnapshotmanager->TakeTickSnapshot(
  1848. #ifdef DEBUG_SNAPSHOT_REFERENCES
  1849. "CGameServer::SendClientMessages",
  1850. #endif
  1851. m_nTickCount );
  1852. // copy temp ents references to pSnapshot
  1853. CopyTempEntities( pSnapshot );
  1854. // Compute the client packs
  1855. SV_ComputeClientPacks( receivingClientCount, pReceivingClients, pSnapshot );
  1856. #ifndef SHARED_NET_STRING_TABLES
  1857. if ( nHltvMaxAckCount >= 0 )
  1858. {// copy string updates from server to hltv stringtable
  1859. networkStringTableContainerServer->DirectUpdate( nHltvMaxAckCount ); // !!!! WARNING: THIS IS NOT THREAD SAFE! MEMORY CORRUPTION GUARANTEED WITH MULTIPLE HLTV SERVERS!
  1860. }
  1861. #endif
  1862. if ( receivingClientCount > 1 && sv_parallel_sendsnapshot.GetBool() )
  1863. {
  1864. VPROF_BUDGET( "SendSnapshots(Parallel)", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1865. ParallelProcess( pReceivingClients, receivingClientCount, &SV_ParallelSendSnapshot );
  1866. }
  1867. else
  1868. {
  1869. VPROF_BUDGET( "SendSnapshots", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1870. for (int i = 0; i < receivingClientCount; ++i)
  1871. {
  1872. CGameClient *pClient = pReceivingClients[i];
  1873. CClientFrame *pFrame = pClient->GetSendFrame();
  1874. if ( !pFrame )
  1875. continue;
  1876. pClient->SendSnapshot( pFrame );
  1877. pClient->UpdateSendState();
  1878. }
  1879. }
  1880. pSnapshot->ReleaseReference();
  1881. }
  1882. }
  1883. // Allow game .dll to run code, including unsetting EF_MUZZLEFLASH and EF_NOINTERP on effects fields
  1884. // etc.
  1885. serverGameClients->PostClientMessagesSent();
  1886. }
  1887. bool CGameServer::AnyClientsInHltvReplayMode()
  1888. {
  1889. for ( int i = 0; i < GetClientCount(); i++ )
  1890. {
  1891. CGameClient* client = Client( i );
  1892. if ( client->GetHltvReplayDelay() )
  1893. {
  1894. Assert( !client->IsFakeClient() ); // fake clients should never be in hltv replay mode; it's technically possible, but logically doesn't make sense and has no use case
  1895. return true;
  1896. }
  1897. }
  1898. return false;
  1899. }
  1900. void CGameServer::SetMaxClients( int number )
  1901. {
  1902. m_nMaxclients = clamp( number, m_nMinClientsLimit, m_nMaxClientsLimit );
  1903. ConMsg( "maxplayers set to %i\n", m_nMaxclients );
  1904. deathmatch.SetValue( m_nMaxclients > 1 );
  1905. }
  1906. //-----------------------------------------------------------------------------
  1907. // A potential optimization of the client data sending; the optimization
  1908. // is based around the fact that we think that we're spending all our time in
  1909. // cache misses since we are accessing so much memory
  1910. //-----------------------------------------------------------------------------
  1911. /*
  1912. ==============================================================================
  1913. SERVER SPAWNING
  1914. ==============================================================================
  1915. */
  1916. void SV_WriteVoiceCodec(bf_write &pBuf)
  1917. {
  1918. CSVCMsg_VoiceInit_t voiceinit;
  1919. voiceinit.set_codec( sv.IsMultiplayer() ? sv_voicecodec.GetString() : "" );
  1920. voiceinit.set_quality( 5 );
  1921. voiceinit.set_version( VOICE_CURRENT_VERSION );
  1922. voiceinit.WriteToBuffer( pBuf );
  1923. }
  1924. // Gets voice data from a client and forwards it to anyone who can hear this client.
  1925. ConVar voice_debugfeedbackfrom( "voice_debugfeedbackfrom", "0" );
  1926. void SV_BroadcastVoiceData(IClient * cl, const CCLCMsg_VoiceData& msg )
  1927. {
  1928. ConVarRef voice_verbose( "voice_verbose" );
  1929. // Disable voice?
  1930. if( !sv_voiceenable.GetInt() )
  1931. {
  1932. if ( voice_verbose.GetBool() )
  1933. {
  1934. Msg( "* SV_BroadcastVoiceData: Dropping all voice. sv_voiceenable is not set.\n" );
  1935. }
  1936. return;
  1937. }
  1938. // Build voice message once
  1939. CSVCMsg_VoiceData_t voiceData;
  1940. voiceData.set_client( cl->GetPlayerSlot() );
  1941. voiceData.set_voice_data( msg.data().c_str(), msg.data().size() );
  1942. if ( msg.xuid() )
  1943. {
  1944. voiceData.set_xuid( msg.xuid() );
  1945. }
  1946. voiceData.set_format( msg.format() );
  1947. voiceData.set_sequence_bytes( msg.sequence_bytes() );
  1948. voiceData.set_section_number( msg.section_number() );
  1949. voiceData.set_uncompressed_sample_offset( msg.uncompressed_sample_offset() );
  1950. if ( voice_debugfeedbackfrom.GetBool() )
  1951. {
  1952. Msg( "Sending voice from: %s - playerslot: %d [ xuid %llx ]\n", cl->GetClientName(), cl->GetPlayerSlot() + 1, msg.xuid() );
  1953. }
  1954. for(int i=0; i < sv.GetClientCount(); i++)
  1955. {
  1956. CBaseClient *pDestClient = static_cast< CBaseClient * >( sv.GetClient(i) );
  1957. bool bSelf = (pDestClient == cl);
  1958. // Only send voice to active clients
  1959. if( !pDestClient->IsActive() )
  1960. {
  1961. if ( voice_verbose.GetBool() )
  1962. {
  1963. Msg( "* SV_BroadcastVoiceData: Not active (SignonState %d). Dropping %d bytes from %s (%s) to %s (%s)\n",
  1964. ((CBaseClient*)pDestClient)->GetSignonState(), voiceData.voice_data().size(),
  1965. cl->GetClientName(),
  1966. cl->GetNetChannel() ? cl->GetNetChannel()->GetAddress() : "null",
  1967. pDestClient->GetClientName(), pDestClient->GetNetChannel() ? pDestClient->GetNetChannel()->GetAddress() : "null" );
  1968. }
  1969. continue;
  1970. }
  1971. // We'll check these guys later when we're on the host of them
  1972. if ( pDestClient->IsSplitScreenUser() )
  1973. {
  1974. continue;
  1975. }
  1976. // Does the game code want cl sending to this client?
  1977. bool bHearsPlayer = pDestClient->IsHearingClient( voiceData.client() );
  1978. voiceData.set_audible_mask(bHearsPlayer);
  1979. voiceData.set_proximity( pDestClient->IsProximityHearingClient( voiceData.client() ) );
  1980. // If any of the parasites of the host can hear it, send it to the host
  1981. for ( int i = 1; i < ARRAYSIZE( pDestClient->m_SplitScreenUsers ); ++i )
  1982. {
  1983. voiceData.set_audible_mask( voiceData.audible_mask() | ( i << 1) );
  1984. CBaseClient *splitUser = pDestClient->m_SplitScreenUsers[ i ];
  1985. if ( splitUser )
  1986. {
  1987. // Set which splitscreen players can hear this voice packet
  1988. bool bSplitUserHearsPlayer = splitUser->IsHearingClient( voiceData.client() );
  1989. bHearsPlayer |= bSplitUserHearsPlayer;
  1990. voiceData.set_audible_mask( voiceData.audible_mask() | ( i << 1) );
  1991. if ( splitUser->IsProximityHearingClient( voiceData.client() ) )
  1992. {
  1993. voiceData.set_proximity( true );
  1994. }
  1995. }
  1996. }
  1997. if ( IsGameConsole() && bSelf == true )
  1998. {
  1999. if ( voice_verbose.GetBool() )
  2000. {
  2001. Msg( "* SV_BroadcastVoiceData: Self. Dropping %d bytes from %s (%s) to %s (%s)\n",
  2002. voiceData.voice_data().size(), cl->GetClientName(),
  2003. cl->GetNetChannel() ? cl->GetNetChannel()->GetAddress() : "null",
  2004. pDestClient->GetClientName(), pDestClient->GetNetChannel() ? pDestClient->GetNetChannel()->GetAddress() : "null" );
  2005. }
  2006. continue;
  2007. }
  2008. if ( !bHearsPlayer && !bSelf )
  2009. {
  2010. if ( voice_verbose.GetBool() )
  2011. {
  2012. Msg( "* SV_BroadcastVoiceData: Doesn't hear player. Dropping %d bytes from %s (%s) to %s (%s)\n",
  2013. voiceData.voice_data().size(), cl->GetClientName(),
  2014. cl->GetNetChannel() ? cl->GetNetChannel()->GetAddress() : "null",
  2015. pDestClient->GetClientName(), pDestClient->GetNetChannel() ? pDestClient->GetNetChannel()->GetAddress() : "null" );
  2016. }
  2017. continue;
  2018. }
  2019. // Is loopback enabled?
  2020. if( !bHearsPlayer )
  2021. {
  2022. // Still send something, just zero length (this is so the client
  2023. // can display something that shows knows the server knows it's talking).
  2024. CSVCMsg_VoiceData_t emptyVoiceMsg;
  2025. emptyVoiceMsg.set_client( voiceData.client() );
  2026. emptyVoiceMsg.set_audible_mask( voiceData.audible_mask() );
  2027. emptyVoiceMsg.set_proximity( voiceData.proximity() );
  2028. if ( voiceData.has_xuid())
  2029. {
  2030. emptyVoiceMsg.set_xuid( voiceData.xuid() );
  2031. }
  2032. pDestClient->SendNetMsg( emptyVoiceMsg, false, true );
  2033. }
  2034. else
  2035. {
  2036. pDestClient->SendNetMsg( voiceData, false, true );
  2037. }
  2038. if ( voice_verbose.GetBool() )
  2039. {
  2040. Msg( "* SV_BroadcastVoiceData: Sending %d bits (%d bytes) from %s (%s) to %s (%s). Proximity %s.\n", voiceData.voice_data().size(), Bits2Bytes(voiceData.voice_data().size()), cl->GetClientName(), cl->GetNetChannel() ? cl->GetNetChannel()->GetAddress() : "null", pDestClient->GetClientName(), pDestClient->GetNetChannel() ? pDestClient->GetNetChannel()->GetAddress() : "null", voiceData.proximity() ? "true" : "false" );
  2041. }
  2042. }
  2043. }
  2044. // UNDONE: "player.mdl" ??? This should be set by name in the DLL
  2045. /*
  2046. ================
  2047. SV_CreateBaseline
  2048. ================
  2049. */
  2050. void SV_CreateBaseline (void)
  2051. {
  2052. SV_WriteVoiceCodec( sv.m_Signon );
  2053. ServerClass *pClasses = serverGameDLL->GetAllServerClasses();
  2054. // Send SendTable info.
  2055. if ( sv_sendtables.GetInt() )
  2056. {
  2057. sv.m_FullSendTablesBuffer.EnsureCapacity( NET_MAX_PAYLOAD );
  2058. sv.m_FullSendTables.StartWriting( sv.m_FullSendTablesBuffer.Base(), sv.m_FullSendTablesBuffer.Count() );
  2059. SV_WriteSendTables( pClasses, sv.m_FullSendTables );
  2060. if ( sv.m_FullSendTables.IsOverflowed() )
  2061. {
  2062. Host_Error("SV_CreateBaseline: WriteSendTables overflow.\n" );
  2063. return;
  2064. }
  2065. // Send class descriptions.
  2066. SV_WriteClassInfos(pClasses, sv.m_FullSendTables);
  2067. if ( sv.m_FullSendTables.IsOverflowed() )
  2068. {
  2069. Host_Error("SV_CreateBaseline: WriteClassInfos overflow.\n" );
  2070. return;
  2071. }
  2072. }
  2073. SerializedEntityHandle_t handle = g_pSerializedEntities->AllocateSerializedEntity(__FILE__, __LINE__);
  2074. // If we're using the local network backdoor, we'll never use the instance baselines.
  2075. if ( !g_pLocalNetworkBackdoor )
  2076. {
  2077. int count = 0;
  2078. int bytes = 0;
  2079. for ( int entnum = 0; entnum < sv.num_edicts ; entnum++)
  2080. {
  2081. // get the current server version
  2082. edict_t *edict = sv.edicts + entnum;
  2083. if ( edict->IsFree() || !edict->GetUnknown() )
  2084. continue;
  2085. ServerClass *pClass = edict->GetNetworkable() ? edict->GetNetworkable()->GetServerClass() : 0;
  2086. if ( !pClass )
  2087. {
  2088. Assert( pClass );
  2089. continue; // no Class ?
  2090. }
  2091. if ( pClass->m_InstanceBaselineIndex != INVALID_STRING_INDEX )
  2092. continue; // we already have a baseline for this class
  2093. SendTable *pSendTable = pClass->m_pTable;
  2094. //
  2095. // create entity baseline
  2096. //
  2097. char packedData[MAX_PACKEDENTITY_DATA];
  2098. bf_write writeBuf( "SV_CreateBaseline->writeBuf", packedData, sizeof( packedData ) );
  2099. // create basline from zero values
  2100. if ( !SendTable_Encode(
  2101. pSendTable,
  2102. handle,
  2103. edict->GetUnknown(),
  2104. entnum,
  2105. NULL
  2106. ) )
  2107. {
  2108. Host_Error("SV_CreateBaseline: SendTable_Encode returned false (ent %d).\n", entnum);
  2109. }
  2110. // copy baseline into baseline stringtable
  2111. SV_EnsureInstanceBaseline( pClass, entnum, handle );
  2112. CSerializedEntity *pEntity = ( CSerializedEntity * )handle;
  2113. bytes += Bits2Bytes( pEntity->GetFieldDataBitCount() );
  2114. count ++;
  2115. }
  2116. DevMsg("Created class baseline: %i classes, %i bytes.\n", count,bytes);
  2117. }
  2118. g_pSerializedEntities->ReleaseSerializedEntity( handle );
  2119. g_GameEventManager.ReloadEventDefinitions();
  2120. CSVCMsg_GameEventList_t gameevents;
  2121. g_GameEventManager.WriteEventList( &gameevents );
  2122. gameevents.WriteToBuffer( sv.m_Signon );
  2123. }
  2124. //-----------------------------------------------------------------------------
  2125. // Purpose:
  2126. // Input : runPhysics -
  2127. //-----------------------------------------------------------------------------
  2128. bool SV_ActivateServer()
  2129. {
  2130. COM_TimestampedLog( "SV_ActivateServer" );
  2131. #ifndef DEDICATED
  2132. EngineVGui()->UpdateProgressBar(PROGRESS_ACTIVATESERVER);
  2133. #endif
  2134. COM_TimestampedLog( "serverGameDLL->ServerActivate" );
  2135. bool bPrevState = networkStringTableContainerServer->Lock( false );
  2136. // Activate the DLL server code
  2137. g_pServerPluginHandler->ServerActivate( sv.edicts, sv.num_edicts, sv.GetMaxClients() );
  2138. // all setup is completed, any further precache statements are errors
  2139. sv.m_State = ss_active;
  2140. COM_TimestampedLog( "SV_CreateBaseline" );
  2141. // create a baseline for more efficient communications
  2142. SV_CreateBaseline();
  2143. sv.allowsignonwrites = false;
  2144. // set skybox name
  2145. ConVar const *skyname = g_pCVar->FindVar( "sv_skyname" );
  2146. if ( skyname )
  2147. {
  2148. Q_strncpy( sv.m_szSkyname, skyname->GetString(), sizeof( sv.m_szSkyname ) );
  2149. }
  2150. else
  2151. {
  2152. Q_strncpy( sv.m_szSkyname, "unknown", sizeof( sv.m_szSkyname ) );
  2153. }
  2154. COM_TimestampedLog( "Send Reconnects" );
  2155. // Tell connected clients to reconnect
  2156. sv.ReconnectClients();
  2157. // Tell what kind of server has been started.
  2158. if ( sv.IsMultiplayer() )
  2159. {
  2160. ConDMsg ("%i player server started\n", sv.GetMaxClients() );
  2161. }
  2162. else
  2163. {
  2164. ConDMsg ("Game started\n");
  2165. }
  2166. // Replay setup
  2167. #if defined( REPLAY_ENABLED )
  2168. if ( !g_pServerReplayHistoryManager )
  2169. {
  2170. g_pServerReplayHistoryManager = CreateServerReplayHistoryManager();
  2171. g_pServerReplayHistoryManager->Init();
  2172. }
  2173. if ( Replay_IsEnabled() )
  2174. {
  2175. if ( CommandLine()->FindParm("-noreplay") )
  2176. {
  2177. // let user know that Replay will not work
  2178. ConMsg ("Replay is disabled on this server.\n");
  2179. }
  2180. else
  2181. {
  2182. if ( !replay )
  2183. {
  2184. replay = new CReplayServer;
  2185. replay->Init( NET_IsDedicated() );
  2186. }
  2187. #if !defined( NO_STEAM )
  2188. Steam3Server().UpdateSpectatorPort( NET_GetUDPPort( NS_REPLAY ) );
  2189. #endif
  2190. if ( replay->IsActive() )
  2191. {
  2192. // replay master already running, just activate client
  2193. replay->m_MasterClient->ActivatePlayer();
  2194. replay->StartMaster( replay->m_MasterClient );
  2195. }
  2196. else
  2197. {
  2198. // create new replay client
  2199. CGameClient *cl = (CGameClient*)sv.CreateFakeClient( "Replay" );
  2200. replay->StartMaster( cl );
  2201. }
  2202. }
  2203. }
  2204. else
  2205. {
  2206. // make sure replay is disabled
  2207. if ( replay )
  2208. replay->Shutdown();
  2209. }
  2210. #endif
  2211. if (sv.IsDedicated())
  2212. {
  2213. // purge unused models and their data hierarchy (materials, shaders, etc)
  2214. modelloader->PurgeUnusedModels();
  2215. g_pMDLCache->UnloadQueuedHardwareData(); // need to do this to properly remove the data associated with purged models (on the client this is called by materialsystem, but not on the dedicated server)
  2216. }
  2217. // Steam is required for proper hltv server startup if the server is broadcasting in http
  2218. if ( sv.IsMultiplayer() || serverGameDLL->ShouldPreferSteamAuth() )
  2219. {
  2220. // We always need to activate the Steam3Server
  2221. // it will have different auth modes for SP and MP
  2222. Steam3Server().Activate();
  2223. sv.SetQueryPortFromSteamServer();
  2224. sv.UpdateGameData(); // Set server tags after server creation
  2225. if ( serverGameDLL )
  2226. {
  2227. serverGameDLL->GameServerSteamAPIActivated( true );
  2228. }
  2229. }
  2230. // HLTV setup
  2231. for ( int nHltvServerIndex = 0; nHltvServerIndex < HLTV_SERVER_MAX_COUNT; ++nHltvServerIndex )
  2232. {
  2233. CHLTVServer *&hltv = g_pHltvServer[ nHltvServerIndex ];
  2234. const ConVar &cvEnable = GetIndexedConVar( tv_enable, nHltvServerIndex );
  2235. if ( cvEnable.GetBool() )
  2236. {
  2237. if ( CommandLine()->FindParm( "-nohltv" ) )
  2238. {
  2239. // let user know that SourceTV will not work
  2240. ConMsg( "GOTV is disabled on this server.\n" );
  2241. }
  2242. else if ( nHltvServerIndex > 0 && !CommandLine()->FindParm( "-addhltv1" ) )
  2243. {
  2244. // default behavior - GOTV[1] disabled - but tv_enable* is ON
  2245. ConMsg( "GOTV[%d] must be explicitly enabled (with -addhltv1) on this server. tv_enable%d 0 to hide this message\n", nHltvServerIndex, nHltvServerIndex );
  2246. }
  2247. else if ( !sv.IsDedicated() || sv.IsReserved() || ( cvEnable.GetInt() != 2 ) )
  2248. {
  2249. // create SourceTV object if not already there
  2250. if ( !hltv )
  2251. {
  2252. extern ConVar tv_snapshotrate;
  2253. hltv = new CHLTVServer( nHltvServerIndex, GetIndexedConVar( tv_snapshotrate, nHltvServerIndex ).GetFloat() );
  2254. hltv->Init( NET_IsDedicated() );
  2255. }
  2256. if ( hltv->IsActive() && hltv->IsMasterProxy() )
  2257. {
  2258. // HLTV master already running, just activate client
  2259. hltv->m_MasterClient->ActivatePlayer();
  2260. hltv->StartMaster( hltv->m_MasterClient );
  2261. }
  2262. else
  2263. {
  2264. // create new HLTV client
  2265. CGameClient *cl = ( CGameClient* )sv.CreateFakeClient( "GOTV" );
  2266. hltv->StartMaster( cl );
  2267. }
  2268. }
  2269. }
  2270. else
  2271. {
  2272. // make sure HLTV is disabled
  2273. if ( hltv )
  2274. hltv->Shutdown();
  2275. }
  2276. }
  2277. networkStringTableContainerServer->Lock( bPrevState );
  2278. // Heartbeat the master server in case we turned SrcTV on or off.
  2279. Steam3Server().SendUpdatedServerDetails();
  2280. #if !defined( NO_STEAM )
  2281. {
  2282. if ( Steam3Server().SteamGameServer() )
  2283. Steam3Server().SteamGameServer()->ForceHeartbeat();
  2284. }
  2285. #endif
  2286. if ( serverGameDLL && Steam3Server().GetGSSteamID().IsValid() )
  2287. serverGameDLL->UpdateGCInformation();
  2288. COM_TimestampedLog( "SV_ActivateServer(finished)" );
  2289. return true;
  2290. }
  2291. #include "tier0/memdbgoff.h"
  2292. static void SV_AllocateEdicts()
  2293. {
  2294. sv.edicts = (edict_t *)Hunk_AllocName( sv.max_edicts*sizeof(edict_t), "edicts" );
  2295. // Invoke the constructor so the vtable is set correctly..
  2296. for (int i = 0; i < sv.max_edicts; ++i)
  2297. {
  2298. new( &sv.edicts[i] ) edict_t;
  2299. }
  2300. ED_ClearTimes();
  2301. sv.edictchangeinfo = (IChangeInfoAccessor *)Hunk_AllocName( sv.max_edicts * sizeof( IChangeInfoAccessor ), "edictchangeinfo" );
  2302. }
  2303. #include "tier0/memdbgon.h"
  2304. void CGameServer::ReloadWhitelist( const char *pMapName )
  2305. {
  2306. // listen servers should not ever run sv_pure
  2307. if ( !sv.IsDedicated() )
  2308. {
  2309. g_sv_pure_mode = 0;
  2310. }
  2311. // Always return - until we get the whilelist stuff resolved for TF2.
  2312. if ( m_pPureServerWhitelist )
  2313. {
  2314. m_pPureServerWhitelist->Release();
  2315. m_pPureServerWhitelist = NULL;
  2316. }
  2317. // Don't do sv_pure stuff in SP games.
  2318. if ( GetMaxClients() <= 1 )
  2319. return;
  2320. // Get rid of the old whitelist.
  2321. if ( m_pPureServerWhitelist )
  2322. {
  2323. m_pPureServerWhitelist->Release();
  2324. m_pPureServerWhitelist = NULL;
  2325. }
  2326. // Don't use the whitelist if sv_pure is not set.
  2327. if ( g_sv_pure_mode == 0 )
  2328. return;
  2329. m_pPureServerWhitelist = CPureServerWhitelist::Create( g_pFileSystem );
  2330. if ( g_sv_pure_mode == 2 )
  2331. {
  2332. // sv_pure 2 means to ignore the pure_server_whitelist.txt file and force everything to come from Steam.
  2333. m_pPureServerWhitelist->EnableFullyPureMode();
  2334. Msg( "Server using sv_pure 2.\n" );
  2335. }
  2336. else
  2337. {
  2338. const char *pGlobalWhitelistFilename = "pure_server_whitelist.txt";
  2339. const char *pMapWhitelistSuffix = "_whitelist.txt";
  2340. // Load the new whitelist.
  2341. KeyValues *kv = new KeyValues( "" );
  2342. bool bLoaded = kv->LoadFromFile( g_pFileSystem, pGlobalWhitelistFilename, "game" );
  2343. if ( bLoaded )
  2344. bLoaded = m_pPureServerWhitelist->LoadFromKeyValues( kv );
  2345. if ( !bLoaded )
  2346. Warning( "Can't load pure server whitelist in %s.\n", pGlobalWhitelistFilename );
  2347. // Load the per-map whitelist.
  2348. char testFilename[MAX_PATH] = "maps";
  2349. V_AppendSlash( testFilename, sizeof( testFilename ) );
  2350. V_strncat( testFilename, pMapName, sizeof( testFilename ) );
  2351. V_strncat( testFilename, pMapWhitelistSuffix, sizeof( testFilename ) );
  2352. kv->Clear();
  2353. if ( kv->LoadFromFile( g_pFileSystem, testFilename ) )
  2354. m_pPureServerWhitelist->LoadFromKeyValues( kv );
  2355. kv->deleteThis();
  2356. }
  2357. }
  2358. //-----------------------------------------------------------------------------
  2359. // Update the game type based on map name, only used when user types "map"
  2360. // we are we hibernating (since someone could join our currently running
  2361. // map).
  2362. void CGameServer::ExecGameTypeCfg( const char *mapname )
  2363. {
  2364. MEM_ALLOC_CREDIT();
  2365. KeyValues *pGameSettings = new KeyValues( "::ExecGameTypeCfg" );
  2366. KeyValues::AutoDelete autodelete( pGameSettings );
  2367. pGameSettings->SetString( "map/mapname", mapname );
  2368. if ( serverGameDLL )
  2369. serverGameDLL->ApplyGameSettings( pGameSettings );
  2370. int numSlots = pGameSettings->GetInt( "members/numSlots", -1 );
  2371. #if defined (_GAMECONSOLE) && defined ( CSTRIKE15 )
  2372. // FIXME(hpe) sb: temp: quick hack for splitscreen; NOTE: SetMaxClients required since integration (taken from PORTAL2 below)
  2373. ConVarRef ss_enable( "ss_enable" );
  2374. if ( ss_enable.GetInt() > 0 )
  2375. {
  2376. numSlots = 9;
  2377. SetMaxClients( numSlots );
  2378. }
  2379. #endif
  2380. if ( numSlots >= 0 )
  2381. {
  2382. m_numGameSlots = numSlots;
  2383. #ifdef PORTAL2 // HACK: PORTAL2 uses maxclients instead of GAMERULES
  2384. SetMaxClients( numSlots );
  2385. #endif
  2386. }
  2387. }
  2388. void CGameServer::SetMapGroupName( char const *mapGroupName )
  2389. {
  2390. if ( mapGroupName && mapGroupName[0] )
  2391. {
  2392. V_strncpy( m_szMapGroupName, mapGroupName, sizeof( m_szMapGroupName ) );
  2393. }
  2394. g_ServerGlobalVariables.mapGroupName = MAKE_STRING( m_szMapGroupName );
  2395. }
  2396. /*
  2397. ================
  2398. SV_SpawnServer
  2399. This is called at the start of each level
  2400. ================
  2401. */
  2402. bool CGameServer::SpawnServer( char *mapname, char * mapGroupName, char *startspot )
  2403. {
  2404. int i;
  2405. char szDllName[MAX_QPATH];
  2406. Assert( serverGameClients );
  2407. SV_SetSteamCrashComment();
  2408. if ( CommandLine()->FindParm( "-NoLoadPluginsForClient" ) != 0 )
  2409. {
  2410. if ( !m_bLoadedPlugins )
  2411. {
  2412. // Only load plugins once.
  2413. m_bLoadedPlugins = true;
  2414. g_pServerPluginHandler->LoadPlugins(); // load 3rd party plugins
  2415. }
  2416. }
  2417. if ( IsGameConsole() && g_pQueuedLoader->IsMapLoading() )
  2418. {
  2419. Msg( "Spawning a new server - loading map %s. Forcing current map load to end.\n", mapname );
  2420. g_pQueuedLoader->EndMapLoading( true );
  2421. }
  2422. // NOTE[pmf]: Removed this. We don't want to limit the server fps below what our desired tick rate is; apparently
  2423. // this restriction was only put in because of people selling dedicated server hosting and offering 500+fps servers,
  2424. // which really does nothing other than waste extra cycles doing additional iterations of the main loop
  2425. // if ( IsDedicated() )
  2426. // {
  2427. // fps_max.SetValue( 60 );
  2428. // }
  2429. ReloadWhitelist( mapname );
  2430. COM_TimestampedLog( "SV_SpawnServer(%s)", mapname );
  2431. #ifndef DEDICATED
  2432. EngineVGui()->UpdateProgressBar(PROGRESS_SPAWNSERVER);
  2433. #endif
  2434. COM_SetupLogDir( mapname );
  2435. g_Log.Open();
  2436. g_Log.Printf( "Loading map \"%s\"\n", mapname );
  2437. g_Log.PrintServerVars();
  2438. if ( startspot )
  2439. {
  2440. ConDMsg("Spawn Server: %s: [%s]\n", mapname, startspot );
  2441. }
  2442. else
  2443. {
  2444. ConDMsg("Spawn Server: %s\n", mapname );
  2445. }
  2446. // Any partially connected client will be restarted if the spawncount is not matched.
  2447. gHostSpawnCount = ++m_nSpawnCount;
  2448. //
  2449. // make cvars consistant
  2450. //
  2451. deathmatch.SetValue( IsMultiplayer() ? 1 : 0 );
  2452. if ( coop.GetInt() )
  2453. {
  2454. deathmatch.SetValue( 0 );
  2455. }
  2456. current_skill = MAX( current_skill, 0 );
  2457. current_skill = MIN( current_skill, 3 );
  2458. skill.SetValue( (float)current_skill );
  2459. // Setup gamemode based on the settings the map was started with
  2460. // ExecGameTypeCfg( mapname );
  2461. COM_TimestampedLog( "StaticPropMgr()->LevelShutdown()" );
  2462. #if !defined( DEDICATED )
  2463. g_pShadowMgr->LevelShutdown();
  2464. #endif // DEDICATED
  2465. StaticPropMgr()->LevelShutdown();
  2466. // if we have an hltv relay proxy running, stop it now
  2467. for ( CHltvServerIterator hltv; hltv; hltv.Next() )
  2468. {
  2469. if ( !hltv->IsMasterProxy() )
  2470. {
  2471. hltv->Shutdown();
  2472. }
  2473. }
  2474. COM_TimestampedLog( "Host_FreeToLowMark" );
  2475. Host_FreeStateAndWorld( true );
  2476. Host_FreeToLowMark( true );
  2477. // Clear out the mapversion so it's reset when the next level loads. Needed for changelevels.
  2478. g_ServerGlobalVariables.mapversion = 0;
  2479. COM_TimestampedLog( "sv.Clear()" );
  2480. Clear();
  2481. COM_TimestampedLog( "framesnapshotmanager->LevelChanged()" );
  2482. // Clear out the state of the most recently sent packed entities from
  2483. // the snapshot manager
  2484. framesnapshotmanager->LevelChanged();
  2485. // set map name and mapgroup name
  2486. Q_FileBase( mapname, m_szBaseMapname, sizeof ( m_szBaseMapname ) );
  2487. V_strcpy_safe( m_szMapname, mapname );
  2488. if ( mapGroupName && mapGroupName[0] )
  2489. {
  2490. Q_strncpy( m_szMapGroupName, mapGroupName, sizeof( m_szMapGroupName ) );
  2491. }
  2492. // set startspot
  2493. if (startspot)
  2494. {
  2495. Q_strncpy(m_szStartspot, startspot, sizeof( m_szStartspot ) );
  2496. }
  2497. else
  2498. {
  2499. m_szStartspot[0] = 0;
  2500. }
  2501. SV_FlushMemoryIfMarked();
  2502. // Preload any necessary data from the xzps:
  2503. g_pFileSystem->SetupPreloadData();
  2504. g_pMDLCache->InitPreloadData( false );
  2505. // Allocate server memory
  2506. max_edicts = MAX_EDICTS;
  2507. g_ServerGlobalVariables.maxEntities = max_edicts;
  2508. g_ServerGlobalVariables.maxClients = GetMaxClients();
  2509. #ifndef DEDICATED
  2510. g_ClientGlobalVariables.network_protocol = GetHostVersion();
  2511. #endif
  2512. // Assume no entities beyond world and client slots
  2513. num_edicts = GetMaxClients()+1;
  2514. COM_TimestampedLog( "SV_AllocateEdicts" );
  2515. SV_AllocateEdicts();
  2516. g_ServerGlobalVariables.pEdicts = edicts;
  2517. allowsignonwrites = true;
  2518. serverclasses = 0; // number of unique server classes
  2519. serverclassbits = 0; // log2 of serverclasses
  2520. // Assign class ids to server classes here so we can encode temp ents into signon
  2521. // if needed
  2522. AssignClassIds();
  2523. COM_TimestampedLog( "Set up players" );
  2524. // allocate player data, and assign the values into the edicts
  2525. for ( i=0 ; i< GetClientCount() ; i++ )
  2526. {
  2527. CGameClient * cl = Client(i);
  2528. // edict for a player is slot + 1, world = 0
  2529. cl->edict = edicts + i + 1;
  2530. // Setup up the edict
  2531. InitializeEntityDLLFields( cl->edict );
  2532. }
  2533. COM_TimestampedLog( "Set up players(done)" );
  2534. m_State = ss_loading;
  2535. sv.SendReservationStatus( sv.kEReservationStatusSuccess );
  2536. // Set initial time values.
  2537. m_flTickInterval = host_state.interval_per_tick;
  2538. m_nTickCount = (int)( 1.0 / host_state.interval_per_tick ) + 1; // Start at appropriate 1
  2539. float flStartTimeOverride = -1.0f;
  2540. flStartTimeOverride = CommandLine()->ParmValue( "-servertime", flStartTimeOverride );
  2541. if ( flStartTimeOverride != -1.0f )
  2542. {
  2543. m_nTickCount = MAX( (int)( flStartTimeOverride / host_state.interval_per_tick ) + 1, 1 );
  2544. }
  2545. g_ServerGlobalVariables.tickcount = m_nTickCount;
  2546. g_ServerGlobalVariables.curtime = GetTime();
  2547. // [mhansen] Reset the host tick count so we can run in threaded mode without
  2548. // complaints about commands being out of sync (as in every command)
  2549. host_tickcount = g_ServerGlobalVariables.tickcount;
  2550. // Load the world model.
  2551. char szModelName[MAX_PATH];
  2552. char szNameOnDisk[MAX_PATH];
  2553. Q_snprintf( szModelName, sizeof( szModelName ), "maps/%s.bsp", mapname );
  2554. GetMapPathNameOnDisk( szNameOnDisk, szModelName, sizeof( szNameOnDisk ) );
  2555. g_pFileSystem->AddSearchPath( szNameOnDisk, "GAME", PATH_ADD_TO_HEAD );
  2556. g_pFileSystem->BeginMapAccess();
  2557. #ifndef DEDICATED
  2558. // Force reload all materials since BSP could have changed
  2559. // TODO:
  2560. // if ( modelloader )
  2561. // modelloader->UnloadUnreferencedModels();
  2562. if ( materials )
  2563. materials->ReloadMaterials();
  2564. #endif
  2565. if ( !CommandLine()->FindParm( "-allowstalezip" ) )
  2566. {
  2567. if ( g_pFileSystem->FileExists( "stale.txt", "GAME" ) )
  2568. {
  2569. Warning( "This map is not final!! Needs to be rebuilt without -keepstalezip and without -onlyents\n" );
  2570. }
  2571. }
  2572. COM_TimestampedLog( "modelloader->GetModelForName(%s) -- Start", szModelName );
  2573. host_state.SetWorldModel( modelloader->GetModelForName( szModelName, IModelLoader::FMODELLOADER_SERVER ) );
  2574. if ( !host_state.worldmodel )
  2575. {
  2576. ConMsg( "Couldn't spawn server %s\n", szModelName );
  2577. m_State = ss_dead;
  2578. g_pFileSystem->EndMapAccess();
  2579. return false;
  2580. }
  2581. COM_TimestampedLog( "modelloader->GetModelForName(%s) -- Finished", szModelName );
  2582. if ( IsMultiplayer() && !IsGameConsole() )
  2583. {
  2584. #ifndef DEDICATED
  2585. EngineVGui()->UpdateProgressBar(PROGRESS_CRCMAP);
  2586. #endif
  2587. // Server map CRC check.
  2588. CRC32_Init(&worldmapCRC);
  2589. if ( !CRC_MapFile( &worldmapCRC, szNameOnDisk ) )
  2590. {
  2591. ConMsg( "Couldn't CRC server map: %s\n", szNameOnDisk );
  2592. m_State = ss_dead;
  2593. g_pFileSystem->EndMapAccess();
  2594. return false;
  2595. }
  2596. #ifndef DEDICATED
  2597. EngineVGui()->UpdateProgressBar(PROGRESS_CRCCLIENTDLL);
  2598. #endif
  2599. // DLL CRC check.
  2600. Q_snprintf( szDllName, sizeof( szDllName ), "bin\\client.dll" );
  2601. Q_FixSlashes( szDllName );
  2602. if ( !CRC_File( &clientDllCRC, szDllName ) )
  2603. {
  2604. clientDllCRC = 0xFFFFFFFF; // we don't require a CRC, its optional
  2605. }
  2606. }
  2607. else
  2608. {
  2609. worldmapCRC = 0;
  2610. clientDllCRC = 0;
  2611. }
  2612. m_StringTables = networkStringTableContainerServer;
  2613. COM_TimestampedLog( "SV_CreateNetworkStringTables" );
  2614. #ifndef DEDICATED
  2615. EngineVGui()->UpdateProgressBar(PROGRESS_CREATENETWORKSTRINGTABLES);
  2616. #endif
  2617. // Create network string tables ( including precache tables )
  2618. SV_CreateNetworkStringTables( mapname );
  2619. stringTableCRC = g_pStringTableDictionary->GetCRC();
  2620. // Leave empty slots for models/sounds/generic (not for decals though)
  2621. PrecacheModel( "", 0 );
  2622. PrecacheGeneric( "", 0 );
  2623. PrecacheSound( "", 0 );
  2624. COM_TimestampedLog( "Precache world model (%s)", szModelName );
  2625. #ifndef DEDICATED
  2626. EngineVGui()->UpdateProgressBar(PROGRESS_PRECACHEWORLD);
  2627. #endif
  2628. // Add in world
  2629. PrecacheModel( szModelName, RES_FATALIFMISSING | RES_PRELOAD, host_state.worldmodel );
  2630. COM_TimestampedLog( "Precache brush models" );
  2631. // Add world submodels to the model cache
  2632. for ( i = 1 ; i < host_state.worldbrush->numsubmodels ; i++ )
  2633. {
  2634. // Add in world brush models
  2635. char localmodel[5]; // inline model names "*1", "*2" etc
  2636. Q_snprintf( localmodel, sizeof( localmodel ), "*%i", i );
  2637. PrecacheModel( localmodel, RES_FATALIFMISSING | RES_PRELOAD, modelloader->GetModelForName( localmodel, IModelLoader::FMODELLOADER_SERVER ) );
  2638. }
  2639. #ifndef DEDICATED
  2640. EngineVGui()->UpdateProgressBar(PROGRESS_CLEARWORLD);
  2641. #endif
  2642. COM_TimestampedLog( "SV_ClearWorld" );
  2643. // Clear world interaction links
  2644. // Loads and inserts static props
  2645. SV_ClearWorld();
  2646. //
  2647. // load the rest of the entities
  2648. //
  2649. COM_TimestampedLog( "InitializeEntityDLLFields" );
  2650. InitializeEntityDLLFields( edicts );
  2651. edicts->ClearFree();
  2652. g_ServerGlobalVariables.coop = ( coop.GetInt() != 0 );
  2653. g_ServerGlobalVariables.deathmatch = ( !g_ServerGlobalVariables.coop && ( deathmatch.GetInt() != 0 ) );
  2654. g_ServerGlobalVariables.mapname = MAKE_STRING( m_szMapname );
  2655. g_ServerGlobalVariables.startspot = MAKE_STRING( m_szStartspot );
  2656. g_ServerGlobalVariables.mapGroupName = MAKE_STRING( m_szMapGroupName );
  2657. GetTestScriptMgr()->CheckPoint( "map_load" );
  2658. // set game event
  2659. IGameEvent *event = g_GameEventManager.CreateEvent( "server_spawn" );
  2660. if ( event )
  2661. {
  2662. event->SetString( "hostname", host_name.GetString() );
  2663. // event->SetString( "address", net_local_adr.ToString( false ) );
  2664. // event->SetInt( "port", GetUDPPort() );
  2665. event->SetString( "game", com_gamedir );
  2666. event->SetString( "mapname", GetMapName() );
  2667. event->SetInt( "maxplayers", GetMaxClients() );
  2668. event->SetInt( "password", 0 ); // TODO
  2669. #if defined( _WIN32 )
  2670. event->SetString( "os", "WIN32" );
  2671. #elif defined ( LINUX )
  2672. event->SetString( "os", "LINUX" );
  2673. #elif defined ( OSX )
  2674. event->SetString( "os", "OSX" );
  2675. #elif defined ( _PS3 )
  2676. event->SetString( "os", "PS3" );
  2677. #else
  2678. #error
  2679. #endif
  2680. event->SetInt( "dedicated", IsDedicated() ? 1 : 0 );
  2681. g_GameEventManager.FireEvent( event );
  2682. }
  2683. COM_TimestampedLog( "SV_SpawnServer -- Finished" );
  2684. g_pFileSystem->EndMapAccess();
  2685. SV_SetSteamCrashComment();
  2686. return true;
  2687. }
  2688. void CGameServer::UpdateMasterServerPlayers()
  2689. {
  2690. if ( !Steam3Server().SteamGameServer() )
  2691. return;
  2692. for ( int i=0; i < GetClientCount() ; i++ )
  2693. {
  2694. CGameClient *client = Client(i);
  2695. if ( !client->IsConnected() )
  2696. continue;
  2697. CPlayerState *pl = serverGameClients->GetPlayerState( client->edict );
  2698. if ( !pl )
  2699. continue;
  2700. if ( !client->m_SteamID.IsValid() )
  2701. continue;
  2702. extern bool CanShowHostTvStatus();
  2703. if ( client->IsHLTV() && !CanShowHostTvStatus() )
  2704. continue;
  2705. Steam3Server().SteamGameServer()->BUpdateUserData( client->m_SteamID, client->GetClientName(), pl->score );
  2706. }
  2707. }
  2708. //-----------------------------------------------------------------------------
  2709. // SV_IsSimulating
  2710. //-----------------------------------------------------------------------------
  2711. bool SV_IsSimulating( void )
  2712. {
  2713. if ( sv.IsPaused() )
  2714. return false;
  2715. #ifndef DEDICATED
  2716. // Don't simulate in single player if console is down or the bug UI is active and we're in a game
  2717. if ( !sv.IsMultiplayer() )
  2718. {
  2719. if ( g_LostVideoMemory )
  2720. return false;
  2721. // Don't simulate in single player if console is down or the bug UI is active and we're in a game
  2722. if ( GetBaseLocalClient().IsActive() && ( Con_IsVisible() || EngineVGui()->ShouldPause() ) )
  2723. return false;
  2724. }
  2725. #endif //DEDICATED
  2726. return true;
  2727. }
  2728. namespace CDebugOverlay
  2729. {
  2730. extern void PurgeServerOverlays( void );
  2731. }
  2732. extern bool g_bIsVGuiBasedDedicatedServer;
  2733. //-----------------------------------------------------------------------------
  2734. // Purpose: Run physics code (simulating == false means we're paused, but we'll still
  2735. // allow player usercmds to be processed
  2736. //-----------------------------------------------------------------------------
  2737. void SV_Think( bool bIsSimulating )
  2738. {
  2739. VPROF( "SV_Physics" );
  2740. if ( sv.IsDedicated() )
  2741. {
  2742. sv.UpdateReservedState();
  2743. if ( sv.IsHibernating() )
  2744. {
  2745. // if we're hibernating, just sleep for a while and do not call server.dll to run a frame
  2746. int nMilliseconds = sv_hibernate_ms.GetInt();
  2747. #ifndef DEDICATED // Non-Linux
  2748. if ( g_bIsVGuiBasedDedicatedServer )
  2749. {
  2750. // Keep VGUi happy
  2751. nMilliseconds = sv_hibernate_ms_vgui.GetInt();
  2752. }
  2753. #endif
  2754. NET_SleepUntilMessages( nMilliseconds );
  2755. return;
  2756. }
  2757. }
  2758. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2759. g_ServerGlobalVariables.curtime = sv.GetTime();
  2760. g_ServerGlobalVariables.frametime = bIsSimulating ? host_state.interval_per_tick : 0;
  2761. // in singleplayer only run think/simulation if localplayer is connected
  2762. #ifdef DEDICATED
  2763. bIsSimulating = bIsSimulating && sv.IsMultiplayer();
  2764. #else
  2765. bIsSimulating = bIsSimulating && ( sv.IsMultiplayer() || GetBaseLocalClient().IsActive() );
  2766. #endif
  2767. #ifndef DEDICATED
  2768. CDebugOverlay::PurgeServerOverlays();
  2769. #endif
  2770. g_pServerPluginHandler->GameFrame( bIsSimulating );
  2771. }
  2772. //-----------------------------------------------------------------------------
  2773. // Purpose:
  2774. // Input : simulating -
  2775. //-----------------------------------------------------------------------------
  2776. void SV_PreClientUpdate(bool bIsSimulating )
  2777. {
  2778. if ( !serverGameDLL )
  2779. return;
  2780. serverGameDLL->PreClientUpdate( bIsSimulating );
  2781. }
  2782. //-----------------------------------------------------------------------------
  2783. //
  2784. //-----------------------------------------------------------------------------
  2785. /*
  2786. ==================
  2787. SV_Frame
  2788. ==================
  2789. */
  2790. CFunctor *g_pDeferredServerWork;
  2791. void SV_FrameExecuteThreadDeferred()
  2792. {
  2793. if ( g_pDeferredServerWork )
  2794. {
  2795. (*g_pDeferredServerWork)();
  2796. delete g_pDeferredServerWork;
  2797. g_pDeferredServerWork = NULL;
  2798. }
  2799. }
  2800. void SV_SendClientUpdates( bool bIsSimulating, bool bSendDuringPause )
  2801. {
  2802. bool bForcedSend = s_bForceSend;
  2803. s_bForceSend = false;
  2804. // ask game.dll to add any debug graphics
  2805. SV_PreClientUpdate( bIsSimulating );
  2806. // This causes network messages to be sent
  2807. sv.SendClientMessages( bIsSimulating || bForcedSend );
  2808. // tricky, increase stringtable tick at least one tick
  2809. // so changes made after this point are not counted to this server
  2810. // frame since we already send out the client snapshots
  2811. networkStringTableContainerServer->SetTick( sv.m_nTickCount + 1 );
  2812. }
  2813. void SV_ProcessVoice( void )
  2814. {
  2815. VPROF( "SV_ProcessVoice" );
  2816. sv.ProcessVoice();
  2817. }
  2818. extern void PrintPropSkippedReport();
  2819. void SV_Frame( bool finalTick )
  2820. {
  2821. PrintPropSkippedReport();
  2822. VPROF( "SV_Frame" );
  2823. SNPROF( "SV_Frame" );
  2824. if ( serverGameDLL && finalTick )
  2825. {
  2826. serverGameDLL->Think( finalTick );
  2827. }
  2828. if ( !sv.IsActive() || !Host_ShouldRun() )
  2829. {
  2830. // Need to process LAN searches
  2831. NET_ProcessSocket( NS_SERVER, &sv );
  2832. return;
  2833. }
  2834. g_ServerGlobalVariables.frametime = host_state.interval_per_tick;
  2835. bool bIsSimulating = SV_IsSimulating();
  2836. bool bSendDuringPause = sv_noclipduringpause ? sv_noclipduringpause->GetBool() : false;
  2837. // unlock sting tables to allow changes, helps to find unwanted changes (bebug build only)
  2838. networkStringTableContainerServer->Lock( false );
  2839. // Run any commands from client and play client Think functions if it is time.
  2840. sv.RunFrame(); // read network input etc
  2841. if ( sv.GetClientCount() > 0 )
  2842. {
  2843. bool serverCanSimulate = ( serverGameDLL && !serverGameDLL->IsRestoring() ) ? true : false;
  2844. if ( serverCanSimulate && ( bIsSimulating || bSendDuringPause ) )
  2845. {
  2846. sv.m_nTickCount++;
  2847. networkStringTableContainerServer->SetTick( sv.m_nTickCount );
  2848. }
  2849. SV_Think( bIsSimulating );
  2850. }
  2851. else if ( sv.IsMultiplayer() )
  2852. {
  2853. SV_Think( false ); // let the game.dll systems think
  2854. }
  2855. // Send the results of movement and physics to the clients
  2856. if ( finalTick )
  2857. {
  2858. if ( !IsEngineThreaded() || sv.IsMultiplayer() )
  2859. SV_SendClientUpdates( bIsSimulating, bSendDuringPause );
  2860. else
  2861. g_pDeferredServerWork = CreateFunctor( SV_SendClientUpdates, bIsSimulating, bSendDuringPause );
  2862. }
  2863. // lock string tables
  2864. networkStringTableContainerServer->Lock( true );
  2865. #if !defined(NO_STEAM)
  2866. // let the steam auth server process new connections
  2867. if ( sv.IsMultiplayer() || serverGameDLL->ShouldPreferSteamAuth() )
  2868. {
  2869. Steam3Server().RunFrame();
  2870. }
  2871. #endif
  2872. }
  2873. void SV_SetSteamCrashComment( void )
  2874. {
  2875. static bool s_bSteamApiWasInitialized = false;
  2876. if ( Steam3Server().BIsActive() )
  2877. s_bSteamApiWasInitialized = true;
  2878. if ( sv.IsDedicated() && s_bSteamApiWasInitialized )
  2879. {
  2880. extern char g_minidumpinfo[ 4094 ];
  2881. char osversion[ 256 ];
  2882. osversion[ 0 ] = 0;
  2883. #if defined(WIN32)
  2884. extern void DisplaySystemVersion( char *osversion, int maxlen );
  2885. DisplaySystemVersion( osversion, sizeof( osversion ) );
  2886. #endif
  2887. struct tm newtime;
  2888. char tString[ 128 ];
  2889. Plat_GetLocalTime( &newtime );
  2890. Plat_GetTimeString( &newtime, tString, sizeof( tString ) );
  2891. int tLen = Q_strlen( tString );
  2892. if ( tLen > 0 && tString[ tLen - 1 ] == '\n' )
  2893. {
  2894. tString[ tLen - 1 ] = 0;
  2895. }
  2896. Q_snprintf( g_minidumpinfo, sizeof(g_minidumpinfo),
  2897. "Map: %s Group: %s Ver: %d\n"\
  2898. "Game: %s\n"\
  2899. "Build: %i\n"\
  2900. "OS: %s\n"\
  2901. "Time: %s\n"\
  2902. "cmdline:%s\n" \
  2903. "protocol:%d\n",
  2904. g_ServerGlobalVariables.mapname.ToCStr(), g_ServerGlobalVariables.mapGroupName.ToCStr(), g_ServerGlobalVariables.mapversion,
  2905. com_gamedir, build_number(), osversion, tString, CommandLine()->GetCmdLine(),
  2906. g_ServerGlobalVariables.network_protocol );
  2907. #ifndef NO_STEAM
  2908. SteamAPI_SetMiniDumpComment( g_minidumpinfo );
  2909. #endif
  2910. }
  2911. }