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.

1682 lines
41 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "server_pch.h"
  7. #include "framesnapshot.h"
  8. #include "checksum_engine.h"
  9. #include "sv_main.h"
  10. #include "GameEventManager.h"
  11. #include "networkstringtable.h"
  12. #include "demo.h"
  13. #include "PlayerState.h"
  14. #include "tier0/vprof.h"
  15. #include "sv_packedentities.h"
  16. #include "LocalNetworkBackdoor.h"
  17. #include "testscriptmgr.h"
  18. #include "hltvserver.h"
  19. #include "pr_edict.h"
  20. #include "logofile_shared.h"
  21. #include "dt_send_eng.h"
  22. #include "sv_plugin.h"
  23. #include "download.h"
  24. #include "cmodel_engine.h"
  25. #include "tier1/CommandBuffer.h"
  26. #include "gl_cvars.h"
  27. #if defined( REPLAY_ENABLED )
  28. #include "replayserver.h"
  29. #include "replay_internal.h"
  30. #endif
  31. #include "tier2/tier2.h"
  32. // memdbgon must be the last include file in a .cpp file!!!
  33. #include "tier0/memdbgon.h"
  34. extern CNetworkStringTableContainer *networkStringTableContainerServer;
  35. static ConVar sv_timeout( "sv_timeout", "65", 0, "After this many seconds without a message from a client, the client is dropped" );
  36. static ConVar sv_maxrate( "sv_maxrate", "0", FCVAR_REPLICATED, "Max bandwidth rate allowed on server, 0 == unlimited" );
  37. static ConVar sv_minrate( "sv_minrate", "3500", FCVAR_REPLICATED, "Min bandwidth rate allowed on server, 0 == unlimited" );
  38. ConVar sv_maxupdaterate( "sv_maxupdaterate", "66", FCVAR_REPLICATED, "Maximum updates per second that the server will allow" );
  39. ConVar sv_minupdaterate( "sv_minupdaterate", "10", FCVAR_REPLICATED, "Minimum updates per second that the server will allow" );
  40. ConVar sv_stressbots("sv_stressbots", "0", FCVAR_DEVELOPMENTONLY, "If set to 1, the server calculates data and fills packets to bots. Used for perf testing.");
  41. static ConVar sv_allowdownload ("sv_allowdownload", "1", 0, "Allow clients to download files");
  42. static ConVar sv_allowupload ("sv_allowupload", "1", 0, "Allow clients to upload customizations files");
  43. ConVar sv_sendtables ( "sv_sendtables", "0", FCVAR_DEVELOPMENTONLY, "Force full sendtable sending path." );
  44. extern ConVar sv_maxreplay;
  45. extern ConVar tv_snapshotrate;
  46. extern ConVar tv_transmitall;
  47. extern ConVar sv_pure_kick_clients;
  48. extern ConVar sv_pure_trace;
  49. // static ConVar sv_failuretime( "sv_failuretime", "0.5", 0, "After this long without a packet from client, don't send any more until client starts sending again" );
  50. static const char * s_clcommands[] =
  51. {
  52. "status",
  53. "pause",
  54. "setpause",
  55. "unpause",
  56. "ping",
  57. "rpt_server_enable",
  58. "rpt_client_enable",
  59. #ifndef SWDS
  60. "rpt",
  61. "rpt_connect",
  62. "rpt_password",
  63. "rpt_screenshot",
  64. "rpt_download_log",
  65. #endif
  66. NULL,
  67. };
  68. // Used on the server and on the client to bound its cl_rate cvar.
  69. int ClampClientRate( int nRate )
  70. {
  71. if ( sv_maxrate.GetInt() > 0 )
  72. {
  73. nRate = clamp( nRate, MIN_RATE, sv_maxrate.GetInt() );
  74. }
  75. if ( sv_minrate.GetInt() > 0 )
  76. {
  77. nRate = clamp( nRate, sv_minrate.GetInt(), MAX_RATE );
  78. }
  79. return nRate;
  80. }
  81. CGameClient::CGameClient(int slot, CBaseServer *pServer )
  82. {
  83. Clear();
  84. m_nClientSlot = slot;
  85. m_nEntityIndex = slot+1;
  86. m_Server = pServer;
  87. m_pCurrentFrame = NULL;
  88. m_bIsInReplayMode = false;
  89. // NULL out data we'll never use.
  90. memset( &m_PrevPackInfo, 0, sizeof( m_PrevPackInfo ) );
  91. m_PrevPackInfo.m_pTransmitEdict = &m_PrevTransmitEdict;
  92. }
  93. CGameClient::~CGameClient()
  94. {
  95. }
  96. bool CGameClient::ProcessClientInfo( CLC_ClientInfo *msg )
  97. {
  98. CBaseClient::ProcessClientInfo( msg );
  99. if ( m_bIsHLTV )
  100. {
  101. // Likely spoofing, or misconfiguration. Don't let Disconnect pathway believe this is a replay bot, it will
  102. // asplode.
  103. m_bIsHLTV = false;
  104. Disconnect( "ProcessClientInfo: SourceTV can not connect to game directly.\n" );
  105. return false;
  106. }
  107. #if defined( REPLAY_ENABLED )
  108. if ( m_bIsReplay )
  109. {
  110. // Likely spoofing, or misconfiguration. Don't let Disconnect pathway believe this is an hltv bot, it will
  111. // asplode.
  112. m_bIsReplay = false;
  113. Disconnect( "ProcessClientInfo: Replay can not connect to game directly.\n" );
  114. return false;
  115. }
  116. #endif
  117. if ( sv_allowupload.GetBool() )
  118. {
  119. // download all missing customizations files from this client;
  120. DownloadCustomizations();
  121. }
  122. return true;
  123. }
  124. bool CGameClient::ProcessMove(CLC_Move *msg)
  125. {
  126. // Don't process usercmds until the client is active. If we do, there can be weird behavior
  127. // like the game trying to send reliable messages to the client and having those messages discarded.
  128. if ( !IsActive() )
  129. return true;
  130. if ( m_LastMovementTick == sv.m_nTickCount )
  131. {
  132. // Only one movement command per frame, someone is cheating.
  133. return true;
  134. }
  135. m_LastMovementTick = sv.m_nTickCount;
  136. int totalcmds =msg->m_nBackupCommands + msg->m_nNewCommands;
  137. // Decrement drop count by held back packet count
  138. int netdrop = m_NetChannel->GetDropNumber();
  139. bool ignore = !sv.IsActive();
  140. #ifdef SWDS
  141. bool paused = sv.IsPaused();
  142. #else
  143. bool paused = sv.IsPaused() || ( !sv.IsMultiplayer() && Con_IsVisible() );
  144. #endif
  145. // Make sure player knows of correct server time
  146. g_ServerGlobalVariables.curtime = sv.GetTime();
  147. g_ServerGlobalVariables.frametime = host_state.interval_per_tick;
  148. // COM_Log( "sv.log", " executing %i move commands from client starting with command %i(%i)\n",
  149. // numcmds,
  150. // m_Client->m_NetChan->incoming_sequence,
  151. // m_Client->m_NetChan->incoming_sequence & SV_UPDATE_MASK );
  152. int startbit = msg->m_DataIn.GetNumBitsRead();
  153. serverGameClients->ProcessUsercmds
  154. (
  155. edict, // Player edict
  156. &msg->m_DataIn,
  157. msg->m_nNewCommands,
  158. totalcmds, // Commands in packet
  159. netdrop, // Number of dropped commands
  160. ignore, // Don't actually run anything
  161. paused // Run, but don't actually do any movement
  162. );
  163. if ( msg->m_DataIn.IsOverflowed() )
  164. {
  165. Disconnect( "ProcessUsercmds: Overflowed reading usercmd data (check sending and receiving code for mismatches)!\n" );
  166. return false;
  167. }
  168. int endbit = msg->m_DataIn.GetNumBitsRead();
  169. if ( msg->m_nLength != (endbit-startbit) )
  170. {
  171. Disconnect( "ProcessUsercmds: Incorrect reading frame (check sending and receiving code for mismatches)!\n" );
  172. return false;
  173. }
  174. return true;
  175. }
  176. bool CGameClient::ProcessVoiceData( CLC_VoiceData *msg )
  177. {
  178. char voiceDataBuffer[4096];
  179. int bitsRead = msg->m_DataIn.ReadBitsClamped( voiceDataBuffer, msg->m_nLength );
  180. SV_BroadcastVoiceData( this, Bits2Bytes(bitsRead), voiceDataBuffer, msg->m_xuid );
  181. return true;
  182. }
  183. bool CGameClient::ProcessCmdKeyValues( CLC_CmdKeyValues *msg )
  184. {
  185. serverGameClients->ClientCommandKeyValues( edict, msg->GetKeyValues() );
  186. return true;
  187. }
  188. bool CGameClient::ProcessRespondCvarValue( CLC_RespondCvarValue *msg )
  189. {
  190. if ( msg->m_iCookie > 0 )
  191. {
  192. if ( g_pServerPluginHandler )
  193. g_pServerPluginHandler->OnQueryCvarValueFinished( msg->m_iCookie, edict, msg->m_eStatusCode, msg->m_szCvarName, msg->m_szCvarValue );
  194. }
  195. else
  196. {
  197. // Negative cookie means the game DLL asked for the value.
  198. if ( serverGameDLL && g_iServerGameDLLVersion >= 6 )
  199. {
  200. #ifdef REL_TO_STAGING_MERGE_TODO
  201. serverGameDLL->OnQueryCvarValueFinished( msg->m_iCookie, edict, msg->m_eStatusCode, msg->m_szCvarName, msg->m_szCvarValue );
  202. #endif
  203. }
  204. }
  205. return true;
  206. }
  207. #include "pure_server.h"
  208. bool CGameClient::ProcessFileCRCCheck( CLC_FileCRCCheck *msg )
  209. {
  210. // Ignore this message if we're not in pure server mode...
  211. if ( !sv.IsInPureServerMode() )
  212. return true;
  213. char warningStr[1024] = {0};
  214. // The client may send us files we don't care about, so filter them here
  215. // if ( !sv.GetPureServerWhitelist()->GetForceMatchList()->IsFileInList( msg->m_szFilename ) )
  216. // return true;
  217. // first check against all the other files users have sent
  218. FileHash_t filehash;
  219. filehash.m_md5contents = msg->m_MD5;
  220. filehash.m_crcIOSequence = msg->m_CRCIOs;
  221. filehash.m_eFileHashType = msg->m_eFileHashType;
  222. filehash.m_cbFileLen = msg->m_nFileFraction;
  223. filehash.m_nPackFileNumber = msg->m_nPackFileNumber;
  224. filehash.m_PackFileID = msg->m_PackFileID;
  225. const char *path = msg->m_szPathID;
  226. const char *fileName = msg->m_szFilename;
  227. if ( g_PureFileTracker.DoesFileMatch( path, fileName, msg->m_nFileFraction, &filehash, GetNetworkID() ) )
  228. {
  229. // track successful file
  230. }
  231. else
  232. {
  233. V_snprintf( warningStr, sizeof( warningStr ), "Pure server: file [%s]\\%s does not match the server's file.", path, fileName );
  234. }
  235. // still ToDo:
  236. // 1. make sure the user sends some files
  237. // 2. make sure the user doesnt skip any files
  238. // 3. make sure the user sends the right files...
  239. if ( warningStr[0] )
  240. {
  241. if ( sv_pure_kick_clients.GetInt() )
  242. {
  243. Disconnect( "%s", warningStr );
  244. }
  245. else
  246. {
  247. ClientPrintf( "Warning: %s\n", warningStr );
  248. if ( sv_pure_trace.GetInt() >= 1 )
  249. {
  250. Msg( "[%s] %s\n", GetNetworkIDString(), warningStr );
  251. }
  252. }
  253. }
  254. else
  255. {
  256. if ( sv_pure_trace.GetInt() >= 2 )
  257. {
  258. Msg( "Pure server CRC check: client %s passed check for [%s]\\%s\n", GetClientName(), msg->m_szPathID, msg->m_szFilename );
  259. }
  260. }
  261. return true;
  262. }
  263. bool CGameClient::ProcessFileMD5Check( CLC_FileMD5Check *msg )
  264. {
  265. // Legacy message
  266. return true;
  267. }
  268. #if defined( REPLAY_ENABLED )
  269. bool CGameClient::ProcessSaveReplay( CLC_SaveReplay *pMsg )
  270. {
  271. // Don't allow on listen servers
  272. if ( !sv.IsDedicated() )
  273. return false;
  274. if ( !g_pReplay )
  275. return false;
  276. g_pReplay->SV_NotifyReplayRequested();
  277. return true;
  278. }
  279. #endif
  280. void CGameClient::DownloadCustomizations()
  281. {
  282. for ( int i=0; i<MAX_CUSTOM_FILES; i++ )
  283. {
  284. if ( m_nCustomFiles[i].crc == 0 )
  285. continue; // slot not used
  286. CCustomFilename hexname( m_nCustomFiles[i].crc );
  287. if ( g_pFileSystem->FileExists( hexname.m_Filename, "game" ) )
  288. continue; // we already have it
  289. // we don't have it, request download from client
  290. m_nCustomFiles[i].reqID = m_NetChannel->RequestFile( hexname.m_Filename );
  291. }
  292. }
  293. void CGameClient::Connect( const char * szName, int nUserID, INetChannel *pNetChannel, bool bFakePlayer, int clientChallenge )
  294. {
  295. CBaseClient::Connect( szName, nUserID, pNetChannel, bFakePlayer, clientChallenge );
  296. edict = EDICT_NUM( m_nEntityIndex );
  297. // init PackInfo
  298. m_PackInfo.m_pClientEnt = edict;
  299. m_PackInfo.m_nPVSSize = sizeof( m_PackInfo.m_PVS );
  300. // fire global game event - server only
  301. IGameEvent *event = g_GameEventManager.CreateEvent( "player_connect" );
  302. {
  303. event->SetInt( "userid", m_UserID );
  304. event->SetInt( "index", m_nClientSlot );
  305. event->SetString( "name", m_Name );
  306. event->SetString("networkid", GetNetworkIDString() );
  307. event->SetString( "address", m_NetChannel?m_NetChannel->GetAddress():"none" );
  308. event->SetInt( "bot", m_bFakePlayer?1:0 );
  309. g_GameEventManager.FireEvent( event, true );
  310. }
  311. // the only difference here is we don't send an
  312. // IP to prevent hackers from doing evil things
  313. event = g_GameEventManager.CreateEvent( "player_connect_client" );
  314. if ( event )
  315. {
  316. event->SetInt( "userid", m_UserID );
  317. event->SetInt( "index", m_nClientSlot );
  318. event->SetString( "name", m_Name );
  319. event->SetString( "networkid", GetNetworkIDString() );
  320. event->SetInt( "bot", m_bFakePlayer ? 1 : 0 );
  321. g_GameEventManager.FireEvent( event );
  322. }
  323. }
  324. void CGameClient::SetupPackInfo( CFrameSnapshot *pSnapshot )
  325. {
  326. // Compute Vis for each client
  327. m_PackInfo.m_nPVSSize = (GetCollisionBSPData()->numclusters + 7) / 8;
  328. serverGameClients->ClientSetupVisibility( (edict_t *)m_pViewEntity,
  329. m_PackInfo.m_pClientEnt, m_PackInfo.m_PVS, m_PackInfo.m_nPVSSize );
  330. // This is the frame we are creating, i.e., the next
  331. // frame after the last one that the client acknowledged
  332. m_pCurrentFrame = AllocateFrame();
  333. m_pCurrentFrame->Init( pSnapshot );
  334. m_PackInfo.m_pTransmitEdict = &m_pCurrentFrame->transmit_entity;
  335. // if this client is the HLTV or Replay client, add the nocheck PVS bit array
  336. // normal clients don't need that extra array
  337. #ifndef _XBOX
  338. #if defined( REPLAY_ENABLED )
  339. if ( IsHLTV() || IsReplay() )
  340. #else
  341. if ( IsHLTV() )
  342. #endif
  343. {
  344. // the hltv client doesn't has a ClientFrame list
  345. m_pCurrentFrame->transmit_always = new CBitVec<MAX_EDICTS>;
  346. m_PackInfo.m_pTransmitAlways = m_pCurrentFrame->transmit_always;
  347. }
  348. else
  349. #endif
  350. {
  351. m_PackInfo.m_pTransmitAlways = NULL;
  352. }
  353. // Add frame to ClientFrame list
  354. int nMaxFrames = MAX_CLIENT_FRAMES;
  355. if ( sv_maxreplay.GetFloat() > 0 )
  356. {
  357. // if the server has replay features enabled, allow a way bigger frame buffer
  358. nMaxFrames = max ( (float)nMaxFrames, sv_maxreplay.GetFloat() / m_Server->GetTickInterval() );
  359. }
  360. if ( nMaxFrames < AddClientFrame( m_pCurrentFrame ) )
  361. {
  362. // If the client has more than 64 frames, the server will start to eat too much memory.
  363. RemoveOldestFrame();
  364. }
  365. // Since area to area visibility is determined by each player's PVS, copy
  366. // the area network lookups into the ClientPackInfo_t
  367. m_PackInfo.m_AreasNetworked = 0;
  368. int areaCount = g_AreasNetworked.Count();
  369. for ( int j = 0; j < areaCount; j++ )
  370. {
  371. m_PackInfo.m_Areas[m_PackInfo.m_AreasNetworked] = g_AreasNetworked[ j ];
  372. m_PackInfo.m_AreasNetworked++;
  373. // Msg("CGameClient::SetupPackInfo: too much areas (%i)", areaCount );
  374. Assert( m_PackInfo.m_AreasNetworked < MAX_WORLD_AREAS );
  375. }
  376. CM_SetupAreaFloodNums( m_PackInfo.m_AreaFloodNums, &m_PackInfo.m_nMapAreas );
  377. }
  378. void CGameClient::SetupPrevPackInfo()
  379. {
  380. memcpy( &m_PrevTransmitEdict, m_PackInfo.m_pTransmitEdict, sizeof( m_PrevTransmitEdict ) );
  381. // Copy the relevant fields into m_PrevPackInfo.
  382. m_PrevPackInfo.m_AreasNetworked = m_PackInfo.m_AreasNetworked;
  383. memcpy( m_PrevPackInfo.m_Areas, m_PackInfo.m_Areas, sizeof( m_PackInfo.m_Areas[0] ) * m_PackInfo.m_AreasNetworked );
  384. m_PrevPackInfo.m_nPVSSize = m_PackInfo.m_nPVSSize;
  385. memcpy( m_PrevPackInfo.m_PVS, m_PackInfo.m_PVS, m_PackInfo.m_nPVSSize );
  386. m_PrevPackInfo.m_nMapAreas = m_PackInfo.m_nMapAreas;
  387. memcpy( m_PrevPackInfo.m_AreaFloodNums, m_PackInfo.m_AreaFloodNums, m_PackInfo.m_nMapAreas * sizeof( m_PackInfo.m_nMapAreas ) );
  388. }
  389. /*
  390. ================
  391. CheckRate
  392. Make sure channel rate for active client is within server bounds
  393. ================
  394. */
  395. void CGameClient::SetRate(int nRate, bool bForce )
  396. {
  397. if ( !bForce )
  398. {
  399. nRate = ClampClientRate( nRate );
  400. }
  401. CBaseClient::SetRate( nRate, bForce );
  402. }
  403. void CGameClient::SetUpdateRate(int udpaterate, bool bForce)
  404. {
  405. if ( !bForce )
  406. {
  407. if ( sv_maxupdaterate.GetInt() > 0 )
  408. {
  409. udpaterate = clamp( udpaterate, 1, sv_maxupdaterate.GetInt() );
  410. }
  411. if ( sv_minupdaterate.GetInt() > 0 )
  412. {
  413. udpaterate = clamp( udpaterate, sv_minupdaterate.GetInt(), 100 );
  414. }
  415. }
  416. CBaseClient::SetUpdateRate( udpaterate, bForce );
  417. }
  418. void CGameClient::UpdateUserSettings()
  419. {
  420. // set voice loopback
  421. m_bVoiceLoopback = m_ConVars->GetInt( "voice_loopback", 0 ) != 0;
  422. CBaseClient::UpdateUserSettings();
  423. // Give entity dll a chance to look at the changes.
  424. // Do this after CBaseClient::UpdateUserSettings() so name changes like prepending a (1)
  425. // take effect before the server dll sees the name.
  426. g_pServerPluginHandler->ClientSettingsChanged( edict );
  427. }
  428. //-----------------------------------------------------------------------------
  429. // Purpose: A File has been received, if it's a logo, send it on to any other players who need it
  430. // and return true, otherwise, return false
  431. // Input : *cl -
  432. // *filename -
  433. // Output : Returns true on success, false on failure.
  434. /*-----------------------------------------------------------------------------
  435. bool CGameClient::ProcessIncomingLogo( const char *filename )
  436. {
  437. char crcfilename[ 512 ];
  438. char logohex[ 16 ];
  439. Q_binarytohex( (byte *)&logo, sizeof( logo ), logohex, sizeof( logohex ) );
  440. Q_snprintf( crcfilename, sizeof( crcfilename ), "materials/decals/downloads/%s.vtf", logohex );
  441. // It's not a logo file?
  442. if ( Q_strcasecmp( filename, crcfilename ) )
  443. {
  444. return false;
  445. }
  446. // First, make sure crc is valid
  447. CRC32_t check;
  448. CRC_File( &check, crcfilename );
  449. if ( check != logo )
  450. {
  451. ConMsg( "Incoming logo file didn't match player's logo CRC, ignoring\n" );
  452. // Still note that it was a logo!
  453. return true;
  454. }
  455. // Okay, looks good, see if any other players need this logo file
  456. SV_SendLogo( check );
  457. return true;
  458. } */
  459. /*
  460. ===================
  461. SV_FullClientUpdate
  462. sends all the info about *cl to *sb
  463. ===================
  464. */
  465. bool CGameClient::IsHearingClient( int index ) const
  466. {
  467. #if defined( REPLAY_ENABLED )
  468. if ( IsHLTV() || IsReplay() )
  469. #else
  470. if ( IsHLTV() )
  471. #endif
  472. return true;
  473. if ( index == GetPlayerSlot() )
  474. return m_bVoiceLoopback;
  475. CGameClient *pClient = sv.Client( index );
  476. return pClient->m_VoiceStreams.Get( GetPlayerSlot() ) != 0;
  477. }
  478. bool CGameClient::IsProximityHearingClient( int index ) const
  479. {
  480. CGameClient *pClient = sv.Client( index );
  481. return pClient->m_VoiceProximity.Get( GetPlayerSlot() ) != 0;
  482. }
  483. void CGameClient::Inactivate( void )
  484. {
  485. if ( edict && !edict->IsFree() )
  486. {
  487. m_Server->RemoveClientFromGame( this );
  488. }
  489. #ifndef _XBOX
  490. if ( IsHLTV() )
  491. {
  492. hltv->Changelevel();
  493. }
  494. #if defined( REPLAY_ENABLED )
  495. if ( IsReplay() )
  496. {
  497. replay->Changelevel();
  498. }
  499. #endif
  500. #endif
  501. CBaseClient::Inactivate();
  502. m_Sounds.Purge();
  503. m_VoiceStreams.ClearAll();
  504. m_VoiceProximity.ClearAll();
  505. DeleteClientFrames( -1 ); // delete all
  506. }
  507. bool CGameClient::UpdateAcknowledgedFramecount(int tick)
  508. {
  509. // free old client frames which won't be used anymore
  510. if ( tick != m_nDeltaTick )
  511. {
  512. // delta tick changed, free all frames smaller than tick
  513. int removeTick = tick;
  514. if ( sv_maxreplay.GetFloat() > 0 )
  515. removeTick -= (sv_maxreplay.GetFloat() / m_Server->GetTickInterval() ); // keep a replay buffer
  516. if ( removeTick > 0 )
  517. {
  518. DeleteClientFrames( removeTick );
  519. }
  520. }
  521. return CBaseClient::UpdateAcknowledgedFramecount( tick );
  522. }
  523. void CGameClient::Clear()
  524. {
  525. #ifndef _XBOX
  526. if ( m_bIsHLTV && hltv )
  527. {
  528. hltv->Shutdown();
  529. }
  530. #if defined( REPLAY_ENABLED )
  531. if ( m_bIsReplay && replay )
  532. {
  533. replay->Shutdown();
  534. }
  535. #endif
  536. #endif
  537. CBaseClient::Clear();
  538. // free all frames
  539. DeleteClientFrames( -1 );
  540. m_Sounds.Purge();
  541. m_VoiceStreams.ClearAll();
  542. m_VoiceProximity.ClearAll();
  543. edict = NULL;
  544. m_pViewEntity = NULL;
  545. m_bVoiceLoopback = false;
  546. m_LastMovementTick = 0;
  547. m_nSoundSequence = 0;
  548. #if defined( REPLAY_ENABLED )
  549. m_flLastSaveReplayTime = host_time;
  550. #endif
  551. }
  552. void CGameClient::Reconnect( void )
  553. {
  554. // If the client was connected before, tell the game .dll to disconnect him/her.
  555. sv.RemoveClientFromGame( this );
  556. CBaseClient::Reconnect();
  557. }
  558. void CGameClient::Disconnect( const char *fmt, ... )
  559. {
  560. va_list argptr;
  561. char reason[1024];
  562. if ( m_nSignonState == SIGNONSTATE_NONE )
  563. return; // no recursion
  564. va_start (argptr,fmt);
  565. Q_vsnprintf (reason, sizeof( reason ), fmt,argptr);
  566. va_end (argptr);
  567. // notify other clients of player leaving the game
  568. // send the username and network id so we don't depend on the CBasePlayer pointer
  569. IGameEvent *event = g_GameEventManager.CreateEvent( "player_disconnect" );
  570. if ( event )
  571. {
  572. event->SetInt("userid", GetUserID() );
  573. event->SetString("reason", reason );
  574. event->SetString("name", GetClientName() );
  575. event->SetString("networkid", GetNetworkIDString() );
  576. event->SetInt( "bot", m_bFakePlayer?1:0 );
  577. g_GameEventManager.FireEvent( event );
  578. }
  579. m_Server->RemoveClientFromGame( this );
  580. CBaseClient::Disconnect( "%s", reason );
  581. }
  582. bool CGameClient::SetSignonState(int state, int spawncount)
  583. {
  584. if ( state == SIGNONSTATE_CONNECTED )
  585. {
  586. if ( !CheckConnect() )
  587. return false;
  588. m_NetChannel->SetTimeout( SIGNON_TIME_OUT ); // allow 5 minutes to load map
  589. m_NetChannel->SetFileTransmissionMode( false );
  590. m_NetChannel->SetMaxBufferSize( true, NET_MAX_PAYLOAD );
  591. }
  592. else if ( state == SIGNONSTATE_NEW )
  593. {
  594. if ( !sv.IsMultiplayer() )
  595. {
  596. // local client as received and create string tables,
  597. // now link server tables to client tables
  598. SV_InstallClientStringTableMirrors();
  599. }
  600. }
  601. else if ( state == SIGNONSTATE_FULL )
  602. {
  603. if ( sv.m_bLoadgame )
  604. {
  605. // If this game was loaded from savegame, finish restoring game now
  606. sv.FinishRestore();
  607. }
  608. m_NetChannel->SetTimeout( sv_timeout.GetFloat() ); // use smaller timeout limit
  609. m_NetChannel->SetFileTransmissionMode( true );
  610. #ifdef _XBOX
  611. // to save memory on the XBOX reduce reliable buffer size from 96 to 8 kB
  612. m_NetChannel->SetMaxBufferSize( true, 8*1024 );
  613. #endif
  614. }
  615. return CBaseClient::SetSignonState( state, spawncount );
  616. }
  617. void CGameClient::SendSound( SoundInfo_t &sound, bool isReliable )
  618. {
  619. #if defined( REPLAY_ENABLED )
  620. if ( IsFakeClient() && !IsHLTV() && !IsReplay() )
  621. #else
  622. if ( IsFakeClient() && !IsHLTV() )
  623. #endif
  624. {
  625. return; // dont send sound messages to bots
  626. }
  627. // don't send sound messages while client is replay mode
  628. if ( m_bIsInReplayMode )
  629. {
  630. return;
  631. }
  632. // reliable sounds are send as single messages
  633. if ( isReliable )
  634. {
  635. SVC_Sounds sndmsg;
  636. char buffer[32];
  637. m_nSoundSequence = ( m_nSoundSequence + 1 ) & SOUND_SEQNUMBER_MASK; // increase own sound sequence counter
  638. sound.nSequenceNumber = 0; // don't transmit nSequenceNumber for reliable sounds
  639. sndmsg.m_DataOut.StartWriting(buffer, sizeof(buffer) );
  640. sndmsg.m_nNumSounds = 1;
  641. sndmsg.m_bReliableSound = true;
  642. SoundInfo_t defaultSound; defaultSound.SetDefault();
  643. sound.WriteDelta( &defaultSound, sndmsg.m_DataOut );
  644. // send reliable sound as single message
  645. SendNetMsg( sndmsg, true );
  646. return;
  647. }
  648. sound.nSequenceNumber = m_nSoundSequence;
  649. m_Sounds.AddToTail( sound ); // queue sounds until snapshot is send
  650. }
  651. void CGameClient::WriteGameSounds( bf_write &buf )
  652. {
  653. if ( m_Sounds.Count() <= 0 )
  654. return;
  655. char data[NET_MAX_PAYLOAD];
  656. SVC_Sounds msg;
  657. msg.m_DataOut.StartWriting( data, sizeof(data) );
  658. int nSoundCount = FillSoundsMessage( msg );
  659. msg.WriteToBuffer( buf );
  660. if ( IsTracing() )
  661. {
  662. TraceNetworkData( buf, "Sounds [count=%d]", nSoundCount );
  663. }
  664. }
  665. int CGameClient::FillSoundsMessage(SVC_Sounds &msg)
  666. {
  667. int i, count = m_Sounds.Count();
  668. // send max 64 sound in multiplayer per snapshot, 255 in SP
  669. int max = m_Server->IsMultiplayer() ? 32 : 255;
  670. // Discard events if we have too many to signal with 8 bits
  671. if ( count > max )
  672. count = max;
  673. // Nothing to send
  674. if ( !count )
  675. return 0;
  676. SoundInfo_t defaultSound; defaultSound.SetDefault();
  677. SoundInfo_t *pDeltaSound = &defaultSound;
  678. msg.m_nNumSounds = count;
  679. msg.m_bReliableSound = false;
  680. msg.SetReliable( false );
  681. Assert( msg.m_DataOut.GetNumBitsLeft() > 0 );
  682. for ( i = 0 ; i < count; i++ )
  683. {
  684. SoundInfo_t &sound = m_Sounds[ i ];
  685. sound.WriteDelta( pDeltaSound, msg.m_DataOut );
  686. pDeltaSound = &m_Sounds[ i ];
  687. }
  688. // remove added events from list
  689. int remove = m_Sounds.Count() - ( count + max );
  690. if ( remove > 0 )
  691. {
  692. DevMsg("Warning! Dropped %i unreliable sounds for client %s.\n" , remove, m_Name );
  693. count+= remove;
  694. }
  695. if ( count > 0 )
  696. {
  697. m_Sounds.RemoveMultiple( 0, count );
  698. }
  699. Assert( m_Sounds.Count() <= max ); // keep ev_max temp ent for next update
  700. return msg.m_nNumSounds;
  701. }
  702. bool CGameClient::CheckConnect( void )
  703. {
  704. // Allow the game dll to reject this client.
  705. char szRejectReason[128];
  706. Q_strncpy( szRejectReason, "Connection rejected by game\n", sizeof( szRejectReason ) );
  707. if ( !g_pServerPluginHandler->ClientConnect( edict, m_Name, m_NetChannel->GetAddress(), szRejectReason, sizeof( szRejectReason ) ) )
  708. {
  709. // Reject the connection and drop the client.
  710. Disconnect( szRejectReason, m_Name );
  711. return false;
  712. }
  713. return true;
  714. }
  715. void CGameClient::ActivatePlayer( void )
  716. {
  717. CBaseClient::ActivatePlayer();
  718. COM_TimestampedLog( "CGameClient::ActivatePlayer -start" );
  719. // call the spawn function
  720. if ( !sv.m_bLoadgame )
  721. {
  722. g_ServerGlobalVariables.curtime = sv.GetTime();
  723. COM_TimestampedLog( "g_pServerPluginHandler->ClientPutInServer" );
  724. g_pServerPluginHandler->ClientPutInServer( edict, m_Name );
  725. }
  726. COM_TimestampedLog( "g_pServerPluginHandler->ClientActive" );
  727. g_pServerPluginHandler->ClientActive( edict, sv.m_bLoadgame );
  728. COM_TimestampedLog( "g_pServerPluginHandler->ClientSettingsChanged" );
  729. g_pServerPluginHandler->ClientSettingsChanged( edict );
  730. COM_TimestampedLog( "GetTestScriptMgr()->CheckPoint" );
  731. GetTestScriptMgr()->CheckPoint( "client_connected" );
  732. // don't send signonstate to client, client will switch to FULL as soon
  733. // as the first full entity update packets has been received
  734. // fire a activate event
  735. IGameEvent *event = g_GameEventManager.CreateEvent( "player_activate" );
  736. if ( event )
  737. {
  738. event->SetInt( "userid", GetUserID() );
  739. g_GameEventManager.FireEvent( event );
  740. }
  741. COM_TimestampedLog( "CGameClient::ActivatePlayer -end" );
  742. }
  743. bool CGameClient::SendSignonData( void )
  744. {
  745. bool bClientHasdifferentTables = false;
  746. if ( sv.m_FullSendTables.IsOverflowed() )
  747. {
  748. Host_Error( "Send Table signon buffer overflowed %i bytes!!!\n", sv.m_FullSendTables.GetNumBytesWritten() );
  749. return false;
  750. }
  751. if ( SendTable_GetCRC() != (CRC32_t)0 )
  752. {
  753. bClientHasdifferentTables = m_nSendtableCRC != SendTable_GetCRC();
  754. }
  755. #ifdef _DEBUG
  756. if ( sv_sendtables.GetInt() == 2 )
  757. {
  758. // force sending class tables, for debugging
  759. bClientHasdifferentTables = true;
  760. }
  761. #endif
  762. // Write the send tables & class infos if needed
  763. if ( bClientHasdifferentTables )
  764. {
  765. if ( sv_sendtables.GetBool() )
  766. {
  767. // send client class table descriptions so it can rebuild tables
  768. ConDMsg("Client sent different SendTable CRC, sending full tables.\n" );
  769. m_NetChannel->SendData( sv.m_FullSendTables );
  770. }
  771. else
  772. {
  773. Disconnect( "Server uses different class tables" );
  774. return false;
  775. }
  776. }
  777. else
  778. {
  779. // use your class infos, CRC is correct
  780. SVC_ClassInfo classmsg( true, m_Server->serverclasses );
  781. m_NetChannel->SendNetMsg( classmsg );
  782. }
  783. if ( !CBaseClient::SendSignonData() )
  784. return false;
  785. m_nSoundSequence = 1; // reset sound sequence numbers after signon block
  786. return true;
  787. }
  788. void CGameClient::SpawnPlayer( void )
  789. {
  790. // run the entrance script
  791. if ( sv.m_bLoadgame )
  792. { // loaded games are fully inited already
  793. // if this is the last client to be connected, unpause
  794. sv.SetPaused( false );
  795. }
  796. else
  797. {
  798. // set up the edict
  799. Assert( serverGameEnts );
  800. serverGameEnts->FreeContainingEntity( edict );
  801. InitializeEntityDLLFields( edict );
  802. }
  803. // restore default client entity and turn off replay mdoe
  804. m_nEntityIndex = m_nClientSlot+1;
  805. m_bIsInReplayMode = false;
  806. // set view entity
  807. SVC_SetView setView( m_nEntityIndex );
  808. SendNetMsg( setView );
  809. CBaseClient::SpawnPlayer();
  810. // notify that the player is spawning
  811. serverGameClients->ClientSpawned( edict );
  812. }
  813. CClientFrame *CGameClient::GetDeltaFrame( int nTick )
  814. {
  815. #ifndef _XBOX
  816. Assert ( !IsHLTV() ); // has no ClientFrames
  817. #if defined( REPLAY_ENABLED )
  818. Assert ( !IsReplay() ); // has no ClientFrames
  819. #endif
  820. #endif
  821. if ( m_bIsInReplayMode )
  822. {
  823. int followEntity;
  824. serverGameClients->GetReplayDelay( edict, followEntity );
  825. Assert( followEntity > 0 );
  826. CGameClient *pFollowEntity = sv.Client( followEntity-1 );
  827. if ( pFollowEntity )
  828. return pFollowEntity->GetClientFrame( nTick );
  829. }
  830. return GetClientFrame( nTick );
  831. }
  832. void CGameClient::WriteViewAngleUpdate()
  833. {
  834. //
  835. // send the current viewpos offset from the view entity
  836. //
  837. // a fixangle might get lost in a dropped packet. Oh well.
  838. if ( IsFakeClient() )
  839. return;
  840. Assert( serverGameClients );
  841. CPlayerState *pl = serverGameClients->GetPlayerState( edict );
  842. Assert( pl );
  843. if ( pl && pl->fixangle != FIXANGLE_NONE )
  844. {
  845. if ( pl->fixangle == FIXANGLE_RELATIVE )
  846. {
  847. SVC_FixAngle fixAngle( true, pl->anglechange );
  848. m_NetChannel->SendNetMsg( fixAngle );
  849. pl->anglechange.Init(); // clear
  850. }
  851. else
  852. {
  853. SVC_FixAngle fixAngle(false, pl->v_angle );
  854. m_NetChannel->SendNetMsg( fixAngle );
  855. }
  856. pl->fixangle = FIXANGLE_NONE;
  857. }
  858. }
  859. /*
  860. ===================
  861. SV_ValidateClientCommand
  862. Determine if passed in user command is valid.
  863. ===================
  864. */
  865. bool CGameClient::IsEngineClientCommand( const CCommand &args ) const
  866. {
  867. if ( args.ArgC() == 0 )
  868. return false;
  869. for ( int i = 0; s_clcommands[i] != NULL; ++i )
  870. {
  871. if ( !Q_strcasecmp( args[0], s_clcommands[i] ) )
  872. return true;
  873. }
  874. return false;
  875. }
  876. bool CGameClient::SendNetMsg(INetMessage &msg, bool bForceReliable)
  877. {
  878. #ifndef _XBOX
  879. if ( m_bIsHLTV )
  880. {
  881. // pass this message to HLTV
  882. return hltv->SendNetMsg( msg, bForceReliable );
  883. }
  884. #if defined( REPLAY_ENABLED )
  885. if ( m_bIsReplay )
  886. {
  887. // pass this message to replay
  888. return replay->SendNetMsg( msg, bForceReliable );
  889. }
  890. #endif
  891. #endif
  892. return CBaseClient::SendNetMsg( msg, bForceReliable);
  893. }
  894. bool CGameClient::ExecuteStringCommand( const char *pCommandString )
  895. {
  896. // first let the baseclass handle it
  897. if ( CBaseClient::ExecuteStringCommand( pCommandString ) )
  898. return true;
  899. // Determine whether the command is appropriate
  900. CCommand args;
  901. if ( !args.Tokenize( pCommandString ) )
  902. return false;
  903. if ( args.ArgC() == 0 )
  904. return false;
  905. if ( IsEngineClientCommand( args ) )
  906. {
  907. Cmd_ExecuteCommand( args, src_client, m_nClientSlot );
  908. return true;
  909. }
  910. const ConCommandBase *pCommand = g_pCVar->FindCommandBase( args[ 0 ] );
  911. if ( pCommand && pCommand->IsCommand() && pCommand->IsFlagSet( FCVAR_GAMEDLL ) )
  912. {
  913. // Allow cheat commands in singleplayer, debug, or multiplayer with sv_cheats on
  914. // NOTE: Don't bother with rpt stuff; commands that matter there shouldn't have FCVAR_GAMEDLL set
  915. if ( pCommand->IsFlagSet( FCVAR_CHEAT ) )
  916. {
  917. if ( sv.IsMultiplayer() && !CanCheat() )
  918. return false;
  919. }
  920. if ( pCommand->IsFlagSet( FCVAR_SPONLY ) )
  921. {
  922. if ( sv.IsMultiplayer() )
  923. {
  924. return false;
  925. }
  926. }
  927. // Don't allow clients to execute commands marked as development only.
  928. if ( pCommand->IsFlagSet( FCVAR_DEVELOPMENTONLY ) )
  929. {
  930. return false;
  931. }
  932. g_pServerPluginHandler->SetCommandClient( m_nClientSlot );
  933. Cmd_Dispatch( pCommand, args );
  934. }
  935. else
  936. {
  937. g_pServerPluginHandler->ClientCommand( edict, args ); // TODO pass client id and string
  938. }
  939. return true;
  940. }
  941. void CGameClient::SendSnapshot( CClientFrame * pFrame )
  942. {
  943. if ( m_bIsHLTV )
  944. {
  945. #ifndef SHARED_NET_STRING_TABLES
  946. // copy string updates from server to hltv stringtable
  947. networkStringTableContainerServer->DirectUpdate( GetMaxAckTickCount() );
  948. #endif
  949. char *buf = (char *)_alloca( NET_MAX_PAYLOAD );
  950. // pack sounds to one message
  951. if ( m_Sounds.Count() > 0 )
  952. {
  953. SVC_Sounds sounds;
  954. sounds.m_DataOut.StartWriting( buf, NET_MAX_PAYLOAD );
  955. FillSoundsMessage( sounds );
  956. hltv->SendNetMsg( sounds );
  957. }
  958. int maxEnts = tv_transmitall.GetBool()?255:64;
  959. hltv->WriteTempEntities( this, pFrame->GetSnapshot(), m_pLastSnapshot.GetObject(), *hltv->GetBuffer( HLTV_BUFFER_TEMPENTS ), maxEnts );
  960. // add snapshot to HLTV server frame list
  961. hltv->AddNewFrame( pFrame );
  962. // remember this snapshot
  963. m_pLastSnapshot = pFrame->GetSnapshot();
  964. // fake acknowledgement, remove ClientFrame reference immediately
  965. UpdateAcknowledgedFramecount( pFrame->tick_count );
  966. return;
  967. }
  968. #if defined( REPLAY_ENABLED )
  969. if ( m_bIsReplay )
  970. {
  971. #ifndef SHARED_NET_STRING_TABLES
  972. // copy string updates from server to replay stringtable
  973. networkStringTableContainerServer->DirectUpdate( GetMaxAckTickCount() );
  974. #endif
  975. char *buf = (char *)_alloca( NET_MAX_PAYLOAD );
  976. // pack sounds to one message
  977. if ( m_Sounds.Count() > 0 )
  978. {
  979. SVC_Sounds sounds;
  980. sounds.m_DataOut.StartWriting( buf, NET_MAX_PAYLOAD );
  981. FillSoundsMessage( sounds );
  982. replay->SendNetMsg( sounds );
  983. }
  984. int maxEnts = 255;
  985. replay->WriteTempEntities( this, pFrame->GetSnapshot(), m_pLastSnapshot.GetObject(), *replay->GetBuffer( REPLAY_BUFFER_TEMPENTS ), maxEnts );
  986. // add snapshot to Replay server frame list
  987. if ( replay->AddNewFrame( pFrame ) )
  988. {
  989. // remember this snapshot
  990. m_pLastSnapshot = pFrame->GetSnapshot();
  991. // fake acknowledgement, remove ClientFrame reference immediately
  992. UpdateAcknowledgedFramecount( pFrame->tick_count );
  993. }
  994. return;
  995. }
  996. #endif
  997. // update client viewangles update
  998. WriteViewAngleUpdate();
  999. CBaseClient::SendSnapshot( pFrame );
  1000. }
  1001. //-----------------------------------------------------------------------------
  1002. // This function contains all the logic to determine if we should send a datagram
  1003. // to a particular client
  1004. //-----------------------------------------------------------------------------
  1005. bool CGameClient::ShouldSendMessages( void )
  1006. {
  1007. #ifndef _XBOX
  1008. if ( m_bIsHLTV )
  1009. {
  1010. // calc snapshot interval
  1011. int nSnapshotInterval = 1.0f / ( m_Server->GetTickInterval() * tv_snapshotrate.GetFloat() );
  1012. // I am the HLTV client, record every nSnapshotInterval tick
  1013. return ( sv.m_nTickCount >= (hltv->m_nLastTick + nSnapshotInterval) );
  1014. }
  1015. #if defined( REPLAY_ENABLED )
  1016. if ( m_bIsReplay )
  1017. {
  1018. const float replay_snapshotrate = 16.0f;
  1019. // calc snapshot interval
  1020. int nSnapshotInterval = 1.0f / ( m_Server->GetTickInterval() * replay_snapshotrate );
  1021. // I am the Replay client, record every nSnapshotInterval tick
  1022. return ( sv.m_nTickCount >= (replay->m_nLastTick + nSnapshotInterval) );
  1023. }
  1024. #endif
  1025. #endif
  1026. // If sv_stressbots is true, then treat a bot more like a regular client and do deltas and such for it.
  1027. if( IsFakeClient() )
  1028. {
  1029. if ( !sv_stressbots.GetBool() )
  1030. return false;
  1031. }
  1032. return CBaseClient::ShouldSendMessages();
  1033. }
  1034. void CGameClient::FileReceived( const char *fileName, unsigned int transferID )
  1035. {
  1036. //check if file is one of our requested custom files
  1037. for ( int i=0; i<MAX_CUSTOM_FILES; i++ )
  1038. {
  1039. if ( m_nCustomFiles[i].reqID == transferID )
  1040. {
  1041. m_nFilesDownloaded++;
  1042. // broadcast update to other clients so they start downlaoding this file
  1043. m_Server->UserInfoChanged( m_nClientSlot );
  1044. return;
  1045. }
  1046. }
  1047. Msg( "CGameClient::FileReceived: %s not wanted.\n", fileName );
  1048. }
  1049. void CGameClient::FileRequested(const char *fileName, unsigned int transferID )
  1050. {
  1051. DevMsg( "File '%s' requested from client %s.\n", fileName, m_NetChannel->GetAddress() );
  1052. if ( sv_allowdownload.GetBool() )
  1053. {
  1054. m_NetChannel->SendFile( fileName, transferID );
  1055. }
  1056. else
  1057. {
  1058. m_NetChannel->DenyFile( fileName, transferID );
  1059. }
  1060. }
  1061. void CGameClient::FileDenied(const char *fileName, unsigned int transferID )
  1062. {
  1063. ConMsg( "Downloading file '%s' from client %s failed.\n", fileName, GetClientName() );
  1064. }
  1065. void CGameClient::FileSent( const char *fileName, unsigned int transferID )
  1066. {
  1067. ConMsg( "Sent file '%s' to client %s.\n", fileName, GetClientName() );
  1068. }
  1069. void CGameClient::PacketStart(int incoming_sequence, int outgoing_acknowledged)
  1070. {
  1071. // make sure m_LastMovementTick != sv.tickcount
  1072. m_LastMovementTick = ( sv.m_nTickCount - 1 );
  1073. host_client = this;
  1074. // During connection, only respond if client sends a packet
  1075. m_bReceivedPacket = true;
  1076. }
  1077. void CGameClient::PacketEnd()
  1078. {
  1079. // Fix up clock in case prediction/etc. code reset it.
  1080. g_ServerGlobalVariables.frametime = host_state.interval_per_tick;
  1081. }
  1082. void CGameClient::ConnectionClosing(const char *reason)
  1083. {
  1084. #ifndef _XBOX
  1085. SV_RedirectEnd ();
  1086. #endif
  1087. // Check for printf format tokens in this reason string. Crash exploit.
  1088. Disconnect ( (reason && !strchr( reason, '%' ) ) ? reason : "Connection closing" );
  1089. }
  1090. void CGameClient::ConnectionCrashed(const char *reason)
  1091. {
  1092. if ( m_Name[0] && IsConnected() )
  1093. {
  1094. DebuggerBreakIfDebugging_StagingOnly();
  1095. #ifndef _XBOX
  1096. SV_RedirectEnd ();
  1097. #endif
  1098. // Check for printf format tokens in this reason string. Crash exploit.
  1099. Disconnect ( (reason && !strchr( reason, '%' ) ) ? reason : "Connection lost" );
  1100. }
  1101. }
  1102. CClientFrame *CGameClient::GetSendFrame()
  1103. {
  1104. CClientFrame *pFrame = m_pCurrentFrame;
  1105. // just return if replay is disabled
  1106. if ( sv_maxreplay.GetFloat() <= 0 )
  1107. return pFrame;
  1108. int followEntity;
  1109. int delayTicks = serverGameClients->GetReplayDelay( edict, followEntity );
  1110. bool isInReplayMode = ( delayTicks > 0 );
  1111. if ( isInReplayMode != m_bIsInReplayMode )
  1112. {
  1113. // force a full update when modes are switched
  1114. m_nDeltaTick = -1;
  1115. m_bIsInReplayMode = isInReplayMode;
  1116. if ( isInReplayMode )
  1117. {
  1118. m_nEntityIndex = followEntity;
  1119. }
  1120. else
  1121. {
  1122. m_nEntityIndex = m_nClientSlot+1;
  1123. }
  1124. }
  1125. Assert( (m_nClientSlot+1 == m_nEntityIndex) || isInReplayMode );
  1126. if ( isInReplayMode )
  1127. {
  1128. CGameClient *pFollowPlayer = sv.Client( followEntity-1 );
  1129. if ( !pFollowPlayer )
  1130. return NULL;
  1131. pFrame = pFollowPlayer->GetClientFrame( sv.GetTick() - delayTicks, false );
  1132. if ( !pFrame )
  1133. return NULL;
  1134. if ( m_pLastSnapshot == pFrame->GetSnapshot() )
  1135. return NULL;
  1136. }
  1137. return pFrame;
  1138. }
  1139. bool CGameClient::IgnoreTempEntity( CEventInfo *event )
  1140. {
  1141. // in replay mode replay all temp entities
  1142. if ( m_bIsInReplayMode )
  1143. return false;
  1144. return CBaseClient::IgnoreTempEntity( event );
  1145. }
  1146. const CCheckTransmitInfo* CGameClient::GetPrevPackInfo()
  1147. {
  1148. return &m_PrevPackInfo;
  1149. }
  1150. // This code is useful for verifying that the networking of soundinfo_t stuff isn't borked.
  1151. #if 0
  1152. #include "vstdlib/random.h"
  1153. class CTestSoundInfoNetworking
  1154. {
  1155. public:
  1156. CTestSoundInfoNetworking();
  1157. void RunTest();
  1158. private:
  1159. void CreateRandomSounds( int nCount );
  1160. void CreateRandomSound( SoundInfo_t &si );
  1161. void Compare( const SoundInfo_t &s1, const SoundInfo_t &s2 );
  1162. CUtlVector< SoundInfo_t > m_Sounds;
  1163. CUtlVector< SoundInfo_t > m_Received;
  1164. };
  1165. static CTestSoundInfoNetworking g_SoundTest;
  1166. CON_COMMAND( st, "sound test" )
  1167. {
  1168. int nCount = 1;
  1169. if ( args.ArgC() >= 2 )
  1170. {
  1171. nCount = clamp( Q_atoi( args.Arg( 1 ) ), 1, 100000 );
  1172. }
  1173. for ( int i = 0 ; i < nCount; ++i )
  1174. {
  1175. if ( !( i % 100 ) && i > 0 )
  1176. {
  1177. Msg( "Running test %d %f %% done\n",
  1178. i, 100.0f * (float)i/(float)nCount );
  1179. }
  1180. g_SoundTest.RunTest();
  1181. }
  1182. }
  1183. CTestSoundInfoNetworking::CTestSoundInfoNetworking()
  1184. {
  1185. }
  1186. void CTestSoundInfoNetworking::CreateRandomSound( SoundInfo_t &si )
  1187. {
  1188. int entindex = RandomInt( 0, MAX_EDICTS - 1 );
  1189. int channel = RandomInt( 0, 7 );
  1190. int soundnum = RandomInt( 0, MAX_SOUNDS - 1 );
  1191. Vector org = RandomVector( -16383, 16383 );
  1192. Vector dir = RandomVector( -1.0f, 1.0f );
  1193. float flVolume = RandomFloat( 0.1f, 1.0f );
  1194. bool bLooping = RandomInt( 0, 100 ) < 5;
  1195. int nPitch = RandomInt( 0, 100 ) < 5 ? RandomInt( 95, 105 ) : 100;
  1196. Vector lo = RandomInt( 0, 100 ) < 5 ? RandomVector( -16383, 16383 ) : org;
  1197. int speaker = RandomInt( 0, 100 ) < 2 ? RandomInt( 0, MAX_EDICTS - 1 ) : -1;
  1198. soundlevel_t level = soundlevel_t(RandomInt( 70, 150 ));
  1199. si.Set( entindex, channel, "foo.wav", org, dir, flVolume, level, bLooping, nPitch, lo, speaker );
  1200. si.nFlags = ( 1 << RandomInt( 0, 6 ) );
  1201. si.nSoundNum = soundnum;
  1202. si.bIsSentence = RandomInt( 0, 1 );
  1203. si.bIsAmbient = RandomInt( 0, 1 );
  1204. si.fDelay = RandomInt( 0, 100 ) < 2 ? RandomFloat( -0.1, 0.1f ) : 0.0f;
  1205. }
  1206. void CTestSoundInfoNetworking::CreateRandomSounds( int nCount )
  1207. {
  1208. m_Sounds.Purge();
  1209. m_Sounds.EnsureCount( nCount );
  1210. for ( int i = 0; i < nCount; ++i )
  1211. {
  1212. SoundInfo_t &si = m_Sounds[ i ];
  1213. CreateRandomSound( si );
  1214. }
  1215. }
  1216. void CTestSoundInfoNetworking::RunTest()
  1217. {
  1218. int m_nSoundSequence = 0;
  1219. CreateRandomSounds( 512 );
  1220. SoundInfo_t defaultSound; defaultSound.SetDefault();
  1221. SoundInfo_t *pDeltaSound = &defaultSound;
  1222. SVC_Sounds msg;
  1223. char *buf = (char *)_alloca( NET_MAX_PAYLOAD );
  1224. msg.m_DataOut.StartWriting( buf, NET_MAX_PAYLOAD );
  1225. msg.m_nNumSounds = m_Sounds.Count();
  1226. msg.m_bReliableSound = false;
  1227. msg.SetReliable( false );
  1228. Assert( msg.m_DataOut.GetNumBitsLeft() > 0 );
  1229. for ( int i = 0 ; i < m_Sounds.Count(); i++ )
  1230. {
  1231. SoundInfo_t &sound = m_Sounds[ i ];
  1232. sound.WriteDelta( pDeltaSound, msg.m_DataOut );
  1233. pDeltaSound = &m_Sounds[ i ];
  1234. }
  1235. // Now read them out
  1236. defaultSound.SetDefault();
  1237. pDeltaSound = &defaultSound;
  1238. msg.m_DataIn.StartReading( buf, msg.m_DataOut.GetNumBytesWritten(), 0, msg.m_DataOut.GetNumBitsWritten() );
  1239. SoundInfo_t sound;
  1240. for ( int i=0; i<msg.m_nNumSounds; i++ )
  1241. {
  1242. sound.ReadDelta( pDeltaSound, msg.m_DataIn );
  1243. pDeltaSound = &sound; // copy delta values
  1244. if ( msg.m_bReliableSound )
  1245. {
  1246. // client is incrementing the reliable sequence numbers itself
  1247. m_nSoundSequence = ( m_nSoundSequence + 1 ) & SOUND_SEQNUMBER_MASK;
  1248. Assert ( sound.nSequenceNumber == 0 );
  1249. sound.nSequenceNumber = m_nSoundSequence;
  1250. }
  1251. // Add no ambient sounds to sorted queue, will be processed after packet has been completly parsed
  1252. // CL_AddSound( sound );
  1253. m_Received.AddToTail( sound );
  1254. }
  1255. // Now validate them
  1256. for ( int i = 0 ; i < msg.m_nNumSounds; ++i )
  1257. {
  1258. SoundInfo_t &server = m_Sounds[ i ];
  1259. SoundInfo_t &client = m_Received[ i ];
  1260. Compare( server, client );
  1261. }
  1262. m_Sounds.Purge();
  1263. m_Received.Purge();
  1264. }
  1265. void CTestSoundInfoNetworking::Compare( const SoundInfo_t &s1, const SoundInfo_t &s2 )
  1266. {
  1267. bool bSndStop = s2.nFlags == SND_STOP;
  1268. if ( !bSndStop && s1.nSequenceNumber != s2.nSequenceNumber )
  1269. {
  1270. Msg( "seq number mismatch %d %d\n", s1.nSequenceNumber, s2.nSequenceNumber );
  1271. }
  1272. if ( s1.nEntityIndex != s2.nEntityIndex )
  1273. {
  1274. Msg( "ent mismatch %d %d\n", s1.nEntityIndex, s2.nEntityIndex );
  1275. }
  1276. if ( s1.nChannel != s2.nChannel )
  1277. {
  1278. Msg( "channel mismatch %d %d\n", s1.nChannel, s2.nChannel );
  1279. }
  1280. Vector d;
  1281. d = s1.vOrigin - s2.vOrigin;
  1282. if ( !bSndStop && d.Length() > 32.0f )
  1283. {
  1284. Msg( "origin mismatch [%f] (%f %f %f) != (%f %f %f)\n", d.Length(), s1.vOrigin.x, s1.vOrigin.y, s1.vOrigin.z, s2.vOrigin.x, s2.vOrigin.y, s2.vOrigin.z );
  1285. }
  1286. // Vector vDirection;
  1287. float delta = fabs( s1.fVolume - s2.fVolume );
  1288. if ( !bSndStop && delta > 1.0f )
  1289. {
  1290. Msg( "vol mismatch %f %f\n", s1.fVolume, s2.fVolume );
  1291. }
  1292. if ( !bSndStop && s1.Soundlevel != s2.Soundlevel )
  1293. {
  1294. Msg( "sndlvl mismatch %d %d\n", s1.Soundlevel, s2.Soundlevel );
  1295. }
  1296. // bLooping;
  1297. if ( s1.bIsSentence != s2.bIsSentence )
  1298. {
  1299. Msg( "sentence mismatch %d %d\n", s1.bIsSentence ? 1 : 0, s2.bIsSentence ? 1 : 0 );
  1300. }
  1301. if ( s1.bIsAmbient != s2.bIsAmbient )
  1302. {
  1303. Msg( "ambient mismatch %d %d\n", s1.bIsAmbient ? 1 : 0, s2.bIsAmbient ? 1 : 0 );
  1304. }
  1305. if ( !bSndStop && s1.nPitch != s2.nPitch )
  1306. {
  1307. Msg( "pitch mismatch %d %d\n", s1.nPitch, s2.nPitch );
  1308. }
  1309. if ( !bSndStop && s1.nSpecialDSP != s2.nSpecialDSP )
  1310. {
  1311. Msg( "special dsp mismatch %d %d\n", s1.nSpecialDSP, s2.nSpecialDSP );
  1312. }
  1313. // Vector vListenerOrigin;
  1314. if ( s1.nFlags != s2.nFlags )
  1315. {
  1316. Msg( "flags mismatch %d %d\n", s1.nFlags, s2.nFlags );
  1317. }
  1318. if ( s1.nSoundNum != s2.nSoundNum )
  1319. {
  1320. Msg( "soundnum mismatch %d %d\n", s1.nSoundNum, s2.nSoundNum );
  1321. }
  1322. delta = fabs( s1.fDelay - s2.fDelay );
  1323. if ( !bSndStop && delta > 0.020f )
  1324. {
  1325. Msg( "delay mismatch %f %f\n", s1.fDelay, s2.fDelay );
  1326. }
  1327. if ( !bSndStop && s1.nSpeakerEntity != s2.nSpeakerEntity )
  1328. {
  1329. Msg( "speakerentity mismatch %d %d\n", s1.nSpeakerEntity, s2.nSpeakerEntity );
  1330. }
  1331. }
  1332. #endif