Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2965 lines
82 KiB

  1. //
  2. // Purpose:
  3. //
  4. // $Workfile: $
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "server_pch.h"
  8. #include "decal.h"
  9. #include "host_cmd.h"
  10. #include "cmodel_engine.h"
  11. #include "sv_log.h"
  12. #include "zone.h"
  13. #include "sound.h"
  14. #include "vox.h"
  15. #include "EngineSoundInternal.h"
  16. #include "checksum_engine.h"
  17. #include "host.h"
  18. #include "keys.h"
  19. #include "vengineserver_impl.h"
  20. #include "sv_filter.h"
  21. #include "pr_edict.h"
  22. #include "screen.h"
  23. #include "sys_dll.h"
  24. #include "world.h"
  25. #include "sv_main.h"
  26. #include "networkstringtableserver.h"
  27. #include "datamap.h"
  28. #include "filesystem_engine.h"
  29. #include "string_t.h"
  30. #include "vstdlib/random.h"
  31. #include "networkstringtable.h"
  32. #include "dt_send_eng.h"
  33. #include "sv_packedentities.h"
  34. #include "testscriptmgr.h"
  35. #include "PlayerState.h"
  36. #include "saverestoretypes.h"
  37. #include "tier0/vprof.h"
  38. #include "proto_oob.h"
  39. #include "staticpropmgr.h"
  40. #include "checksum_crc.h"
  41. #include "console.h"
  42. #include "tier0/icommandline.h"
  43. #include "gl_matsysiface.h"
  44. #include "GameEventManager.h"
  45. #ifndef SWDS
  46. #include "vgui_baseui_interface.h"
  47. #endif
  48. #include "cbenchmark.h"
  49. #include "client.h"
  50. #include "hltvserver.h"
  51. #include "replay_internal.h"
  52. #include "replayserver.h"
  53. #include "KeyValues.h"
  54. #include "sv_logofile.h"
  55. #include "cl_steamauth.h"
  56. #include "sv_steamauth.h"
  57. #include "sv_plugin.h"
  58. #include "DownloadListGenerator.h"
  59. #include "sv_steamauth.h"
  60. #include "LocalNetworkBackdoor.h"
  61. #include "cvar.h"
  62. #include "enginethreads.h"
  63. #include "tier1/functors.h"
  64. #include "vstdlib/jobthread.h"
  65. #include "pure_server.h"
  66. #include "datacache/idatacache.h"
  67. #include "filesystem/IQueuedLoader.h"
  68. #include "vstdlib/jobthread.h"
  69. #include "SourceAppInfo.h"
  70. #include "cl_rcon.h"
  71. #include "host_state.h"
  72. #include "voice.h"
  73. // memdbgon must be the last include file in a .cpp file!!!
  74. #include "tier0/memdbgon.h"
  75. extern CNetworkStringTableContainer *networkStringTableContainerServer;
  76. extern CNetworkStringTableContainer *networkStringTableContainerClient;
  77. //void OnHibernateWhenEmptyChanged( IConVar *var, const char *pOldValue, float flOldValue );
  78. //ConVar sv_hibernate_when_empty( "sv_hibernate_when_empty", "1", 0, "Puts the server into extremely low CPU usage mode when no clients connected", OnHibernateWhenEmptyChanged );
  79. //ConVar sv_hibernate_ms( "sv_hibernate_ms", "20", 0, "# of milliseconds to sleep per frame while hibernating" );
  80. //ConVar sv_hibernate_ms_vgui( "sv_hibernate_ms_vgui", "20", 0, "# of milliseconds to sleep per frame while hibernating but running the vgui dedicated server frontend" );
  81. //static ConVar sv_hibernate_postgame_delay( "sv_hibernate_postgame_delay", "5", 0, "# of seconds to wait after final client leaves before hibernating.");
  82. ConVar sv_shutdown_timeout_minutes( "sv_shutdown_timeout_minutes", "360", FCVAR_REPLICATED, "If sv_shutdown is pending, wait at most N minutes for server to drain before forcing shutdown." );
  83. static double s_timeForceShutdown = 0.0;
  84. extern ConVar deathmatch;
  85. extern ConVar sv_sendtables;
  86. // Server default maxplayers value
  87. #define DEFAULT_SERVER_CLIENTS 6
  88. // This many players on a Lan with same key, is ok.
  89. #define MAX_IDENTICAL_CDKEYS 5
  90. CGameServer sv;
  91. CGlobalVars g_ServerGlobalVariables( false );
  92. static int current_skill;
  93. static void SV_CheatsChanged_f( IConVar *pConVar, const char *pOldString, float flOldValue )
  94. {
  95. ConVarRef var( pConVar );
  96. if ( var.GetInt() == 0 )
  97. {
  98. // cheats were disabled, revert all cheat cvars to their default values
  99. g_pCVar->RevertFlaggedConVars( FCVAR_CHEAT );
  100. DevMsg( "FCVAR_CHEAT cvars reverted to defaults.\n" );
  101. }
  102. }
  103. static bool g_sv_pure_waiting_on_reload = false;
  104. static int g_sv_pure_mode = 0;
  105. int GetSvPureMode()
  106. {
  107. return g_sv_pure_mode;
  108. }
  109. static void SV_Pure_f( const CCommand &args )
  110. {
  111. int pure_mode = -2;
  112. if ( args.ArgC() == 2 )
  113. {
  114. pure_mode = atoi( args[1] );
  115. }
  116. Msg( "--------------------------------------------------------\n" );
  117. if ( pure_mode >= -1 && pure_mode <= 2 )
  118. {
  119. // Not changing?
  120. if ( pure_mode == GetSvPureMode() )
  121. {
  122. Msg( "sv_pure value unchanged (current value is %d).\n", GetSvPureMode() );
  123. }
  124. else
  125. {
  126. // Set the value.
  127. g_sv_pure_mode = pure_mode;
  128. Msg( "sv_pure set to %d.\n", g_sv_pure_mode );
  129. if ( sv.IsActive() )
  130. {
  131. g_sv_pure_waiting_on_reload = true;
  132. }
  133. }
  134. }
  135. else
  136. {
  137. Msg( "sv_pure: Only allow client to use certain files.\n"
  138. "\n"
  139. " -1 - Do not apply any rules or restrict which files the client may load.\n"
  140. " 0 - Apply rules in cfg/pure_server_minimal.txt only.\n"
  141. " 1 - Apply rules in cfg/pure_server_full.txt and then cfg/pure_server_whitelist.txt.\n"
  142. " 2 - Apply rules in cfg/pure_server_full.txt.\n"
  143. "\n"
  144. " See cfg/pure_server_whitelist_example.txt for more details.\n"
  145. );
  146. }
  147. if ( pure_mode == -2 )
  148. {
  149. // If we're a client on a server with sv_pure = 1, display the current whitelist.
  150. #ifndef DEDICATED
  151. if ( cl.IsConnected() )
  152. {
  153. Msg( "\n\n" );
  154. extern void CL_PrintWhitelistInfo(); // from cl_main.cpp
  155. CL_PrintWhitelistInfo();
  156. }
  157. else
  158. #endif
  159. {
  160. Msg( "\nCurrent sv_pure value is %d.\n", GetSvPureMode() );
  161. }
  162. }
  163. if ( sv.IsActive() && g_sv_pure_waiting_on_reload )
  164. {
  165. Msg( "Note: Waiting for the next changelevel to apply the current value.\n" );
  166. }
  167. Msg( "--------------------------------------------------------\n" );
  168. }
  169. static ConCommand sv_pure( "sv_pure", SV_Pure_f, "Show user data." );
  170. ConVar sv_pure_kick_clients( "sv_pure_kick_clients", "1", 0, "If set to 1, the server will kick clients with mismatching files. Otherwise, it will issue a warning to the client." );
  171. ConVar sv_pure_trace( "sv_pure_trace", "0", 0, "If set to 1, the server will print a message whenever a client is verifying a CRC for a file." );
  172. ConVar sv_pure_consensus( "sv_pure_consensus", "5", 0, "Minimum number of file hashes to agree to form a consensus." );
  173. ConVar sv_pure_retiretime( "sv_pure_retiretime", "900", 0, "Seconds of server idle time to flush the sv_pure file hash cache." );
  174. ConVar sv_cheats( "sv_cheats", "0", FCVAR_NOTIFY|FCVAR_REPLICATED, "Allow cheats on server", SV_CheatsChanged_f );
  175. ConVar sv_lan( "sv_lan", "0", 0, "Server is a lan server ( no heartbeat, no authentication, no non-class C addresses )" );
  176. static ConVar sv_pausable( "sv_pausable","0", FCVAR_NOTIFY, "Is the server pausable." );
  177. static ConVar sv_contact( "sv_contact", "", FCVAR_NOTIFY, "Contact email for server sysop" );
  178. static ConVar sv_cacheencodedents("sv_cacheencodedents", "1", 0, "If set to 1, does an optimization to prevent extra SendTable_Encode calls.");
  179. static ConVar sv_voiceenable( "sv_voiceenable", "1", FCVAR_ARCHIVE|FCVAR_NOTIFY ); // set to 0 to disable all voice forwarding.
  180. ConVar sv_downloadurl( "sv_downloadurl", "", FCVAR_REPLICATED, "Location from which clients can download missing files" );
  181. ConVar sv_maxreplay("sv_maxreplay", "0", 0, "Maximum replay time in seconds", true, 0, true, 15 );
  182. static ConVar sv_consistency( "sv_consistency", "1", FCVAR_REPLICATED, "Legacy variable with no effect! This was deleted and then added as a temporary kludge to prevent players from being banned by servers running old versions of SMAC" );
  183. /// XXX(JohnS): When steam voice gets ugpraded to Opus we will probably default back to steam. At that time we should
  184. /// note that Steam voice is the highest quality codec below.
  185. static ConVar sv_voicecodec( "sv_voicecodec", "vaudio_celt", 0,
  186. "Specifies which voice codec to use. Valid options are:\n"
  187. "vaudio_speex - Legacy Speex codec (lowest quality)\n"
  188. "vaudio_celt - Newer CELT codec\n"
  189. "steam - Use Steam voice API" );
  190. ConVar sv_mincmdrate( "sv_mincmdrate", "10", FCVAR_REPLICATED, "This sets the minimum value for cl_cmdrate. 0 == unlimited." );
  191. ConVar sv_maxcmdrate( "sv_maxcmdrate", "66", FCVAR_REPLICATED, "(If sv_mincmdrate is > 0), this sets the maximum value for cl_cmdrate." );
  192. ConVar sv_client_cmdrate_difference( "sv_client_cmdrate_difference", "20", FCVAR_REPLICATED,
  193. "cl_cmdrate is moved to within sv_client_cmdrate_difference units of cl_updaterate before it "
  194. "is clamped between sv_mincmdrate and sv_maxcmdrate." );
  195. ConVar sv_client_min_interp_ratio( "sv_client_min_interp_ratio", "1", FCVAR_REPLICATED,
  196. "This can be used to limit the value of cl_interp_ratio for connected clients "
  197. "(only while they are connected).\n"
  198. " -1 = let clients set cl_interp_ratio to anything\n"
  199. " any other value = set minimum value for cl_interp_ratio"
  200. );
  201. ConVar sv_client_max_interp_ratio( "sv_client_max_interp_ratio", "5", FCVAR_REPLICATED,
  202. "This can be used to limit the value of cl_interp_ratio for connected clients "
  203. "(only while they are connected). If sv_client_min_interp_ratio is -1, "
  204. "then this cvar has no effect."
  205. );
  206. ConVar sv_client_predict( "sv_client_predict", "-1", FCVAR_REPLICATED,
  207. "This can be used to force the value of cl_predict for connected clients "
  208. "(only while they are connected).\n"
  209. " -1 = let clients set cl_predict to anything\n"
  210. " 0 = force cl_predict to 0\n"
  211. " 1 = force cl_predict to 1"
  212. );
  213. ConVar sv_restrict_aspect_ratio_fov( "sv_restrict_aspect_ratio_fov", "1", FCVAR_REPLICATED,
  214. "This can be used to limit the effective FOV of users using wide-screen\n"
  215. "resolutions with aspect ratios wider than 1.85:1 (slightly wider than 16:9).\n"
  216. " 0 = do not cap effective FOV\n"
  217. " 1 = limit the effective FOV on windowed mode users using resolutions\n"
  218. " greater than 1.85:1\n"
  219. " 2 = limit the effective FOV on both windowed mode and full-screen users\n",
  220. true, 0, true, 2);
  221. void OnTVEnablehanged( IConVar *pConVar, const char *pOldString, float flOldValue )
  222. {
  223. ConVarRef var( pConVar );
  224. /*
  225. ConVarRef replay_enable( "replay_enable" );
  226. if ( var.GetBool() && replay_enable.IsValid() && replay_enable.GetBool() )
  227. {
  228. var.SetValue( 0 );
  229. Warning( "Error: Replay is enabled. Please disable Replay if you wish to enable SourceTV.\n" );
  230. return;
  231. }
  232. */
  233. //Let's check maxclients and make sure we have room for SourceTV
  234. if ( var.GetBool() == true )
  235. {
  236. sv.InitMaxClients();
  237. }
  238. }
  239. ConVar tv_enable( "tv_enable", "0", FCVAR_NOTIFY, "Activates SourceTV on server.", OnTVEnablehanged );
  240. extern ConVar *sv_noclipduringpause;
  241. static bool s_bForceSend = false;
  242. void SV_ForceSend()
  243. {
  244. s_bForceSend = true;
  245. }
  246. bool g_FlushMemoryOnNextServer;
  247. int g_FlushMemoryOnNextServerCounter;
  248. void SV_FlushMemoryOnNextServer()
  249. {
  250. g_FlushMemoryOnNextServer = true;
  251. g_FlushMemoryOnNextServerCounter++;
  252. }
  253. // Prints important entity creation/deletion events to console
  254. #if defined( _DEBUG )
  255. ConVar sv_deltatrace( "sv_deltatrace", "0", 0, "For debugging, print entity creation/deletion info to console." );
  256. #define TRACE_DELTA( text ) if ( sv_deltatrace.GetInt() ) { ConMsg( text ); };
  257. #else
  258. #define TRACE_DELTA( funcs )
  259. #endif
  260. #if defined( DEBUG_NETWORKING )
  261. //-----------------------------------------------------------------------------
  262. // Opens the recording file
  263. //-----------------------------------------------------------------------------
  264. static FILE* OpenRecordingFile()
  265. {
  266. FILE* fp = 0;
  267. static bool s_CantOpenFile = false;
  268. static bool s_NeverOpened = true;
  269. if (!s_CantOpenFile)
  270. {
  271. fp = fopen( "svtrace.txt", s_NeverOpened ? "wt" : "at" );
  272. if (!fp)
  273. {
  274. s_CantOpenFile = true;
  275. }
  276. s_NeverOpened = false;
  277. }
  278. return fp;
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Records an argument for a command, flushes when the command is done
  282. //-----------------------------------------------------------------------------
  283. /*
  284. void SpewToFile( char const* pFmt, ... )
  285. static void SpewToFile( const char* pFmt, ... )
  286. {
  287. static CUtlVector<unsigned char> s_RecordingBuffer;
  288. char temp[2048];
  289. va_list args;
  290. va_start( args, pFmt );
  291. int len = Q_vsnprintf( temp, sizeof( temp ), pFmt, args );
  292. va_end( args );
  293. Assert( len < 2048 );
  294. int idx = s_RecordingBuffer.AddMultipleToTail( len );
  295. memcpy( &s_RecordingBuffer[idx], temp, len );
  296. if ( 1 ) //s_RecordingBuffer.Size() > 8192)
  297. {
  298. FILE* fp = OpenRecordingFile();
  299. fwrite( s_RecordingBuffer.Base(), 1, s_RecordingBuffer.Size(), fp );
  300. fclose( fp );
  301. s_RecordingBuffer.RemoveAll();
  302. }
  303. }
  304. */
  305. #endif // #if defined( DEBUG_NETWORKING )
  306. /*void SV_Init(bool isDedicated)
  307. {
  308. sv.Init( isDedicated );
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose:
  312. //-----------------------------------------------------------------------------
  313. void SV_Shutdown( void )
  314. {
  315. sv.Shutdown();
  316. }*/
  317. void CGameServer::Clear( void )
  318. {
  319. m_pModelPrecacheTable = NULL;
  320. m_pGenericPrecacheTable = NULL;
  321. m_pSoundPrecacheTable = NULL;
  322. m_pDecalPrecacheTable = NULL;
  323. m_pDynamicModelsTable = NULL;
  324. m_bIsLevelMainMenuBackground = false;
  325. m_bLoadgame = false;
  326. host_state.SetWorldModel( NULL );
  327. Q_memset( m_szStartspot, 0, sizeof( m_szStartspot ) );
  328. num_edicts = 0;
  329. max_edicts = 0;
  330. free_edicts = 0;
  331. edicts = NULL;
  332. // Clear the instance baseline indices in the ServerClasses.
  333. if ( serverGameDLL )
  334. {
  335. for( ServerClass *pCur = serverGameDLL->GetAllServerClasses(); pCur; pCur=pCur->m_pNext )
  336. {
  337. pCur->m_InstanceBaselineIndex = INVALID_STRING_INDEX;
  338. }
  339. }
  340. for ( int i = 0; i < m_TempEntities.Count(); i++ )
  341. {
  342. delete m_TempEntities[i];
  343. }
  344. m_TempEntities.Purge();
  345. CBaseServer::Clear();
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose: Create any client/server string tables needed internally by the engine
  349. //-----------------------------------------------------------------------------
  350. void CGameServer::CreateEngineStringTables( void )
  351. {
  352. int i,j;
  353. m_StringTables->SetTick( m_nTickCount ); // set first tick
  354. bool bUseFilenameTables = false;
  355. char szDownloadableFileTablename[255] = DOWNLOADABLE_FILE_TABLENAME;
  356. char szModelPrecacheTablename[255] = MODEL_PRECACHE_TABLENAME;
  357. char szGenericPrecacheTablename[255] = GENERIC_PRECACHE_TABLENAME;
  358. char szSoundPrecacheTablename[255] = SOUND_PRECACHE_TABLENAME;
  359. char szDecalPrecacheTablename[255] = DECAL_PRECACHE_TABLENAME;
  360. // This was added into staging at some point and is not enabled in main or rel.
  361. if ( 0 )
  362. {
  363. bUseFilenameTables = true;
  364. Q_snprintf( szDownloadableFileTablename, 255, ":%s", DOWNLOADABLE_FILE_TABLENAME );
  365. Q_snprintf( szModelPrecacheTablename, 255, ":%s", MODEL_PRECACHE_TABLENAME );
  366. Q_snprintf( szGenericPrecacheTablename, 255, ":%s", GENERIC_PRECACHE_TABLENAME );
  367. Q_snprintf( szSoundPrecacheTablename, 255, ":%s", SOUND_PRECACHE_TABLENAME );
  368. Q_snprintf( szDecalPrecacheTablename, 255, ":%s", DECAL_PRECACHE_TABLENAME );
  369. }
  370. m_pDownloadableFileTable = m_StringTables->CreateStringTableEx(
  371. szDownloadableFileTablename,
  372. MAX_DOWNLOADABLE_FILES,
  373. 0,
  374. 0,
  375. bUseFilenameTables );
  376. m_pModelPrecacheTable = m_StringTables->CreateStringTableEx(
  377. szModelPrecacheTablename,
  378. MAX_MODELS,
  379. sizeof ( CPrecacheUserData ),
  380. PRECACHE_USER_DATA_NUMBITS,
  381. bUseFilenameTables );
  382. m_pGenericPrecacheTable = m_StringTables->CreateStringTableEx(
  383. szGenericPrecacheTablename,
  384. MAX_GENERIC,
  385. sizeof ( CPrecacheUserData ),
  386. PRECACHE_USER_DATA_NUMBITS,
  387. bUseFilenameTables );
  388. m_pSoundPrecacheTable = m_StringTables->CreateStringTableEx(
  389. szSoundPrecacheTablename,
  390. MAX_SOUNDS,
  391. sizeof ( CPrecacheUserData ),
  392. PRECACHE_USER_DATA_NUMBITS,
  393. bUseFilenameTables );
  394. m_pDecalPrecacheTable = m_StringTables->CreateStringTableEx(
  395. szDecalPrecacheTablename,
  396. MAX_BASE_DECALS,
  397. sizeof ( CPrecacheUserData ),
  398. PRECACHE_USER_DATA_NUMBITS,
  399. bUseFilenameTables );
  400. m_pInstanceBaselineTable = m_StringTables->CreateStringTable(
  401. INSTANCE_BASELINE_TABLENAME,
  402. MAX_DATATABLES );
  403. m_pLightStyleTable = m_StringTables->CreateStringTable(
  404. LIGHT_STYLES_TABLENAME,
  405. MAX_LIGHTSTYLES );
  406. m_pUserInfoTable = m_StringTables->CreateStringTable(
  407. USER_INFO_TABLENAME,
  408. 1<<ABSOLUTE_PLAYER_LIMIT_DW ); // make it a power of 2
  409. // Fixed-size user data; bit value of either 0 or 1.
  410. m_pDynamicModelsTable = m_StringTables->CreateStringTable( "DynamicModels", 2048, true, 1 );
  411. // Send the query info..
  412. m_pServerStartupTable = m_StringTables->CreateStringTable(
  413. SERVER_STARTUP_DATA_TABLENAME,
  414. 4 );
  415. SetQueryPortFromSteamServer();
  416. CopyPureServerWhitelistToStringTable();
  417. Assert ( m_pModelPrecacheTable &&
  418. m_pGenericPrecacheTable &&
  419. m_pSoundPrecacheTable &&
  420. m_pDecalPrecacheTable &&
  421. m_pInstanceBaselineTable &&
  422. m_pLightStyleTable &&
  423. m_pUserInfoTable &&
  424. m_pServerStartupTable &&
  425. m_pDownloadableFileTable &&
  426. m_pDynamicModelsTable );
  427. // create an empty lightstyle table with unique index names
  428. for ( i = 0; i<MAX_LIGHTSTYLES; i++ )
  429. {
  430. char name[8]; Q_snprintf( name, 8, "%i", i );
  431. j = m_pLightStyleTable->AddString( true, name );
  432. Assert( j==i ); // indices must match
  433. }
  434. for ( i = 0; i<GetMaxClients(); i++ )
  435. {
  436. char name[8]; Q_snprintf( name, 8, "%i", i );
  437. j = m_pUserInfoTable->AddString( true, name );
  438. Assert( j==i ); // indices must match
  439. }
  440. // set up the downloadable files generator
  441. DownloadListGenerator().SetStringTable( m_pDownloadableFileTable );
  442. }
  443. void CGameServer::SetQueryPortFromSteamServer()
  444. {
  445. if ( !m_pServerStartupTable )
  446. return;
  447. int queryPort = Steam3Server().GetQueryPort();
  448. m_pServerStartupTable->AddString( true, "QueryPort", sizeof( queryPort ), &queryPort );
  449. }
  450. void CGameServer::CopyPureServerWhitelistToStringTable()
  451. {
  452. if ( !m_pPureServerWhitelist )
  453. return;
  454. CUtlBuffer buf;
  455. m_pPureServerWhitelist->Encode( buf );
  456. m_pServerStartupTable->AddString( true, "PureServerWhitelist", buf.TellPut(), buf.Base() );
  457. }
  458. void SV_InstallClientStringTableMirrors( void )
  459. {
  460. #ifndef SWDS
  461. #ifndef SHARED_NET_STRING_TABLES
  462. int numTables = networkStringTableContainerServer->GetNumTables();
  463. for ( int i =0; i<numTables; i++)
  464. {
  465. // iterate through server tables
  466. CNetworkStringTable *serverTable =
  467. (CNetworkStringTable*)networkStringTableContainerServer->GetTable( i );
  468. if ( !serverTable )
  469. continue;
  470. // get mathcing client table
  471. CNetworkStringTable *clientTable =
  472. (CNetworkStringTable*)networkStringTableContainerClient->FindTable( serverTable->GetTableName() );
  473. if ( !clientTable )
  474. {
  475. DevMsg("SV_InstallClientStringTableMirrors! Missing client table \"%s\".\n ", serverTable->GetTableName() );
  476. continue;
  477. }
  478. // link client table to server table
  479. serverTable->SetMirrorTable( clientTable );
  480. }
  481. #endif
  482. #endif
  483. }
  484. //-----------------------------------------------------------------------------
  485. // user <name or userid>
  486. //
  487. // Dump userdata / masterdata for a user
  488. //-----------------------------------------------------------------------------
  489. CON_COMMAND( user, "Show user data." )
  490. {
  491. int uid;
  492. int i;
  493. if ( !sv.IsActive() )
  494. {
  495. ConMsg( "Can't 'user', not running a server\n" );
  496. return;
  497. }
  498. if (args.ArgC() != 2)
  499. {
  500. ConMsg ("Usage: user <username / userid>\n");
  501. return;
  502. }
  503. uid = atoi(args[1]);
  504. for (i=0 ; i< sv.GetClientCount() ; i++)
  505. {
  506. IClient *pClient = sv.GetClient( i );
  507. if ( !pClient->IsConnected() )
  508. continue;
  509. if ( (pClient->GetPlayerSlot()== uid ) || !Q_strcmp( pClient->GetClientName(), args[1]) )
  510. {
  511. ConMsg ("TODO: SV_User_f.\n");
  512. return;
  513. }
  514. }
  515. ConMsg ("User not in server.\n");
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Dump userids for all current players
  519. //-----------------------------------------------------------------------------
  520. CON_COMMAND( users, "Show user info for players on server." )
  521. {
  522. if ( !sv.IsActive() )
  523. {
  524. ConMsg( "Can't 'users', not running a server\n" );
  525. return;
  526. }
  527. int c = 0;
  528. ConMsg ("<slot:userid:\"name\">\n");
  529. for ( int i=0 ; i< sv.GetClientCount() ; i++ )
  530. {
  531. IClient *pClient = sv.GetClient( i );
  532. if ( pClient->IsConnected() )
  533. {
  534. ConMsg ("%i:%i:\"%s\"\n", pClient->GetPlayerSlot(), pClient->GetUserID(), pClient->GetClientName() );
  535. c++;
  536. }
  537. }
  538. ConMsg ( "%i users\n", c );
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose: Determine the value of sv.maxclients
  542. //-----------------------------------------------------------------------------
  543. bool CL_IsHL2Demo(); // from cl_main.cpp
  544. bool CL_IsPortalDemo(); // from cl_main.cpp
  545. extern ConVar tv_enable;
  546. void SetupMaxPlayers( int iDesiredMaxPlayers )
  547. {
  548. int minmaxplayers = 1;
  549. int maxmaxplayers = ABSOLUTE_PLAYER_LIMIT;
  550. int defaultmaxplayers = 1;
  551. if ( serverGameClients )
  552. {
  553. serverGameClients->GetPlayerLimits( minmaxplayers, maxmaxplayers, defaultmaxplayers );
  554. if ( minmaxplayers < 1 )
  555. {
  556. Sys_Error( "GetPlayerLimits: min maxplayers must be >= 1 (%i)", minmaxplayers );
  557. }
  558. else if ( defaultmaxplayers < 1 )
  559. {
  560. Sys_Error( "GetPlayerLimits: default maxplayers must be >= 1 (%i)", minmaxplayers );
  561. }
  562. if ( minmaxplayers > maxmaxplayers || defaultmaxplayers > maxmaxplayers )
  563. {
  564. Sys_Error( "GetPlayerLimits: min maxplayers %i > max %i", minmaxplayers, maxmaxplayers );
  565. }
  566. if ( maxmaxplayers > ABSOLUTE_PLAYER_LIMIT )
  567. {
  568. Sys_Error( "GetPlayerLimits: max players limited to %i", ABSOLUTE_PLAYER_LIMIT );
  569. }
  570. }
  571. // Determine absolute limit
  572. sv.m_nMaxClientsLimit = maxmaxplayers;
  573. // Check for command line override
  574. int newmaxplayers = iDesiredMaxPlayers;
  575. if ( newmaxplayers >= 1 )
  576. {
  577. // Never go above what the game .dll can handle
  578. newmaxplayers = min( newmaxplayers, maxmaxplayers );
  579. sv.m_nMaxClientsLimit = newmaxplayers;
  580. }
  581. else
  582. {
  583. newmaxplayers = defaultmaxplayers;
  584. }
  585. #if defined( REPLAY_ENABLED )
  586. if ( Replay_IsSupportedModAndPlatform() && CommandLine()->CheckParm( "-replay" ) )
  587. {
  588. newmaxplayers += 1;
  589. sv.m_nMaxClientsLimit += 1;
  590. }
  591. #endif
  592. if ( tv_enable.GetBool() )
  593. {
  594. newmaxplayers += 1;
  595. sv.m_nMaxClientsLimit += 1;
  596. }
  597. newmaxplayers = clamp( newmaxplayers, minmaxplayers, sv.m_nMaxClientsLimit );
  598. if ( ( CL_IsHL2Demo() || CL_IsPortalDemo() ) && !sv.IsDedicated() )
  599. {
  600. newmaxplayers = 1;
  601. sv.m_nMaxClientsLimit = 1;
  602. }
  603. if ( sv.GetMaxClients() < newmaxplayers || !tv_enable.GetBool() )
  604. sv.SetMaxClients( newmaxplayers );
  605. }
  606. void CGameServer::InitMaxClients( void )
  607. {
  608. int newmaxplayers = CommandLine()->ParmValue( "-maxplayers", -1 );
  609. if ( newmaxplayers == -1 )
  610. {
  611. newmaxplayers = CommandLine()->ParmValue( "+maxplayers", -1 );
  612. }
  613. SetupMaxPlayers( newmaxplayers );
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Purpose: Changes the maximum # of players allowed on the server.
  617. // Server cannot be running when command is issued.
  618. //-----------------------------------------------------------------------------
  619. CON_COMMAND( maxplayers, "Change the maximum number of players allowed on this server." )
  620. {
  621. if ( args.ArgC () != 2 )
  622. {
  623. ConMsg ("\"maxplayers\" is \"%u\"\n", sv.GetMaxClients() );
  624. return;
  625. }
  626. if ( sv.IsActive() )
  627. {
  628. ConMsg( "Cannot change maxplayers while the server is running\n");
  629. return;
  630. }
  631. SetupMaxPlayers( Q_atoi( args[ 1 ] ) );
  632. }
  633. int SV_BuildSendTablesArray( ServerClass *pClasses, SendTable **pTables, int nMaxTables )
  634. {
  635. int nTables = 0;
  636. for( ServerClass *pCur=pClasses; pCur; pCur=pCur->m_pNext )
  637. {
  638. ErrorIfNot( nTables < nMaxTables, ("SV_BuildSendTablesArray: too many SendTables!") );
  639. pTables[nTables] = pCur->m_pTable;
  640. ++nTables;
  641. }
  642. return nTables;
  643. }
  644. // Builds an alternate copy of the datatable for any classes that have datatables with props excluded.
  645. void SV_InitSendTables( ServerClass *pClasses )
  646. {
  647. SendTable *pTables[MAX_DATATABLES];
  648. int nTables = SV_BuildSendTablesArray( pClasses, pTables, ARRAYSIZE( pTables ) );
  649. SendTable_Init( pTables, nTables );
  650. }
  651. void SV_TermSendTables( ServerClass *pClasses )
  652. {
  653. SendTable_Term();
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Purpose: returns which games/mods we're allowed to play
  657. //-----------------------------------------------------------------------------
  658. struct ModDirPermissions_t
  659. {
  660. int m_iAppID;
  661. const char *m_pchGameDir;
  662. };
  663. static ModDirPermissions_t g_ModDirPermissions[] =
  664. {
  665. { GetAppSteamAppId( k_App_CSS ), GetAppModName( k_App_CSS ) },
  666. { GetAppSteamAppId( k_App_DODS ), GetAppModName( k_App_DODS ) },
  667. { GetAppSteamAppId( k_App_HL2MP ), GetAppModName( k_App_HL2MP ) },
  668. { GetAppSteamAppId( k_App_LOST_COAST ), GetAppModName( k_App_LOST_COAST ) },
  669. { GetAppSteamAppId( k_App_HL1DM ), GetAppModName( k_App_HL1DM ) },
  670. { GetAppSteamAppId( k_App_PORTAL ), GetAppModName( k_App_PORTAL ) },
  671. { GetAppSteamAppId( k_App_HL2 ), GetAppModName( k_App_HL2 ) },
  672. { GetAppSteamAppId( k_App_HL2_EP1 ), GetAppModName( k_App_HL2_EP1 ) },
  673. { GetAppSteamAppId( k_App_HL2_EP2 ), GetAppModName( k_App_HL2_EP2 ) },
  674. { GetAppSteamAppId( k_App_TF2 ), GetAppModName( k_App_TF2 ) },
  675. };
  676. bool ServerDLL_Load( bool bIsServerOnly )
  677. {
  678. // Load in the game .dll
  679. LoadEntityDLLs( GetBaseDirectory(), bIsServerOnly );
  680. return true;
  681. }
  682. void ServerDLL_Unload()
  683. {
  684. UnloadEntityDLLs();
  685. }
  686. #if !defined(DEDICATED)
  687. #if !defined(_X360)
  688. // Put this function declaration at global scope to avoid the ambiguity of the most vexing parse.
  689. bool CL_IsHL2Demo();
  690. #endif
  691. #endif
  692. //-----------------------------------------------------------------------------
  693. // Purpose: Loads the game .dll
  694. //-----------------------------------------------------------------------------
  695. void SV_InitGameDLL( void )
  696. {
  697. // Clear out the command buffer.
  698. Cbuf_Execute();
  699. // Don't initialize a second time
  700. if ( sv.dll_initialized )
  701. {
  702. return;
  703. }
  704. #if !defined(SWDS)
  705. #if !defined(_X360)
  706. if ( CL_IsHL2Demo() && !sv.IsDedicated() && Q_stricmp( COM_GetModDirectory(), "hl2" ) )
  707. {
  708. Error( "The HL2 demo is unable to run Mods.\n" );
  709. return;
  710. }
  711. if ( CL_IsPortalDemo() && !sv.IsDedicated() && Q_stricmp( COM_GetModDirectory(), "portal" ) )
  712. {
  713. Error( "The Portal demo is unable to run Mods.\n" );
  714. return;
  715. }
  716. // check permissions
  717. if ( Steam3Client().SteamApps() && !CL_IsHL2Demo() && !CL_IsPortalDemo() )
  718. {
  719. bool bVerifiedMod = false;
  720. // find the game dir we're running
  721. for ( int i = 0; i < ARRAYSIZE( g_ModDirPermissions ); i++ )
  722. {
  723. if ( !Q_stricmp( COM_GetModDirectory(), g_ModDirPermissions[i].m_pchGameDir ) )
  724. {
  725. // we've found the mod, make sure we own the app
  726. if ( Steam3Client().SteamApps()->BIsSubscribedApp( g_ModDirPermissions[i].m_iAppID ) )
  727. {
  728. bVerifiedMod = true;
  729. }
  730. else
  731. {
  732. Error( "No permissions to run '%s'\n", COM_GetModDirectory() );
  733. return;
  734. }
  735. break;
  736. }
  737. }
  738. if ( !bVerifiedMod )
  739. {
  740. // make sure they can run the Source engine
  741. if ( ! Steam3Client().SteamApps()->BIsSubscribedApp( 215 ) )
  742. {
  743. Error( "A Source engine game is required to run mods\n" );
  744. return;
  745. }
  746. }
  747. }
  748. #endif // _X360
  749. #endif
  750. COM_TimestampedLog( "SV_InitGameDLL" );
  751. if ( !serverGameDLL )
  752. {
  753. Warning( "Failed to load server binary\n" );
  754. return;
  755. }
  756. // Flag that we've started the game .dll
  757. sv.dll_initialized = true;
  758. COM_TimestampedLog( "serverGameDLL->DLLInit" );
  759. // Tell the game DLL to start up
  760. if(!serverGameDLL->DLLInit(g_AppSystemFactory, g_AppSystemFactory, g_AppSystemFactory, &g_ServerGlobalVariables))
  761. {
  762. Host_Error("IDLLFunctions::DLLInit returned false.\n");
  763. }
  764. if ( CommandLine()->FindParm( "-NoLoadPluginsForClient" ) == 0 )
  765. g_pServerPluginHandler->LoadPlugins(); // load 3rd party plugins
  766. // let's not have any servers with no name
  767. if ( host_name.GetString()[0] == 0 )
  768. {
  769. host_name.SetValue( serverGameDLL->GetGameDescription() );
  770. }
  771. sv_noclipduringpause = ( ConVar * )g_pCVar->FindVar( "sv_noclipduringpause" );
  772. COM_TimestampedLog( "SV_InitSendTables" );
  773. // Make extra copies of data tables if they have SendPropExcludes.
  774. SV_InitSendTables( serverGameDLL->GetAllServerClasses() );
  775. host_state.interval_per_tick = serverGameDLL->GetTickInterval();
  776. if ( host_state.interval_per_tick < MINIMUM_TICK_INTERVAL ||
  777. host_state.interval_per_tick > MAXIMUM_TICK_INTERVAL )
  778. {
  779. Sys_Error( "GetTickInterval returned bogus tick interval (%f)[%f to %f is valid range]", host_state.interval_per_tick,
  780. MINIMUM_TICK_INTERVAL, MAXIMUM_TICK_INTERVAL );
  781. }
  782. // set maxclients limit based on Mod or commandline settings
  783. sv.InitMaxClients();
  784. // Execute and server commands the game .dll added at startup
  785. Cbuf_Execute();
  786. #if defined( REPLAY_ENABLED )
  787. extern IReplaySystem *g_pReplay;
  788. if ( Replay_IsSupportedModAndPlatform() && sv.IsDedicated() )
  789. {
  790. if ( !serverGameDLL->ReplayInit( g_fnReplayFactory ) )
  791. {
  792. Sys_Error( "Server replay init failed" );
  793. }
  794. if ( sv.IsDedicated() && !g_pReplay->SV_Init( g_ServerFactory ) )
  795. {
  796. Sys_Error( "Replay system server init failed!" );
  797. }
  798. }
  799. #endif
  800. }
  801. //
  802. // Release resources associated with extension DLLs.
  803. //
  804. void SV_ShutdownGameDLL( void )
  805. {
  806. if ( !sv.dll_initialized )
  807. {
  808. return;
  809. }
  810. if ( g_pReplay )
  811. {
  812. g_pReplay->SV_Shutdown();
  813. }
  814. // Delete any extra SendTable copies we've attached to the game DLL's classes, if any.
  815. SV_TermSendTables( serverGameDLL->GetAllServerClasses() );
  816. g_pServerPluginHandler->UnloadPlugins();
  817. serverGameDLL->DLLShutdown();
  818. UnloadEntityDLLs();
  819. sv.dll_initialized = false;
  820. }
  821. ServerClass* SV_FindServerClass( const char *pName )
  822. {
  823. ServerClass *pCur = serverGameDLL->GetAllServerClasses();
  824. while ( pCur )
  825. {
  826. if ( Q_stricmp( pCur->GetName(), pName ) == 0 )
  827. return pCur;
  828. pCur = pCur->m_pNext;
  829. }
  830. return NULL;
  831. }
  832. ServerClass* SV_FindServerClass( int index )
  833. {
  834. ServerClass *pCur = serverGameDLL->GetAllServerClasses();
  835. int count = 0;
  836. while ( (count < index) && (pCur != NULL) )
  837. {
  838. count++;
  839. pCur = pCur->m_pNext;
  840. }
  841. return pCur;
  842. }
  843. //-----------------------------------------------------------------------------
  844. // Purpose: General initialization of the server
  845. //-----------------------------------------------------------------------------
  846. void CGameServer::Init (bool isDedicated)
  847. {
  848. CBaseServer::Init( isDedicated );
  849. m_FullSendTables.SetDebugName( "m_FullSendTables" );
  850. dll_initialized = false;
  851. }
  852. bool CGameServer::IsPausable( void ) const
  853. {
  854. // In single-player, they can always pause it. In multiplayer, check the cvar.
  855. if ( IsMultiplayer() )
  856. {
  857. return sv_pausable.GetBool();
  858. }
  859. else
  860. {
  861. return true;
  862. }
  863. }
  864. void CGameServer::Shutdown( void )
  865. {
  866. m_bIsLevelMainMenuBackground = false;
  867. CBaseServer::Shutdown();
  868. // Actually performs a shutdown.
  869. framesnapshotmanager->LevelChanged();
  870. IGameEvent *event = g_GameEventManager.CreateEvent( "server_shutdown" );
  871. if ( event )
  872. {
  873. event->SetString( "reason", "quit" );
  874. g_GameEventManager.FireEvent( event );
  875. }
  876. Steam3Server().Shutdown();
  877. if ( serverGameDLL && g_iServerGameDLLVersion >= 7 )
  878. {
  879. serverGameDLL->GameServerSteamAPIShutdown();
  880. }
  881. // Log_Printf( "Server shutdown.\n" );
  882. g_Log.Close();
  883. }
  884. /*
  885. ==================
  886. SV_StartSound
  887. Each entity can have eight independant sound sources, like voice,
  888. weapon, feet, etc.
  889. Channel 0 is an auto-allocate channel, the others override anything
  890. allready running on that entity/channel pair.
  891. An attenuation of 0 will play full volume everywhere in the level.
  892. Larger attenuations will drop off. (max 4 attenuation)
  893. Pitch should be PITCH_NORM (100) for no pitch shift. Values over 100 (up to 255)
  894. shift pitch higher, values lower than 100 lower the pitch.
  895. ==================
  896. */
  897. void SV_StartSound ( IRecipientFilter& filter, edict_t *pSoundEmittingEntity, int iChannel,
  898. const char *pSample, float flVolume, soundlevel_t iSoundLevel, int iFlags,
  899. int iPitch, int iSpecialDSP, const Vector *pOrigin, float soundtime, int speakerentity, CUtlVector< Vector >* pUtlVecOrigins )
  900. {
  901. SoundInfo_t sound;
  902. sound.SetDefault();
  903. sound.nEntityIndex = pSoundEmittingEntity ? NUM_FOR_EDICT( pSoundEmittingEntity ) : 0;
  904. sound.nChannel = iChannel;
  905. sound.fVolume = flVolume;
  906. sound.Soundlevel = iSoundLevel;
  907. sound.nFlags = iFlags;
  908. sound.nPitch = iPitch;
  909. sound.nSpecialDSP = iSpecialDSP;
  910. sound.nSpeakerEntity = speakerentity;
  911. if ( iFlags & SND_STOP )
  912. {
  913. Assert( filter.IsReliable() );
  914. }
  915. // Compute the sound origin
  916. if ( pOrigin )
  917. {
  918. VectorCopy( *pOrigin, sound.vOrigin );
  919. }
  920. else if ( pSoundEmittingEntity )
  921. {
  922. IServerEntity *serverEntity = pSoundEmittingEntity->GetIServerEntity();
  923. if ( serverEntity )
  924. {
  925. CM_WorldSpaceCenter( serverEntity->GetCollideable(), &sound.vOrigin );
  926. }
  927. }
  928. // Add actual sound origin to vector if requested
  929. if ( pUtlVecOrigins )
  930. {
  931. (*pUtlVecOrigins).AddToTail( sound.vOrigin );
  932. }
  933. // set sound delay
  934. if ( soundtime != 0.0f )
  935. {
  936. // add one tick since server time ends at the current tick
  937. // we'd rather delay sounds slightly than skip the beginning samples
  938. // so add one tick of latency
  939. soundtime += sv.GetTickInterval();
  940. sound.fDelay = soundtime - sv.GetFinalTickTime();
  941. sound.nFlags |= SND_DELAY;
  942. #if 0
  943. static float lastSoundTime = 0;
  944. Msg("SV: [%.3f] Play %s at %.3f\n", soundtime - lastSoundTime, pSample, soundtime );
  945. lastSoundTime = soundtime;
  946. #endif
  947. }
  948. // find precache number for sound
  949. // if this is a sentence, get sentence number
  950. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  951. {
  952. sound.bIsSentence = true;
  953. sound.nSoundNum = Q_atoi( PSkipSoundChars(pSample) );
  954. if ( sound.nSoundNum >= VOX_SentenceCount() )
  955. {
  956. ConMsg("SV_StartSound: invalid sentence number: %s", PSkipSoundChars(pSample));
  957. return;
  958. }
  959. }
  960. else
  961. {
  962. sound.bIsSentence = false;
  963. sound.nSoundNum = sv.LookupSoundIndex( pSample );
  964. if ( !sound.nSoundNum || !sv.GetSound( sound.nSoundNum ) )
  965. {
  966. ConMsg ("SV_StartSound: %s not precached (%d)\n", pSample, sound.nSoundNum );
  967. return;
  968. }
  969. }
  970. // now sound message is complete, send to clients in filter
  971. sv.BroadcastSound( sound, filter );
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose: Sets bits of playerbits based on valid multicast recipients
  975. // Input : usepas -
  976. // origin -
  977. // playerbits -
  978. //-----------------------------------------------------------------------------
  979. void SV_DetermineMulticastRecipients( bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits )
  980. {
  981. // determine cluster for origin
  982. int cluster = CM_LeafCluster( CM_PointLeafnum( origin ) );
  983. byte pvs[MAX_MAP_LEAFS/8];
  984. int visType = usepas ? DVIS_PAS : DVIS_PVS;
  985. const byte *pMask = CM_Vis( pvs, sizeof(pvs), cluster, visType );
  986. playerbits.ClearAll();
  987. // Check for relevent clients
  988. for (int i = 0; i < sv.GetClientCount(); i++ )
  989. {
  990. CGameClient *pClient = sv.Client( i );
  991. if ( !pClient->IsActive() )
  992. continue;
  993. // HACK: Should above also check pClient->spawned instead of this
  994. if ( !pClient->edict || pClient->edict->IsFree() || pClient->edict->GetUnknown() == NULL )
  995. continue;
  996. // Always add the or Replay client
  997. #if defined( REPLAY_ENABLED )
  998. if ( pClient->IsHLTV() || pClient->IsReplay() )
  999. #else
  1000. if ( pClient->IsHLTV() )
  1001. #endif
  1002. {
  1003. playerbits.Set( i );
  1004. continue;
  1005. }
  1006. Vector vecEarPosition;
  1007. serverGameClients->ClientEarPosition( pClient->edict, &vecEarPosition );
  1008. int iBitNumber = CM_LeafCluster( CM_PointLeafnum( vecEarPosition ) );
  1009. if ( !(pMask[iBitNumber>>3] & (1<<(iBitNumber&7)) ) )
  1010. continue;
  1011. playerbits.Set( i );
  1012. }
  1013. }
  1014. //-----------------------------------------------------------------------------
  1015. // Purpose: Write single ConVar change to all connected clients
  1016. // Input : *var -
  1017. // *newValue -
  1018. //-----------------------------------------------------------------------------
  1019. void SV_ReplicateConVarChange( ConVar const *var, const char *newValue )
  1020. {
  1021. Assert( var );
  1022. Assert( var->IsFlagSet( FCVAR_REPLICATED ) );
  1023. Assert( newValue );
  1024. if ( !sv.IsActive() || !sv.IsMultiplayer() )
  1025. return;
  1026. NET_SetConVar cvarMsg( var->GetName(), Host_CleanupConVarStringValue( newValue ) );
  1027. sv.BroadcastMessage( cvarMsg );
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose: Execute a command on all clients or a particular client
  1031. // Input : *var -
  1032. // *newValue -
  1033. //-----------------------------------------------------------------------------
  1034. void SV_ExecuteRemoteCommand( const char *pCommand, int nClientSlot )
  1035. {
  1036. if ( !sv.IsActive() || !sv.IsMultiplayer() )
  1037. return;
  1038. NET_StringCmd cmdMsg( pCommand );
  1039. if ( nClientSlot >= 0 )
  1040. {
  1041. CEngineSingleUserFilter filter( nClientSlot + 1, true );
  1042. sv.BroadcastMessage( cmdMsg, filter );
  1043. }
  1044. else
  1045. {
  1046. sv.BroadcastMessage( cmdMsg );
  1047. }
  1048. }
  1049. /*
  1050. ==============================================================================
  1051. CLIENT SPAWNING
  1052. ==============================================================================
  1053. */
  1054. CGameServer::CGameServer()
  1055. {
  1056. m_nMaxClientsLimit = 0;
  1057. m_pPureServerWhitelist = NULL;
  1058. m_bHibernating = false;
  1059. m_bLoadedPlugins = false;
  1060. V_memset( m_szMapname, 0, sizeof( m_szMapname ) );
  1061. V_memset( m_szMapFilename, 0, sizeof( m_szMapFilename ) );
  1062. }
  1063. CGameServer::~CGameServer()
  1064. {
  1065. if ( m_pPureServerWhitelist )
  1066. m_pPureServerWhitelist->Release();
  1067. }
  1068. //-----------------------------------------------------------------------------
  1069. // Purpose: Disconnects the client and cleans out the m_pEnt CBasePlayer container object
  1070. // Input : *clientedict -
  1071. //-----------------------------------------------------------------------------
  1072. void CGameServer::RemoveClientFromGame( CBaseClient *client )
  1073. {
  1074. CGameClient *pClient = (CGameClient*)client;
  1075. // we must have an active server and a spawned client
  1076. // If we are a local server and we're disconnecting just return
  1077. if ( !pClient->edict || !pClient->IsSpawned() || !IsActive() || (pClient->GetNetChannel() && pClient->GetNetChannel()->IsLoopback() ) )
  1078. return;
  1079. Assert( g_pServerPluginHandler );
  1080. g_pServerPluginHandler->ClientDisconnect( pClient->edict );
  1081. // release the DLL entity that's attached to this edict, if any
  1082. serverGameEnts->FreeContainingEntity( pClient->edict );
  1083. }
  1084. static int s_iNetSpikeValue = -1;
  1085. int GetNetSpikeValue()
  1086. {
  1087. // Read from the command line the first time
  1088. if ( s_iNetSpikeValue < 0 )
  1089. s_iNetSpikeValue = Max( V_atoi( CommandLine()->ParmValue( "-netspike", "0" ) ), 0 );
  1090. return s_iNetSpikeValue;
  1091. }
  1092. const char szSvNetSpikeUsageText[] =
  1093. "Write network trace if amount of data sent to client exceeds N bytes. Use zero to disable tracing.\n"
  1094. "Note that having this enabled, even if never triggered, impacts performance. Set to zero when not in use.\n"
  1095. "For compatibility reasons, this command can be initialized on the command line with the -netspike option.";
  1096. static void sv_netspike_f( const CCommand &args )
  1097. {
  1098. if ( args.ArgC() != 2 )
  1099. {
  1100. Msg( "%s\n\n", szSvNetSpikeUsageText );
  1101. Msg( "sv_netspike value is currently %d\n", GetNetSpikeValue() );
  1102. return;
  1103. }
  1104. s_iNetSpikeValue = Max( V_atoi( args.Arg( 1 ) ), 0 );
  1105. }
  1106. static ConCommand sv_netspike( "sv_netspike", sv_netspike_f, szSvNetSpikeUsageText
  1107. );
  1108. CBaseClient *CGameServer::CreateNewClient(int slot )
  1109. {
  1110. CBaseClient *pClient = new CGameClient( slot, this );
  1111. return pClient;
  1112. }
  1113. /*
  1114. ================
  1115. SV_FinishCertificateCheck
  1116. For LAN connections, make sure we don't have too many people with same cd key hash
  1117. For Authenticated net connections, check the certificate and also double check won userid
  1118. from that certificate
  1119. ================
  1120. */
  1121. bool CGameServer::FinishCertificateCheck( netadr_t &adr, int nAuthProtocol, const char *szRawCertificate, int clientChallenge )
  1122. {
  1123. // Now check auth information
  1124. switch ( nAuthProtocol )
  1125. {
  1126. default:
  1127. case PROTOCOL_AUTHCERTIFICATE:
  1128. RejectConnection( adr, clientChallenge, "#GameUI_ServerAuthDisabled");
  1129. return false;
  1130. case PROTOCOL_STEAM:
  1131. return true; // the SteamAuthServer() state machine checks this
  1132. break;
  1133. case PROTOCOL_HASHEDCDKEY:
  1134. if ( AllowDebugDedicatedServerOutsideSteam() )
  1135. return true;
  1136. if ( !Host_IsSinglePlayerGame() || sv.IsDedicated()) // PROTOCOL_HASHEDCDKEY isn't allowed for multiplayer servers
  1137. {
  1138. RejectConnection( adr, clientChallenge, "#GameUI_ServerCDKeyAuthInvalid" );
  1139. return false;
  1140. }
  1141. if ( Q_strlen( szRawCertificate ) != 32 )
  1142. {
  1143. RejectConnection( adr, clientChallenge, "#GameUI_ServerInvalidCDKey" );
  1144. return false;
  1145. }
  1146. int nHashCount = 0;
  1147. // Now make sure that this hash isn't "overused"
  1148. for ( int i=0; i< GetClientCount(); i++ )
  1149. {
  1150. CBaseClient *pClient = Client(i);
  1151. if ( !pClient->IsConnected() )
  1152. continue;
  1153. if ( Q_strnicmp ( szRawCertificate, pClient->m_GUID, SIGNED_GUID_LEN ) )
  1154. continue;
  1155. nHashCount++;
  1156. }
  1157. if ( nHashCount >= MAX_IDENTICAL_CDKEYS )
  1158. {
  1159. RejectConnection( adr, clientChallenge, "#GameUI_ServerCDKeyInUse" );
  1160. return false;
  1161. }
  1162. break;
  1163. }
  1164. return true;
  1165. }
  1166. /*
  1167. =============================================================================
  1168. The PVS must include a small area around the client to allow head bobbing
  1169. or other small motion on the client side. Otherwise, a bob might cause an
  1170. entity that should be visible to not show up, especially when the bob
  1171. crosses a waterline.
  1172. =============================================================================
  1173. */
  1174. static int s_FatBytes;
  1175. static byte* s_pFatPVS = 0;
  1176. CUtlVector<int> g_AreasNetworked;
  1177. static void SV_AddToFatPVS( const Vector& org )
  1178. {
  1179. int i;
  1180. byte pvs[MAX_MAP_LEAFS/8];
  1181. CM_Vis( pvs, sizeof(pvs), CM_LeafCluster( CM_PointLeafnum( org ) ), DVIS_PVS );
  1182. for (i=0 ; i<s_FatBytes ; i++)
  1183. {
  1184. s_pFatPVS[i] |= pvs[i];
  1185. }
  1186. }
  1187. //-----------------------------------------------------------------------------
  1188. // Purpose: Zeroes out pvs, this way we can or together multiple pvs's for a player
  1189. //-----------------------------------------------------------------------------
  1190. void SV_ResetPVS( byte* pvs, int pvssize )
  1191. {
  1192. s_pFatPVS = pvs;
  1193. s_FatBytes = Bits2Bytes(CM_NumClusters());
  1194. if ( s_FatBytes > pvssize )
  1195. {
  1196. Sys_Error( "SV_ResetPVS: Size %i too big for buffer %i\n", s_FatBytes, pvssize );
  1197. }
  1198. Q_memset (s_pFatPVS, 0, s_FatBytes);
  1199. g_AreasNetworked.RemoveAll();
  1200. }
  1201. /*
  1202. =============
  1203. Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
  1204. given point.
  1205. =============
  1206. */
  1207. void SV_AddOriginToPVS( const Vector& origin )
  1208. {
  1209. SV_AddToFatPVS( origin );
  1210. int area = CM_LeafArea( CM_PointLeafnum( origin ) );
  1211. int i;
  1212. for( i = 0; i < g_AreasNetworked.Count(); i++ )
  1213. {
  1214. if( g_AreasNetworked[i] == area )
  1215. {
  1216. return;
  1217. }
  1218. }
  1219. g_AreasNetworked.AddToTail( area );
  1220. }
  1221. void CGameServer::BroadcastSound( SoundInfo_t &sound, IRecipientFilter &filter )
  1222. {
  1223. int num = filter.GetRecipientCount();
  1224. // don't add sounds while paused, unless we're in developer mode
  1225. if ( IsPaused() && !developer.GetInt() )
  1226. return;
  1227. for ( int i = 0; i < num; i++ )
  1228. {
  1229. int index = filter.GetRecipientIndex( i );
  1230. if ( index < 1 || index > GetClientCount() )
  1231. {
  1232. Msg( "CGameServer::BroadcastSound: Recipient Filter for sound (reliable: %s, init: %s) with bogus client index (%i) in list of %i clients\n",
  1233. filter.IsReliable() ? "yes" : "no",
  1234. filter.IsInitMessage() ? "yes" : "no",
  1235. index, num );
  1236. continue;
  1237. }
  1238. CGameClient *pClient = Client( index - 1 );
  1239. // client must be fully connect to hear sounds
  1240. if ( !pClient->IsActive() )
  1241. {
  1242. continue;
  1243. }
  1244. pClient->SendSound( sound, filter.IsReliable() );
  1245. }
  1246. }
  1247. bool CGameServer::IsInPureServerMode() const
  1248. {
  1249. return (m_pPureServerWhitelist != NULL);
  1250. }
  1251. CPureServerWhitelist * CGameServer::GetPureServerWhitelist() const
  1252. {
  1253. return m_pPureServerWhitelist;
  1254. }
  1255. //void OnHibernateWhenEmptyChanged( IConVar *var, const char *pOldValue, float flOldValue )
  1256. //{
  1257. // // We only need to do something special if we were preventing hibernation
  1258. // // with sv_hibernate_when_empty but we would otherwise have been hibernating.
  1259. // // In that case, punt all connected clients.
  1260. // sv.UpdateHibernationState( );
  1261. //}
  1262. static bool s_bExitWhenEmpty = false;
  1263. static ConVar sv_memlimit( "sv_memlimit", "0", 0,
  1264. "If set, whenever a game ends, if the total memory used by the server is "
  1265. "greater than this # of megabytes, the server will exit." );
  1266. static ConVar sv_minuptimelimit( "sv_minuptimelimit", "0", 0,
  1267. "If set, whenever a game ends, if the server uptime is less than "
  1268. "this number of hours, the server will continue running regardless of sv_memlimit." );
  1269. static ConVar sv_maxuptimelimit( "sv_maxuptimelimit", "0", 0,
  1270. "If set, whenever a game ends, if the server uptime exceeds "
  1271. "this number of hours, the server will exit." );
  1272. #if 0
  1273. static void sv_WasteMemory( void )
  1274. {
  1275. uint8 *pWastedRam = new uint8[ 100 * 1024 * 1024 ];
  1276. memset( pWastedRam, 0xff, 100 * 1024 * 1024 ); // make sure it gets committed
  1277. Msg( "waste 100mb. using %dMB with an sv_memory_limit of %dMB\n", ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1278. }
  1279. static ConCommand sv_wastememory( "sv_wastememory", sv_WasteMemory, "Causes the server to allocate 100MB of ram and never free it", FCVAR_CHEAT );
  1280. #endif
  1281. static void sv_ShutDownCancel( void )
  1282. {
  1283. if ( s_bExitWhenEmpty || ( s_timeForceShutdown > 0.0 ) )
  1284. {
  1285. ConMsg( "sv_shutdown canceled.\n" );
  1286. }
  1287. else
  1288. {
  1289. ConMsg( "sv_shutdown not pending.\n" );
  1290. }
  1291. s_bExitWhenEmpty = false;
  1292. s_timeForceShutdown = 0.0;
  1293. }
  1294. static ConCommand sv_shutdown_cancel( "sv_shutdown_cancel", sv_ShutDownCancel, "Cancels pending sv_shutdown command" );
  1295. static void sv_ShutDown( void )
  1296. {
  1297. if ( !sv.IsDedicated() )
  1298. {
  1299. Warning( "sv_shutdown only works on dedicated servers.\n" );
  1300. return;
  1301. }
  1302. s_bExitWhenEmpty = true;
  1303. Warning( "sv_shutdown command received.\n" );
  1304. double timeCurrent = Plat_FloatTime();
  1305. if ( sv.IsHibernating() || !sv.IsActive() )
  1306. {
  1307. Warning( "Server is inactive or hibernating. Shutting down right now\n" );
  1308. s_timeForceShutdown = timeCurrent + 5.0; // don't forget!
  1309. HostState_Shutdown();
  1310. }
  1311. else
  1312. {
  1313. // Check if we should update shutdown timeout
  1314. if ( s_timeForceShutdown == 0.0 && sv_shutdown_timeout_minutes.GetInt() > 0 )
  1315. s_timeForceShutdown = timeCurrent + sv_shutdown_timeout_minutes.GetInt() * 60.0;
  1316. // Print appropriate message
  1317. if ( s_timeForceShutdown > 0.0 )
  1318. {
  1319. Warning( "Server will shut down in %d seconds, or when it becomes empty.\n", (int)(s_timeForceShutdown - timeCurrent) );
  1320. }
  1321. else
  1322. {
  1323. Warning( "Server will shut down when it becomes empty.\n" );
  1324. }
  1325. }
  1326. }
  1327. static ConCommand sv_shutdown( "sv_shutdown", sv_ShutDown, "Sets the server to shutdown next time it's empty" );
  1328. bool CGameServer::IsHibernating() const
  1329. {
  1330. return m_bHibernating;
  1331. }
  1332. void CGameServer::SetHibernating( bool bHibernating )
  1333. {
  1334. static double s_flPlatFloatTimeBeginUptime = Plat_FloatTime();
  1335. if ( m_bHibernating != bHibernating )
  1336. {
  1337. m_bHibernating = bHibernating;
  1338. Msg( m_bHibernating ? "Server is hibernating\n" : "Server waking up from hibernation\n" );
  1339. if ( m_bHibernating )
  1340. {
  1341. // see if we have any other connected bot clients
  1342. for ( int iClient = 0; iClient < m_Clients.Count(); iClient++ )
  1343. {
  1344. CBaseClient *pClient = m_Clients[iClient];
  1345. if ( pClient->IsFakeClient() && pClient->IsConnected() && !pClient->IsSplitScreenUser() && !pClient->IsReplay() && !pClient->IsHLTV() )
  1346. {
  1347. pClient->Disconnect( "Punting bot, server is hibernating" );
  1348. }
  1349. }
  1350. // A solo player using the game menu to return to lobby can leave the server paused
  1351. SetPaused( false );
  1352. // if we are hibernating, and we want to quit, quit
  1353. bool bExit = false;
  1354. if ( s_bExitWhenEmpty )
  1355. {
  1356. bExit = true;
  1357. Warning( "Server shutting down because sv_shutdown was requested and a server is empty.\n" );
  1358. }
  1359. else
  1360. {
  1361. if ( sv_memlimit.GetInt() )
  1362. {
  1363. if ( ApproximateProcessMemoryUsage() > 1024 * 1024 * sv_memlimit.GetInt() )
  1364. {
  1365. if ( ( sv_minuptimelimit.GetFloat() > 0 ) &&
  1366. ( ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 < sv_minuptimelimit.GetFloat() ) )
  1367. {
  1368. 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",
  1369. ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt(),
  1370. sv_minuptimelimit.GetFloat(), ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 );
  1371. }
  1372. else
  1373. {
  1374. Warning( "Server shutting down because of using %dMB with an sv_memory_limit of %dMB\n", ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1375. bExit = true;
  1376. }
  1377. }
  1378. }
  1379. if ( ( sv_maxuptimelimit.GetFloat() > 0 ) &&
  1380. ( ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0 > sv_maxuptimelimit.GetFloat() ) )
  1381. {
  1382. 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",
  1383. sv_maxuptimelimit.GetFloat(), ( Plat_FloatTime() - s_flPlatFloatTimeBeginUptime ) / 3600.0,
  1384. ApproximateProcessMemoryUsage() / ( 1024 * 1024 ), sv_memlimit.GetInt() );
  1385. bExit = true;
  1386. }
  1387. }
  1388. //#ifdef _LINUX
  1389. // // if we are a child process running forked, we want to exit now. We want to "really" exit. no destructors, no nothing
  1390. // if ( IsChildProcess() ) // are we a subprocess?
  1391. // {
  1392. // syscall( SYS_exit_group, 0 ); // we are not going to perform a normal c++ exit. We _dont_ want to run destructors, etc.
  1393. // }
  1394. //#endif
  1395. if ( bExit )
  1396. {
  1397. HostState_Shutdown();
  1398. }
  1399. // ResetGameConVarsToDefaults();
  1400. }
  1401. if ( g_iServerGameDLLVersion >= 8 )
  1402. {
  1403. serverGameDLL->SetServerHibernation( m_bHibernating );
  1404. }
  1405. // Heartbeat ASAP
  1406. Steam3Server().SendUpdatedServerDetails();
  1407. if ( Steam3Server().SteamGameServer() )
  1408. {
  1409. Steam3Server().SteamGameServer()->ForceHeartbeat();
  1410. }
  1411. }
  1412. }
  1413. void CGameServer::UpdateHibernationState()
  1414. {
  1415. if ( !IsDedicated() || sv.m_State == ss_dead )
  1416. return;
  1417. // is this the last client disconnecting?
  1418. bool bHaveAnyClients = false;
  1419. // see if we have any other connected clients
  1420. for ( int iClient = 0; iClient < m_Clients.Count(); iClient++ )
  1421. {
  1422. CBaseClient *pClient = m_Clients[iClient];
  1423. // don't consider the client being removed, it still shows as connected but won't be in a moment
  1424. if ( pClient->IsConnected() && ( pClient->IsSplitScreenUser() || !pClient->IsFakeClient() ) )
  1425. {
  1426. bHaveAnyClients = true;
  1427. break;
  1428. }
  1429. }
  1430. bool hibernateFromGCServer = ( g_iServerGameDLLVersion < 8 ) || !serverGameDLL->GetServerGCLobby() || serverGameDLL->GetServerGCLobby()->ShouldHibernate();
  1431. // If a restart was requested and we're supposed to reboot after XX amount of time, reboot the server.
  1432. if ( !bHaveAnyClients && ( sv_maxuptimelimit.GetFloat() > 0.0f ) &&
  1433. Steam3Server().SteamGameServer() && Steam3Server().SteamGameServer()->WasRestartRequested() )
  1434. {
  1435. hibernateFromGCServer = true;
  1436. s_bExitWhenEmpty = true;
  1437. }
  1438. //SetHibernating( sv_hibernate_when_empty.GetBool() && hibernateFromGCServer && !bHaveAnyClients );
  1439. SetHibernating( hibernateFromGCServer && !bHaveAnyClients );
  1440. }
  1441. void CGameServer::FinishRestore()
  1442. {
  1443. #ifndef SWDS
  1444. CSaveRestoreData currentLevelData;
  1445. char name[MAX_OSPATH];
  1446. if ( !m_bLoadgame )
  1447. return;
  1448. g_ServerGlobalVariables.pSaveData = &currentLevelData;
  1449. // Build the adjacent map list
  1450. serverGameDLL->BuildAdjacentMapList();
  1451. if ( !saverestore->IsXSave() )
  1452. {
  1453. Q_snprintf( name, sizeof( name ), "%s%s.HL2", saverestore->GetSaveDir(), m_szMapname );
  1454. }
  1455. else
  1456. {
  1457. Q_snprintf( name, sizeof( name ), "%s:\\%s.HL2", GetCurrentMod(), m_szMapname );
  1458. }
  1459. Q_FixSlashes( name );
  1460. saverestore->RestoreClientState( name, false );
  1461. if ( g_ServerGlobalVariables.eLoadType == MapLoad_Transition )
  1462. {
  1463. for ( int i = 0; i < currentLevelData.levelInfo.connectionCount; i++ )
  1464. {
  1465. saverestore->RestoreAdjacenClientState( currentLevelData.levelInfo.levelList[i].mapName );
  1466. }
  1467. }
  1468. saverestore->OnFinishedClientRestore();
  1469. g_ServerGlobalVariables.pSaveData = NULL;
  1470. // Reset
  1471. m_bLoadgame = false;
  1472. saverestore->SetIsXSave( IsX360() );
  1473. #endif
  1474. }
  1475. void CGameServer::CopyTempEntities( CFrameSnapshot* pSnapshot )
  1476. {
  1477. Assert( pSnapshot->m_pTempEntities == NULL );
  1478. if ( m_TempEntities.Count() > 0 )
  1479. {
  1480. // copy temp entities if any
  1481. pSnapshot->m_nTempEntities = m_TempEntities.Count();
  1482. pSnapshot->m_pTempEntities = new CEventInfo*[pSnapshot->m_nTempEntities];
  1483. Q_memcpy( pSnapshot->m_pTempEntities, m_TempEntities.Base(), m_TempEntities.Count() * sizeof( CEventInfo * ) );
  1484. // clear server list
  1485. m_TempEntities.RemoveAll();
  1486. }
  1487. }
  1488. // If enabled, random crashes start to appear in WriteTempEntities, etc. It looks like
  1489. // one thread can be in WriteDeltaEntities while another is in WriteTempEntities, and both are
  1490. // partying on g_FrameSnapshotManager.m_FrameSnapshots. Bruce sent e-mail from a customer
  1491. // that stated these crashes don't occur when parallel_sendsnapshot is disabled. Zoid said:
  1492. //
  1493. // Easiest is just turn off parallel snapshots, it's not much of a win on servers where we
  1494. // are running many instances anyway. It's off in Dota and CSGO dedicated servers.
  1495. //
  1496. // Bruce also had a patch to disable this in //ValveGames/staging/game/tf/cfg/unencrypted/print_instance_config.py
  1497. static ConVar sv_parallel_sendsnapshot( "sv_parallel_sendsnapshot", "0" );
  1498. static void SV_ParallelSendSnapshot( CGameClient *& pClient )
  1499. {
  1500. // HLTV and replay clients must be handled on the main thread
  1501. // because they access and modify global state. Skip them.
  1502. if ( pClient->IsHLTV() )
  1503. return;
  1504. #if defined( REPLAY_ENABLED )
  1505. if ( pClient->IsReplay() )
  1506. return;
  1507. #endif
  1508. CClientFrame *pFrame = pClient->GetSendFrame();
  1509. if ( pFrame )
  1510. {
  1511. pClient->SendSnapshot( pFrame );
  1512. pClient->UpdateSendState();
  1513. }
  1514. // Replace this parallel processing array entry with NULL so
  1515. // that the calling code knows that this entry was handled.
  1516. pClient = NULL;
  1517. }
  1518. void CGameServer::SendClientMessages ( bool bSendSnapshots )
  1519. {
  1520. VPROF_BUDGET( "SendClientMessages", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1521. // build individual updates
  1522. int receivingClientCount = 0;
  1523. CGameClient* pReceivingClients[ABSOLUTE_PLAYER_LIMIT];
  1524. for (int i=0; i< GetClientCount(); i++ )
  1525. {
  1526. CGameClient* client = Client(i);
  1527. // Update Host client send state...
  1528. if ( !client->ShouldSendMessages() )
  1529. continue;
  1530. // Append the unreliable data (player updates and packet entities)
  1531. if ( bSendSnapshots && client->IsActive() )
  1532. {
  1533. // Add this client to the list of clients we're gonna send to.
  1534. pReceivingClients[receivingClientCount] = client;
  1535. ++receivingClientCount;
  1536. }
  1537. else
  1538. {
  1539. // Connected, but inactive, just send reliable, sequenced info.
  1540. if ( client->IsFakeClient() )
  1541. continue;
  1542. // if client never send a netchannl packet yet, send S2C_CONNECTION
  1543. // because it could get lost in multiplayer
  1544. if ( NET_IsMultiplayer() && client->m_NetChannel->GetSequenceNr(FLOW_INCOMING) == 0 )
  1545. {
  1546. NET_OutOfBandPrintf ( m_Socket, client->m_NetChannel->GetRemoteAddress(), "%c00000000000000", S2C_CONNECTION );
  1547. }
  1548. #ifdef SHARED_NET_STRING_TABLES
  1549. sv.m_StringTables->TriggerCallbacks( client->m_nDeltaTick );
  1550. #endif
  1551. client->m_NetChannel->Transmit();
  1552. client->UpdateSendState();
  1553. }
  1554. }
  1555. if ( receivingClientCount )
  1556. {
  1557. // if any client wants an update, take new snapshot now
  1558. CFrameSnapshot* pSnapshot = framesnapshotmanager->TakeTickSnapshot( m_nTickCount );
  1559. // copy temp ents references to pSnapshot
  1560. CopyTempEntities( pSnapshot );
  1561. // Compute the client packs
  1562. SV_ComputeClientPacks( receivingClientCount, pReceivingClients, pSnapshot );
  1563. if ( receivingClientCount > 1 && sv_parallel_sendsnapshot.GetBool() )
  1564. {
  1565. // SV_ParallelSendSnapshot will not process HLTV or Replay clients as they
  1566. // must be run on the main thread due to un-threadsafe global state access.
  1567. // It will replace anything that it does process with a NULL pointer.
  1568. ParallelProcess( "SV_ParallelSendSnapshot", pReceivingClients, receivingClientCount, &SV_ParallelSendSnapshot );
  1569. }
  1570. for (int i = 0; i < receivingClientCount; ++i)
  1571. {
  1572. CGameClient *pClient = pReceivingClients[i];
  1573. if ( !pClient )
  1574. continue;
  1575. CClientFrame *pFrame = pClient->GetSendFrame();
  1576. if ( !pFrame )
  1577. continue;
  1578. pClient->SendSnapshot( pFrame );
  1579. pClient->UpdateSendState();
  1580. }
  1581. pSnapshot->ReleaseReference();
  1582. }
  1583. }
  1584. void CGameServer::SetMaxClients( int number )
  1585. {
  1586. m_nMaxclients = clamp( number, 1, m_nMaxClientsLimit );
  1587. if ( tv_enable.GetBool() == false )
  1588. {
  1589. ConMsg( "maxplayers set to %i\n", m_nMaxclients );
  1590. }
  1591. else
  1592. {
  1593. ConMsg( "maxplayers set to %i (extra slot was added for SourceTV)\n", m_nMaxclients );
  1594. }
  1595. deathmatch.SetValue( m_nMaxclients > 1 );
  1596. }
  1597. //-----------------------------------------------------------------------------
  1598. // A potential optimization of the client data sending; the optimization
  1599. // is based around the fact that we think that we're spending all our time in
  1600. // cache misses since we are accessing so much memory
  1601. //-----------------------------------------------------------------------------
  1602. /*
  1603. ==============================================================================
  1604. SERVER SPAWNING
  1605. ==============================================================================
  1606. */
  1607. void SV_WriteVoiceCodec(bf_write &pBuf)
  1608. {
  1609. // Only send in multiplayer. Otherwise, we don't want voice.
  1610. const char *pCodec = sv.IsMultiplayer() ? sv_voicecodec.GetString() : NULL;
  1611. int nSampleRate = pCodec ? Voice_GetDefaultSampleRate( pCodec ) : 0;
  1612. SVC_VoiceInit voiceinit( pCodec, nSampleRate );
  1613. voiceinit.WriteToBuffer( pBuf );
  1614. }
  1615. // Gets voice data from a client and forwards it to anyone who can hear this client.
  1616. ConVar voice_debugfeedbackfrom( "voice_debugfeedbackfrom", "0" );
  1617. void SV_BroadcastVoiceData(IClient * pClient, int nBytes, char * data, int64 xuid )
  1618. {
  1619. // Disable voice?
  1620. if( !sv_voiceenable.GetInt() )
  1621. return;
  1622. // Build voice message once
  1623. SVC_VoiceData voiceData;
  1624. voiceData.m_nFromClient = pClient->GetPlayerSlot();
  1625. voiceData.m_nLength = nBytes * 8; // length in bits
  1626. voiceData.m_DataOut = data;
  1627. voiceData.m_xuid = xuid;
  1628. if ( voice_debugfeedbackfrom.GetBool() )
  1629. {
  1630. Msg( "Sending voice from: %s - playerslot: %d\n", pClient->GetClientName(), pClient->GetPlayerSlot() + 1 );
  1631. }
  1632. for(int i=0; i < sv.GetClientCount(); i++)
  1633. {
  1634. IClient *pDestClient = sv.GetClient(i);
  1635. bool bSelf = (pDestClient == pClient);
  1636. // Only send voice to active clients
  1637. if( !pDestClient->IsActive() )
  1638. continue;
  1639. // Does the game code want cl sending to this client?
  1640. bool bHearsPlayer = pDestClient->IsHearingClient( voiceData.m_nFromClient );
  1641. voiceData.m_bProximity = pDestClient->IsProximityHearingClient( voiceData.m_nFromClient );
  1642. if ( IsX360() && bSelf == true )
  1643. continue;
  1644. if ( !bHearsPlayer && !bSelf )
  1645. continue;
  1646. voiceData.m_nLength = nBytes * 8;
  1647. // Is loopback enabled?
  1648. if( !bHearsPlayer )
  1649. {
  1650. // Still send something, just zero length (this is so the client
  1651. // can display something that shows knows the server knows it's talking).
  1652. voiceData.m_nLength = 0;
  1653. }
  1654. pDestClient->SendNetMsg( voiceData );
  1655. }
  1656. }
  1657. // UNDONE: "player.mdl" ??? This should be set by name in the DLL
  1658. /*
  1659. ================
  1660. SV_CreateBaseline
  1661. ================
  1662. */
  1663. void SV_CreateBaseline (void)
  1664. {
  1665. SV_WriteVoiceCodec( sv.m_Signon );
  1666. ServerClass *pClasses = serverGameDLL->GetAllServerClasses();
  1667. // Send SendTable info.
  1668. if ( sv_sendtables.GetInt() )
  1669. {
  1670. #ifdef _XBOX
  1671. Error( "sv_sendtables not allowed on XBOX." );
  1672. #endif
  1673. sv.m_FullSendTablesBuffer.EnsureCapacity( NET_MAX_PAYLOAD );
  1674. sv.m_FullSendTables.StartWriting( sv.m_FullSendTablesBuffer.Base(), sv.m_FullSendTablesBuffer.Count() );
  1675. SV_WriteSendTables( pClasses, sv.m_FullSendTables );
  1676. if ( sv.m_FullSendTables.IsOverflowed() )
  1677. {
  1678. Host_Error("SV_CreateBaseline: WriteSendTables overflow.\n" );
  1679. return;
  1680. }
  1681. // Send class descriptions.
  1682. SV_WriteClassInfos(pClasses, sv.m_FullSendTables);
  1683. if ( sv.m_FullSendTables.IsOverflowed() )
  1684. {
  1685. Host_Error("SV_CreateBaseline: WriteClassInfos overflow.\n" );
  1686. return;
  1687. }
  1688. }
  1689. // If we're using the local network backdoor, we'll never use the instance baselines.
  1690. if ( !g_pLocalNetworkBackdoor )
  1691. {
  1692. int count = 0;
  1693. int bytes = 0;
  1694. for ( int entnum = 0; entnum < sv.num_edicts ; entnum++)
  1695. {
  1696. // get the current server version
  1697. edict_t *edict = sv.edicts + entnum;
  1698. if ( edict->IsFree() || !edict->GetUnknown() )
  1699. continue;
  1700. ServerClass *pClass = edict->GetNetworkable() ? edict->GetNetworkable()->GetServerClass() : 0;
  1701. if ( !pClass )
  1702. {
  1703. Assert( pClass );
  1704. continue; // no Class ?
  1705. }
  1706. if ( pClass->m_InstanceBaselineIndex != INVALID_STRING_INDEX )
  1707. continue; // we already have a baseline for this class
  1708. SendTable *pSendTable = pClass->m_pTable;
  1709. //
  1710. // create entity baseline
  1711. //
  1712. ALIGN4 char packedData[MAX_PACKEDENTITY_DATA] ALIGN4_POST;
  1713. bf_write writeBuf( "SV_CreateBaseline->writeBuf", packedData, sizeof( packedData ) );
  1714. // create basline from zero values
  1715. if ( !SendTable_Encode(
  1716. pSendTable,
  1717. edict->GetUnknown(),
  1718. &writeBuf,
  1719. entnum,
  1720. NULL,
  1721. false
  1722. ) )
  1723. {
  1724. Host_Error("SV_CreateBaseline: SendTable_Encode returned false (ent %d).\n", entnum);
  1725. }
  1726. // copy baseline into baseline stringtable
  1727. SV_EnsureInstanceBaseline( pClass, entnum, packedData, writeBuf.GetNumBytesWritten() );
  1728. bytes += writeBuf.GetNumBytesWritten();
  1729. count ++;
  1730. }
  1731. DevMsg("Created class baseline: %i classes, %i bytes.\n", count,bytes);
  1732. }
  1733. g_GameEventManager.ReloadEventDefinitions();
  1734. SVC_GameEventList gameevents;
  1735. char data[NET_MAX_PAYLOAD];
  1736. gameevents.m_DataOut.StartWriting( data, sizeof(data) );
  1737. g_GameEventManager.WriteEventList( &gameevents );
  1738. gameevents.WriteToBuffer( sv.m_Signon );
  1739. }
  1740. //-----------------------------------------------------------------------------
  1741. // Purpose: Ensure steam context is initialized for multiplayer gameservers. Idempotent.
  1742. //-----------------------------------------------------------------------------
  1743. void SV_InitGameServerSteam()
  1744. {
  1745. if ( sv.IsMultiplayer() )
  1746. {
  1747. Steam3Server().Activate( CSteam3Server::eServerTypeNormal );
  1748. sv.SetQueryPortFromSteamServer();
  1749. if ( serverGameDLL && g_iServerGameDLLVersion >= 6 )
  1750. {
  1751. serverGameDLL->GameServerSteamAPIActivated();
  1752. }
  1753. }
  1754. }
  1755. //-----------------------------------------------------------------------------
  1756. // Purpose:
  1757. // Input : runPhysics -
  1758. //-----------------------------------------------------------------------------
  1759. bool SV_ActivateServer()
  1760. {
  1761. COM_TimestampedLog( "SV_ActivateServer" );
  1762. #ifndef SWDS
  1763. EngineVGui()->UpdateProgressBar(PROGRESS_ACTIVATESERVER);
  1764. #endif
  1765. COM_TimestampedLog( "serverGameDLL->ServerActivate" );
  1766. host_state.interval_per_tick = serverGameDLL->GetTickInterval();
  1767. if ( host_state.interval_per_tick < MINIMUM_TICK_INTERVAL ||
  1768. host_state.interval_per_tick > MAXIMUM_TICK_INTERVAL )
  1769. {
  1770. Sys_Error( "GetTickInterval returned bogus tick interval (%f)[%f to %f is valid range]", host_state.interval_per_tick,
  1771. MINIMUM_TICK_INTERVAL, MAXIMUM_TICK_INTERVAL );
  1772. }
  1773. Msg( "SV_ActivateServer: setting tickrate to %.1f\n", 1.0f / host_state.interval_per_tick );
  1774. bool bPrevState = networkStringTableContainerServer->Lock( false );
  1775. // Activate the DLL server code
  1776. g_pServerPluginHandler->ServerActivate( sv.edicts, sv.num_edicts, sv.GetMaxClients() );
  1777. // all setup is completed, any further precache statements are errors
  1778. sv.m_State = ss_active;
  1779. COM_TimestampedLog( "SV_CreateBaseline" );
  1780. // create a baseline for more efficient communications
  1781. SV_CreateBaseline();
  1782. sv.allowsignonwrites = false;
  1783. // set skybox name
  1784. ConVar const *skyname = g_pCVar->FindVar( "sv_skyname" );
  1785. if ( skyname )
  1786. {
  1787. Q_strncpy( sv.m_szSkyname, skyname->GetString(), sizeof( sv.m_szSkyname ) );
  1788. }
  1789. else
  1790. {
  1791. Q_strncpy( sv.m_szSkyname, "unknown", sizeof( sv.m_szSkyname ) );
  1792. }
  1793. COM_TimestampedLog( "Send Reconnects" );
  1794. // Tell connected clients to reconnect
  1795. sv.ReconnectClients();
  1796. // Tell what kind of server has been started.
  1797. if ( sv.IsMultiplayer() )
  1798. {
  1799. ConDMsg ("%i player server started\n", sv.GetMaxClients() );
  1800. }
  1801. else
  1802. {
  1803. ConDMsg ("Game started\n");
  1804. }
  1805. // Replay setup
  1806. #if defined( REPLAY_ENABLED )
  1807. if ( g_pReplay && g_pReplay->IsReplayEnabled() )
  1808. {
  1809. if ( !replay )
  1810. {
  1811. replay = new CReplayServer;
  1812. replay->Init( NET_IsDedicated() );
  1813. }
  1814. if ( replay->IsActive() )
  1815. {
  1816. // replay master already running, just activate client
  1817. replay->m_MasterClient->ActivatePlayer();
  1818. replay->StartMaster( replay->m_MasterClient );
  1819. }
  1820. else
  1821. {
  1822. // create new replay client
  1823. ConVarRef replay_name( "replay_name" );
  1824. CGameClient *pClient = (CGameClient*)sv.CreateFakeClient( replay_name.GetString() );
  1825. replay->StartMaster( pClient );
  1826. }
  1827. }
  1828. else
  1829. {
  1830. // make sure replay is disabled
  1831. if ( replay )
  1832. replay->Shutdown();
  1833. }
  1834. #endif // #if defined( REPLAY_ENABLED )
  1835. // HLTV setup
  1836. if ( tv_enable.GetBool() )
  1837. {
  1838. if ( CommandLine()->FindParm("-nohltv") )
  1839. {
  1840. // let user know that SourceTV will not work
  1841. ConMsg ("SourceTV is disabled on this server.\n");
  1842. }
  1843. else
  1844. {
  1845. // create SourceTV object if not already there
  1846. if ( !hltv )
  1847. {
  1848. hltv = new CHLTVServer;
  1849. hltv->Init( NET_IsDedicated() );
  1850. }
  1851. if ( hltv->IsActive() && hltv->IsMasterProxy() )
  1852. {
  1853. // HLTV master already running, just activate client
  1854. hltv->m_MasterClient->ActivatePlayer();
  1855. hltv->StartMaster( hltv->m_MasterClient );
  1856. }
  1857. else
  1858. {
  1859. // create new HLTV client
  1860. CGameClient *pClient = (CGameClient*)sv.CreateFakeClient( tv_name.GetString() );
  1861. hltv->StartMaster( pClient );
  1862. }
  1863. }
  1864. }
  1865. else
  1866. {
  1867. // make sure HLTV is disabled
  1868. if ( hltv )
  1869. hltv->Shutdown();
  1870. }
  1871. if (sv.IsDedicated())
  1872. {
  1873. // purge unused models and their data hierarchy (materials, shaders, etc)
  1874. modelloader->PurgeUnusedModels();
  1875. }
  1876. SV_InitGameServerSteam();
  1877. networkStringTableContainerServer->Lock( bPrevState );
  1878. // Heartbeat the master server in case we turned SrcTV on or off.
  1879. Steam3Server().SendUpdatedServerDetails();
  1880. if ( Steam3Server().SteamGameServer() )
  1881. {
  1882. Steam3Server().SteamGameServer()->ForceHeartbeat();
  1883. }
  1884. COM_TimestampedLog( "SV_ActivateServer(finished)" );
  1885. return true;
  1886. }
  1887. #include "tier0/memdbgoff.h"
  1888. static void SV_AllocateEdicts()
  1889. {
  1890. sv.edicts = (edict_t *)Hunk_AllocName( sv.max_edicts*sizeof(edict_t), "edicts" );
  1891. COMPILE_TIME_ASSERT( MAX_EDICT_BITS+1 <= 8*sizeof(sv.edicts[0].m_EdictIndex) );
  1892. // Invoke the constructor so the vtable is set correctly..
  1893. for (int i = 0; i < sv.max_edicts; ++i)
  1894. {
  1895. new( &sv.edicts[i] ) edict_t;
  1896. sv.edicts[i].m_EdictIndex = i;
  1897. sv.edicts[i].freetime = 0;
  1898. }
  1899. ED_ClearFreeEdictList();
  1900. sv.edictchangeinfo = (IChangeInfoAccessor *)Hunk_AllocName( sv.max_edicts * sizeof( IChangeInfoAccessor ), "edictchangeinfo" );
  1901. }
  1902. #include "tier0/memdbgon.h"
  1903. void CGameServer::ReloadWhitelist( const char *pMapName )
  1904. {
  1905. // Always return - until we get the whitelist stuff resolved for TF2.
  1906. if ( m_pPureServerWhitelist )
  1907. {
  1908. m_pPureServerWhitelist->Release();
  1909. m_pPureServerWhitelist = NULL;
  1910. }
  1911. g_sv_pure_waiting_on_reload = false;
  1912. // Don't do sv_pure stuff in SP games.
  1913. if ( GetMaxClients() <= 1 )
  1914. return;
  1915. // Don't use the whitelist if sv_pure is not set.
  1916. if ( GetSvPureMode() < 0 )
  1917. return;
  1918. // There's a magic number we use in the steam.inf in P4 that we don't update.
  1919. // We can use this to detect if they are running out of P4, and if so, don't use the whitelist
  1920. const char *pszVersionInP4 = "2000";
  1921. if ( !Q_strcmp( GetSteamInfIDVersionInfo().szVersionString, pszVersionInP4 ) )
  1922. return;
  1923. m_pPureServerWhitelist = CPureServerWhitelist::Create( g_pFileSystem );
  1924. // Load it
  1925. m_pPureServerWhitelist->Load( GetSvPureMode() );
  1926. // Load user whitelists, if allowed
  1927. if ( GetSvPureMode() == 1 )
  1928. {
  1929. // Load the per-map whitelist.
  1930. const char *pMapWhitelistSuffix = "_whitelist.txt";
  1931. char testFilename[MAX_PATH] = "maps";
  1932. V_AppendSlash( testFilename, sizeof( testFilename ) );
  1933. V_strncat( testFilename, pMapName, sizeof( testFilename ) );
  1934. V_strncat( testFilename, pMapWhitelistSuffix, sizeof( testFilename ) );
  1935. KeyValues *kv = new KeyValues( "" );
  1936. if ( kv->LoadFromFile( g_pFileSystem, testFilename ) )
  1937. m_pPureServerWhitelist->LoadCommandsFromKeyValues( kv );
  1938. kv->deleteThis();
  1939. }
  1940. }
  1941. /*
  1942. ================
  1943. SV_SpawnServer
  1944. This is called at the start of each level
  1945. ================
  1946. */
  1947. bool CGameServer::SpawnServer( const char *szMapName, const char *szMapFile, const char *startspot )
  1948. {
  1949. int i;
  1950. Assert( serverGameClients );
  1951. if ( CommandLine()->FindParm( "-NoLoadPluginsForClient" ) != 0 )
  1952. {
  1953. if ( !m_bLoadedPlugins )
  1954. {
  1955. // Only load plugins once.
  1956. m_bLoadedPlugins = true;
  1957. g_pServerPluginHandler->LoadPlugins(); // load 3rd party plugins
  1958. }
  1959. }
  1960. // Reset the last used count on all models before beginning the new load -- The nServerCount value on models could
  1961. // be from a client load connecting to a different server, and we know we're at the beginning of a new load now.
  1962. modelloader->ResetModelServerCounts();
  1963. ReloadWhitelist( szMapName );
  1964. COM_TimestampedLog( "SV_SpawnServer(%s)", szMapName );
  1965. #ifndef SWDS
  1966. EngineVGui()->UpdateProgressBar(PROGRESS_SPAWNSERVER);
  1967. #endif
  1968. COM_SetupLogDir( szMapName );
  1969. g_Log.Open();
  1970. g_Log.Printf( "Loading map \"%s\"\n", szMapName );
  1971. g_Log.PrintServerVars();
  1972. #ifndef SWDS
  1973. SCR_CenterStringOff();
  1974. #endif
  1975. if ( startspot )
  1976. {
  1977. ConDMsg("Spawn Server: %s: [%s]\n", szMapName, startspot );
  1978. }
  1979. else
  1980. {
  1981. ConDMsg("Spawn Server: %s\n", szMapName );
  1982. }
  1983. // Any partially connected client will be restarted if the spawncount is not matched.
  1984. gHostSpawnCount = ++m_nSpawnCount;
  1985. //
  1986. // make cvars consistant
  1987. //
  1988. deathmatch.SetValue( IsMultiplayer() ? 1 : 0 );
  1989. if ( coop.GetInt() )
  1990. {
  1991. deathmatch.SetValue( 0 );
  1992. }
  1993. current_skill = (int)(skill.GetFloat() + 0.5);
  1994. current_skill = max( current_skill, 0 );
  1995. current_skill = min( current_skill, 3 );
  1996. skill.SetValue( (float)current_skill );
  1997. COM_TimestampedLog( "StaticPropMgr()->LevelShutdown()" );
  1998. #if !defined( SWDS )
  1999. g_pShadowMgr->LevelShutdown();
  2000. #endif // SWDS
  2001. StaticPropMgr()->LevelShutdown();
  2002. // if we have an hltv relay proxy running, stop it now
  2003. if ( hltv && !hltv->IsMasterProxy() )
  2004. {
  2005. hltv->Shutdown();
  2006. }
  2007. // NOTE: Replay system does not deal with relay proxies.
  2008. COM_TimestampedLog( "Host_FreeToLowMark" );
  2009. Host_FreeStateAndWorld( true );
  2010. Host_FreeToLowMark( true );
  2011. // Clear out the mapversion so it's reset when the next level loads. Needed for changelevels.
  2012. g_ServerGlobalVariables.mapversion = 0;
  2013. COM_TimestampedLog( "sv.Clear()" );
  2014. Clear();
  2015. COM_TimestampedLog( "framesnapshotmanager->LevelChanged()" );
  2016. // Clear out the state of the most recently sent packed entities from
  2017. // the snapshot manager
  2018. framesnapshotmanager->LevelChanged();
  2019. // set map name
  2020. Q_strncpy( m_szMapname, szMapName, sizeof( m_szMapname ) );
  2021. Q_strncpy( m_szMapFilename, szMapFile, sizeof( m_szMapFilename ) );
  2022. // set startspot
  2023. if (startspot)
  2024. {
  2025. Q_strncpy(m_szStartspot, startspot, sizeof( m_szStartspot ) );
  2026. }
  2027. else
  2028. {
  2029. m_szStartspot[0] = 0;
  2030. }
  2031. if ( g_FlushMemoryOnNextServer )
  2032. {
  2033. g_FlushMemoryOnNextServer = false;
  2034. if ( IsX360() )
  2035. {
  2036. g_pQueuedLoader->PurgeAll();
  2037. }
  2038. g_pDataCache->Flush();
  2039. g_pMaterialSystem->CompactMemory();
  2040. g_pFileSystem->AsyncFinishAll();
  2041. #if !defined( SWDS )
  2042. extern CThreadMutex g_SndMutex;
  2043. g_SndMutex.Lock();
  2044. g_pFileSystem->AsyncSuspend();
  2045. g_pThreadPool->SuspendExecution();
  2046. MemAlloc_CompactHeap();
  2047. g_pThreadPool->ResumeExecution();
  2048. g_pFileSystem->AsyncResume();
  2049. g_SndMutex.Unlock();
  2050. #endif // SWDS
  2051. }
  2052. // Preload any necessary data from the xzps:
  2053. g_pFileSystem->SetupPreloadData();
  2054. g_pMDLCache->InitPreloadData( false );
  2055. // Allocate server memory
  2056. max_edicts = MAX_EDICTS;
  2057. g_ServerGlobalVariables.maxEntities = max_edicts;
  2058. g_ServerGlobalVariables.maxClients = GetMaxClients();
  2059. #ifndef SWDS
  2060. g_ClientGlobalVariables.network_protocol = PROTOCOL_VERSION;
  2061. #endif
  2062. // Assume no entities beyond world and client slots
  2063. num_edicts = GetMaxClients()+1;
  2064. COM_TimestampedLog( "SV_AllocateEdicts" );
  2065. SV_AllocateEdicts();
  2066. serverGameEnts->SetDebugEdictBase( edicts );
  2067. allowsignonwrites = true;
  2068. serverclasses = 0; // number of unique server classes
  2069. serverclassbits = 0; // log2 of serverclasses
  2070. // Assign class ids to server classes here so we can encode temp ents into signon
  2071. // if needed
  2072. AssignClassIds();
  2073. COM_TimestampedLog( "Set up players" );
  2074. // allocate player data, and assign the values into the edicts
  2075. for ( i=0 ; i< GetClientCount() ; i++ )
  2076. {
  2077. CGameClient * pClient = Client(i);
  2078. // edict for a player is slot + 1, world = 0
  2079. pClient->edict = edicts + i + 1;
  2080. // Setup up the edict
  2081. InitializeEntityDLLFields( pClient->edict );
  2082. }
  2083. COM_TimestampedLog( "Set up players(done)" );
  2084. m_State = ss_loading;
  2085. // Set initial time values.
  2086. m_flTickInterval = host_state.interval_per_tick;
  2087. m_nTickCount = (int)( 1.0 / host_state.interval_per_tick ) + 1; // Start at appropriate 1
  2088. g_ServerGlobalVariables.tickcount = m_nTickCount;
  2089. g_ServerGlobalVariables.curtime = GetTime();
  2090. // Load the world model.
  2091. g_pFileSystem->AddSearchPath( szMapFile, "GAME", PATH_ADD_TO_HEAD );
  2092. g_pFileSystem->BeginMapAccess();
  2093. if ( !CommandLine()->FindParm( "-allowstalezip" ) )
  2094. {
  2095. if ( g_pFileSystem->FileExists( "stale.txt", "GAME" ) )
  2096. {
  2097. Warning( "This map is not final!! Needs to be rebuilt without -keepstalezip and without -onlyents\n" );
  2098. }
  2099. }
  2100. COM_TimestampedLog( "modelloader->GetModelForName(%s) -- Start", szMapFile );
  2101. host_state.SetWorldModel( modelloader->GetModelForName( szMapFile, IModelLoader::FMODELLOADER_SERVER ) );
  2102. if ( !host_state.worldmodel )
  2103. {
  2104. ConMsg( "Couldn't spawn server %s\n", szMapFile );
  2105. m_State = ss_dead;
  2106. g_pFileSystem->EndMapAccess();
  2107. return false;
  2108. }
  2109. COM_TimestampedLog( "modelloader->GetModelForName(%s) -- Finished", szMapFile );
  2110. if ( IsMultiplayer() && !IsX360() )
  2111. {
  2112. #ifndef SWDS
  2113. EngineVGui()->UpdateProgressBar(PROGRESS_CRCMAP);
  2114. #endif
  2115. // Server map CRC check.
  2116. V_memset( worldmapMD5.bits, 0, MD5_DIGEST_LENGTH );
  2117. if ( !MD5_MapFile( &worldmapMD5, szMapFile ) )
  2118. {
  2119. ConMsg( "Couldn't CRC server map: %s\n", szMapFile );
  2120. m_State = ss_dead;
  2121. g_pFileSystem->EndMapAccess();
  2122. return false;
  2123. }
  2124. #ifndef SWDS
  2125. EngineVGui()->UpdateProgressBar(PROGRESS_CRCCLIENTDLL);
  2126. #endif
  2127. }
  2128. else
  2129. {
  2130. V_memset( worldmapMD5.bits, 0, MD5_DIGEST_LENGTH );
  2131. }
  2132. m_StringTables = networkStringTableContainerServer;
  2133. COM_TimestampedLog( "SV_CreateNetworkStringTables" );
  2134. #ifndef SWDS
  2135. EngineVGui()->UpdateProgressBar(PROGRESS_CREATENETWORKSTRINGTABLES);
  2136. #endif
  2137. // Create network string tables ( including precache tables )
  2138. SV_CreateNetworkStringTables();
  2139. // Leave empty slots for models/sounds/generic (not for decals though)
  2140. PrecacheModel( "", 0 );
  2141. PrecacheGeneric( "", 0 );
  2142. PrecacheSound( "", 0 );
  2143. COM_TimestampedLog( "Precache world model (%s)", szMapFile );
  2144. #ifndef SWDS
  2145. EngineVGui()->UpdateProgressBar(PROGRESS_PRECACHEWORLD);
  2146. #endif
  2147. // Add in world
  2148. PrecacheModel( szMapFile, RES_FATALIFMISSING | RES_PRELOAD, host_state.worldmodel );
  2149. COM_TimestampedLog( "Precache brush models" );
  2150. // Add world submodels to the model cache
  2151. for ( i = 1 ; i < host_state.worldbrush->numsubmodels ; i++ )
  2152. {
  2153. // Add in world brush models
  2154. char localmodel[5]; // inline model names "*1", "*2" etc
  2155. Q_snprintf( localmodel, sizeof( localmodel ), "*%i", i );
  2156. PrecacheModel( localmodel, RES_FATALIFMISSING | RES_PRELOAD, modelloader->GetModelForName( localmodel, IModelLoader::FMODELLOADER_SERVER ) );
  2157. }
  2158. #ifndef SWDS
  2159. EngineVGui()->UpdateProgressBar(PROGRESS_CLEARWORLD);
  2160. #endif
  2161. COM_TimestampedLog( "SV_ClearWorld" );
  2162. // Clear world interaction links
  2163. // Loads and inserts static props
  2164. SV_ClearWorld();
  2165. //
  2166. // load the rest of the entities
  2167. //
  2168. COM_TimestampedLog( "InitializeEntityDLLFields" );
  2169. InitializeEntityDLLFields( edicts );
  2170. // Clear the free bit on the world edict (entindex: 0).
  2171. ED_ClearFreeFlag( &edicts[0] );
  2172. if (coop.GetFloat())
  2173. {
  2174. g_ServerGlobalVariables.coop = (coop.GetInt() != 0);
  2175. }
  2176. else
  2177. {
  2178. g_ServerGlobalVariables.deathmatch = (deathmatch.GetInt() != 0);
  2179. }
  2180. g_ServerGlobalVariables.mapname = MAKE_STRING( m_szMapname );
  2181. g_ServerGlobalVariables.startspot = MAKE_STRING( m_szStartspot );
  2182. GetTestScriptMgr()->CheckPoint( "map_load" );
  2183. // set game event
  2184. IGameEvent *event = g_GameEventManager.CreateEvent( "server_spawn" );
  2185. if ( event )
  2186. {
  2187. event->SetString( "hostname", host_name.GetString() );
  2188. event->SetString( "address", net_local_adr.ToString( false ) );
  2189. event->SetInt( "port", GetUDPPort() );
  2190. event->SetString( "game", com_gamedir );
  2191. event->SetString( "mapname", GetMapName() );
  2192. event->SetInt( "maxplayers", GetMaxClients() );
  2193. event->SetInt( "password", 0 ); // TODO
  2194. #if defined( _WIN32 )
  2195. event->SetString( "os", "WIN32" );
  2196. #elif defined ( LINUX )
  2197. event->SetString( "os", "LINUX" );
  2198. #elif defined ( OSX )
  2199. event->SetString( "os", "OSX" );
  2200. #else
  2201. #error
  2202. #endif
  2203. event->SetInt( "dedicated", IsDedicated() ? 1 : 0 );
  2204. g_GameEventManager.FireEvent( event );
  2205. }
  2206. COM_TimestampedLog( "SV_SpawnServer -- Finished" );
  2207. g_pFileSystem->EndMapAccess();
  2208. return true;
  2209. }
  2210. void CGameServer::UpdateMasterServerPlayers()
  2211. {
  2212. if ( !Steam3Server().SteamGameServer() )
  2213. return;
  2214. for ( int i=0; i < GetClientCount() ; i++ )
  2215. {
  2216. CGameClient *client = Client(i);
  2217. if ( !client->IsConnected() )
  2218. continue;
  2219. CPlayerState *pl = serverGameClients->GetPlayerState( client->edict );
  2220. if ( !pl )
  2221. continue;
  2222. if ( !client->m_SteamID.IsValid() )
  2223. continue;
  2224. Steam3Server().SteamGameServer()->BUpdateUserData( client->m_SteamID, client->GetClientName(), pl->frags );
  2225. }
  2226. }
  2227. //-----------------------------------------------------------------------------
  2228. // SV_IsSimulating
  2229. //-----------------------------------------------------------------------------
  2230. bool SV_IsSimulating( void )
  2231. {
  2232. if ( sv.IsPaused() )
  2233. return false;
  2234. #ifndef SWDS
  2235. // Don't simulate in single player if console is down or the bug UI is active and we're in a game
  2236. if ( !sv.IsMultiplayer() )
  2237. {
  2238. if ( g_LostVideoMemory )
  2239. return false;
  2240. // Don't simulate in single player if console is down or the bug UI is active and we're in a game
  2241. if ( cl.IsActive() && ( Con_IsVisible() || EngineVGui()->ShouldPause() ) )
  2242. return false;
  2243. }
  2244. #endif //SWDS
  2245. return true;
  2246. }
  2247. //-----------------------------------------------------------------------------
  2248. // Purpose:
  2249. // Output : Returns true on success, false on failure.
  2250. //-----------------------------------------------------------------------------
  2251. bool SV_HasPlayers()
  2252. {
  2253. /*int i;
  2254. for ( i = 0; i < sv.clients.Count(); i++ )
  2255. {
  2256. if ( sv.clients[ i ]->active )
  2257. {
  2258. return true;
  2259. }
  2260. }
  2261. return false; */
  2262. return sv.GetClientCount() > 0;
  2263. }
  2264. //-----------------------------------------------------------------------------
  2265. // Purpose: Run physics code (simulating == false means we're paused, but we'll still
  2266. // allow player usercmds to be processed
  2267. //-----------------------------------------------------------------------------
  2268. void SV_Think( bool bIsSimulating )
  2269. {
  2270. VPROF( "SV_Physics" );
  2271. tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "SV_Think(%s)", bIsSimulating ? "simulating" : "not simulating" );
  2272. // @FD The staging branch already did away with "frames" and wakes on tick
  2273. // optimally. Currently the hibernating flag essentially means "is empty
  2274. // and available to host a game," which is used for the GC matchmaking.
  2275. sv.UpdateHibernationState();
  2276. if ( s_timeForceShutdown > 0.0 )
  2277. {
  2278. if ( s_timeForceShutdown < Plat_FloatTime() )
  2279. {
  2280. Warning( "Server shutting down because sv_shutdown was requested and timeout has expired.\n" );
  2281. HostState_Shutdown();
  2282. }
  2283. }
  2284. // if ( sv.IsDedicated() )
  2285. // {
  2286. // sv.UpdateReservedState();
  2287. // if ( sv.IsHibernating() )
  2288. // {
  2289. // // if we're hibernating, just sleep for a while and do not call server.dll to run a frame
  2290. // int nMilliseconds = sv_hibernate_ms.GetInt();
  2291. //#ifndef DEDICATED // Non-Linux
  2292. // if ( g_bIsVGuiBasedDedicatedServer )
  2293. // {
  2294. // // Keep VGUi happy
  2295. // nMilliseconds = sv_hibernate_ms_vgui.GetInt();
  2296. // }
  2297. //#endif
  2298. // g_pNetworkSystem->SleepUntilMessages( NS_SERVER, nMilliseconds );
  2299. // return;
  2300. // }
  2301. // }
  2302. g_ServerGlobalVariables.tickcount = sv.m_nTickCount;
  2303. g_ServerGlobalVariables.curtime = sv.GetTime();
  2304. g_ServerGlobalVariables.frametime = bIsSimulating ? host_state.interval_per_tick : 0;
  2305. // in singleplayer only run think/simulation if localplayer is connected
  2306. bIsSimulating = bIsSimulating && ( sv.IsMultiplayer() || cl.IsActive() );
  2307. g_pServerPluginHandler->GameFrame( bIsSimulating );
  2308. }
  2309. //-----------------------------------------------------------------------------
  2310. // Purpose:
  2311. // Input : simulating -
  2312. //-----------------------------------------------------------------------------
  2313. void SV_PreClientUpdate(bool bIsSimulating )
  2314. {
  2315. if ( !serverGameDLL )
  2316. return;
  2317. serverGameDLL->PreClientUpdate( bIsSimulating );
  2318. }
  2319. //-----------------------------------------------------------------------------
  2320. //
  2321. //-----------------------------------------------------------------------------
  2322. /*
  2323. ==================
  2324. SV_Frame
  2325. ==================
  2326. */
  2327. CFunctor *g_pDeferredServerWork;
  2328. void SV_FrameExecuteThreadDeferred()
  2329. {
  2330. if ( g_pDeferredServerWork )
  2331. {
  2332. (*g_pDeferredServerWork)();
  2333. delete g_pDeferredServerWork;
  2334. g_pDeferredServerWork = NULL;
  2335. }
  2336. }
  2337. void SV_SendClientUpdates( bool bIsSimulating, bool bSendDuringPause )
  2338. {
  2339. bool bForcedSend = s_bForceSend;
  2340. s_bForceSend = false;
  2341. // ask game.dll to add any debug graphics
  2342. SV_PreClientUpdate( bIsSimulating );
  2343. // This causes network messages to be sent
  2344. sv.SendClientMessages( bIsSimulating || bForcedSend );
  2345. // tricky, increase stringtable tick at least one tick
  2346. // so changes made after this point are not counted to this server
  2347. // frame since we already send out the client snapshots
  2348. networkStringTableContainerServer->SetTick( sv.m_nTickCount + 1 );
  2349. }
  2350. void SV_Frame( bool finalTick )
  2351. {
  2352. VPROF( "SV_Frame" );
  2353. if ( serverGameDLL && finalTick )
  2354. {
  2355. serverGameDLL->Think( finalTick );
  2356. }
  2357. if ( !sv.IsActive() || !Host_ShouldRun() )
  2358. {
  2359. return;
  2360. }
  2361. g_ServerGlobalVariables.frametime = host_state.interval_per_tick;
  2362. bool bIsSimulating = SV_IsSimulating();
  2363. bool bSendDuringPause = sv_noclipduringpause ? sv_noclipduringpause->GetBool() : false;
  2364. // unlock sting tables to allow changes, helps to find unwanted changes (bebug build only)
  2365. networkStringTableContainerServer->Lock( false );
  2366. // Run any commands from client and play client Think functions if it is time.
  2367. sv.RunFrame(); // read network input etc
  2368. bool simulated = false;
  2369. if ( SV_HasPlayers() )
  2370. {
  2371. bool serverCanSimulate = ( serverGameDLL && !serverGameDLL->IsRestoring() ) ? true : false;
  2372. if ( serverCanSimulate && ( bIsSimulating || bSendDuringPause ) )
  2373. {
  2374. simulated = true;
  2375. sv.m_nTickCount++;
  2376. networkStringTableContainerServer->SetTick( sv.m_nTickCount );
  2377. }
  2378. SV_Think( bIsSimulating );
  2379. }
  2380. else if ( sv.IsMultiplayer() )
  2381. {
  2382. SV_Think( false ); // let the game.dll systems think
  2383. }
  2384. // This value is read on another thread, so this needs to only happen once per frame and be atomic.
  2385. sv.m_bSimulatingTicks = simulated;
  2386. // Send the results of movement and physics to the clients
  2387. if ( finalTick )
  2388. {
  2389. if ( !IsEngineThreaded() || sv.IsMultiplayer() )
  2390. SV_SendClientUpdates( bIsSimulating, bSendDuringPause );
  2391. else
  2392. g_pDeferredServerWork = CreateFunctor( SV_SendClientUpdates, bIsSimulating, bSendDuringPause );
  2393. }
  2394. // lock string tables
  2395. networkStringTableContainerServer->Lock( true );
  2396. // let the steam auth server process new connections
  2397. if ( IsPC() && sv.IsMultiplayer() )
  2398. {
  2399. Steam3Server().RunFrame();
  2400. }
  2401. }