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

2292 lines
61 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: baseclient.cpp: implementation of the CBaseClient class.
  4. //
  5. //===========================================================================//
  6. #include "server_pch.h"
  7. #include "baseclient.h"
  8. #include "server.h"
  9. #include "networkstringtable.h"
  10. #include "framesnapshot.h"
  11. #include "GameEventManager.h"
  12. #include "LocalNetworkBackdoor.h"
  13. #ifndef DEDICATED
  14. #include "vgui_baseui_interface.h"
  15. #endif
  16. #include "sv_remoteaccess.h" // NotifyDedicatedServerUI()
  17. #include "MapReslistGenerator.h"
  18. #include "sv_steamauth.h"
  19. #include "sv_main.h"
  20. #include "host_state.h"
  21. #include "net_chan.h"
  22. #include "hltvserver.h"
  23. #include "icliententity.h"
  24. #include "matchmaking/imatchframework.h"
  25. #include "tier2/tier2.h"
  26. #include "tier0/etwprof.h"
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. extern IServerGameDLL *serverGameDLL;
  30. ConVar sv_reliableavatardata( "sv_reliableavatardata", "0", FCVAR_REPLICATED | FCVAR_RELEASE, "When enabled player avatars are exchanged via gameserver (0: off, 1: players, 2: server)" );
  31. ConVar sv_duplicate_playernames_ok( "sv_duplicate_playernames_ok", "0", FCVAR_REPLICATED | FCVAR_RELEASE, "When enabled player names won't have the (#) in front of their names its the same as another player." );
  32. //////////////////////////////////////////////////////////////////////
  33. // Construction/Destruction
  34. //////////////////////////////////////////////////////////////////////
  35. CBaseClient::CBaseClient()
  36. {
  37. // init all pointers
  38. m_NetChannel = NULL;
  39. m_ConVars = NULL;
  40. m_Server = NULL;
  41. m_pBaseline = NULL;
  42. m_bIsHLTV = false;
  43. m_pHltvSlaveServer = NULL;
  44. #if defined( REPLAY_ENABLED )
  45. m_bIsReplay = false;
  46. #endif
  47. m_bConVarsChanged = false;
  48. m_bSendServerInfo = false;
  49. m_bFullyAuthenticated = false;
  50. m_nSignonState = SIGNONSTATE_NONE;
  51. m_bSplitScreenUser = false;
  52. m_bSplitAllowFastDisconnect = false;
  53. m_bSplitPlayerDisconnecting = false;
  54. m_nSplitScreenPlayerSlot = 0;
  55. m_pAttachedTo = NULL;
  56. Q_memset( m_SplitScreenUsers, 0, sizeof( m_SplitScreenUsers ) );
  57. m_SplitScreenUsers[ 0 ] = this;
  58. m_ClientPlatform = CROSSPLAYPLATFORM_THISPLATFORM;
  59. m_nDebugID = EVENT_DEBUG_ID_INIT;
  60. }
  61. CBaseClient::~CBaseClient()
  62. {
  63. // first remove the client as listener
  64. g_GameEventManager.RemoveListener( this );
  65. m_nDebugID = EVENT_DEBUG_ID_SHUTDOWN;
  66. }
  67. void CBaseClient::SetRate(int nRate, bool bForce )
  68. {
  69. if ( m_NetChannel )
  70. m_NetChannel->SetDataRate( nRate );
  71. }
  72. int CBaseClient::GetRate( void ) const
  73. {
  74. if ( m_NetChannel )
  75. {
  76. return m_NetChannel->GetDataRate();
  77. }
  78. else
  79. {
  80. return 0;
  81. }
  82. }
  83. bool CBaseClient::FillUserInfo( player_info_s &userInfo )
  84. {
  85. Q_memset( &userInfo, 0, sizeof(userInfo) );
  86. if ( !IsConnected() )
  87. return false; // inactive user, no more data available
  88. userInfo.version = CDLL_PLAYER_INFO_S_VERSION_CURRENT;
  89. Q_strncpy( userInfo.name, GetClientName(), MAX_PLAYER_NAME_LENGTH );
  90. Q_strncpy( userInfo.guid, GetNetworkIDString(), SIGNED_GUID_LEN + 1 );
  91. userInfo.friendsID = m_SteamID.GetAccountID();
  92. userInfo.xuid = GetClientXuid();
  93. Q_strncpy( userInfo.friendsName, m_FriendsName, sizeof(m_FriendsName) );
  94. userInfo.userID = GetUserID();
  95. userInfo.fakeplayer = ( IsFakeClient() && !IsSplitScreenUser() );
  96. userInfo.ishltv = IsHLTV();
  97. #if defined( REPLAY_ENABLED )
  98. userInfo.isreplay = IsReplay();
  99. #endif
  100. for( int i=0; i< MAX_CUSTOM_FILES; i++ )
  101. userInfo.customFiles[i] = m_nCustomFiles[i].crc;
  102. userInfo.filesDownloaded = m_nFilesDownloaded;
  103. return true;
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Send text to client
  107. // Input : *fmt -
  108. // ... -
  109. //-----------------------------------------------------------------------------
  110. void CBaseClient::ClientPrintf (const char *fmt, ...)
  111. {
  112. va_list argptr;
  113. char string[1024];
  114. va_start (argptr,fmt);
  115. Q_vsnprintf (string, sizeof( string ), fmt,argptr);
  116. va_end (argptr);
  117. CSVCMsg_Print_t print;
  118. print.set_text( string );
  119. SendNetMsg( print, print.IsReliable(), false );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Send text to client
  123. // Input : *fmt -
  124. // ... -
  125. //-----------------------------------------------------------------------------
  126. bool CBaseClient::SendNetMsg( INetMessage &msg, bool bForceReliable, bool bVoice )
  127. {
  128. if ( !m_NetChannel )
  129. {
  130. return true;
  131. }
  132. //
  133. // Send the actual message that was passed
  134. //
  135. int nStartBit = m_NetChannel->GetNumBitsWritten( msg.IsReliable() || bForceReliable );
  136. bool bret = m_NetChannel->SendNetMsg( msg, bForceReliable, bVoice );
  137. if ( IsTracing() )
  138. {
  139. int nBits = m_NetChannel->GetNumBitsWritten( msg.IsReliable() || bForceReliable ) - nStartBit;
  140. TraceNetworkMsg( nBits, "NetMessage %s", msg.ToString() );
  141. }
  142. return bret;
  143. }
  144. CHLTVServer * CBaseClient::GetHltvServer()
  145. {
  146. if ( m_Server->IsHLTV() )
  147. return static_cast< CHLTVServer* >( m_Server );
  148. else
  149. {
  150. Assert( !m_bIsHLTV || m_pHltvSlaveServer ); // if we have m_bIsHLTV mark, it means we connect to HLTV data source, either as a client listening to the HLTV port, or as a master client of HLTV Slave server. We can't be m_bIsHLTV and not be connected to any HLTV server from any end
  151. return NULL;
  152. }
  153. }
  154. CHLTVServer * CBaseClient::GetAnyConnectedHltvServer()
  155. {
  156. if ( m_pHltvSlaveServer )
  157. {
  158. Assert( !m_Server->IsHLTV() ); // we shouldn't cascade hltv->hltv within the same process
  159. return m_pHltvSlaveServer;
  160. }
  161. else
  162. {
  163. return GetHltvServer();
  164. }
  165. }
  166. char const *CBaseClient::GetUserSetting( char const *cvar ) const
  167. {
  168. if ( !m_ConVars || !cvar || !cvar[0] )
  169. {
  170. return "";
  171. }
  172. const char * value = m_ConVars->GetString( cvar, "" );
  173. if ( value[0]==0 )
  174. {
  175. // For non FCVAR_SS fields, defer to the player 0 value
  176. if ( m_bSplitScreenUser )
  177. {
  178. return m_pAttachedTo->GetUserSetting( cvar );
  179. }
  180. // // check if this var even existed
  181. // if ( m_ConVars->GetDataType( cvar ) == KeyValues::TYPE_NONE )
  182. // {
  183. // DevMsg( "GetUserSetting: cvar '%s' unknown.\n", cvar );
  184. // }
  185. }
  186. return value;
  187. }
  188. void CBaseClient::SetUserCVar( const char *cvar, const char *value)
  189. {
  190. if ( !cvar || !value )
  191. return;
  192. m_ConVars->SetString( cvar, value );
  193. }
  194. void CBaseClient::SetUpdateRate( float fUpdateRate, bool bForce)
  195. {
  196. fUpdateRate = clamp( fUpdateRate, 1, 128.0f );
  197. m_fSnapshotInterval = 1.0f / fUpdateRate;
  198. }
  199. float CBaseClient::GetUpdateRate(void) const
  200. {
  201. if ( m_fSnapshotInterval > 0 )
  202. return 1.0f / m_fSnapshotInterval;
  203. else
  204. return 0.0f;
  205. }
  206. void CBaseClient::FreeBaselines()
  207. {
  208. if ( m_pBaseline )
  209. {
  210. m_pBaseline->ReleaseReference();
  211. m_pBaseline = NULL;
  212. }
  213. m_nBaselineUpdateTick = -1;
  214. m_nBaselineUsed = 0;
  215. m_BaselinesSent.ClearAll();
  216. }
  217. void CBaseClient::SetSignonState( int nState )
  218. {
  219. bool bOldIsConnected = IsConnected();
  220. m_nSignonState = nState;
  221. bool bNewIsConnected = IsConnected();
  222. if ( ( bOldIsConnected != bNewIsConnected ) && ( !IsFakeClient() || IsSplitScreenUser() ) )
  223. { // SetSignonState can be called in the callstack of an existing client
  224. // and we don't want to trigger full hibernation and cause all clients
  225. // to disconnect as a result, and come back into a callstack with a bad "this" CBaseClient pointer.
  226. // So we just defer hibernation update till next SV_Think frame
  227. // ( Also note that disconnecting GOTV clients can trigger a hibernation update on the main game server )
  228. sv.UpdateHibernationStateDeferred();
  229. }
  230. }
  231. void CBaseClient::Clear()
  232. {
  233. // Throw away any residual garbage in the channel.
  234. if ( m_NetChannel )
  235. {
  236. m_NetChannel->Shutdown("Disconnect by server.\n");
  237. m_NetChannel = NULL;
  238. }
  239. if ( m_ConVars )
  240. {
  241. m_ConVars->deleteThis();
  242. m_ConVars = NULL;
  243. }
  244. FreeBaselines();
  245. // This used to be a memset, but memset will screw up any embedded classes
  246. // and we want to preserve some things like index.
  247. SetSignonState( SIGNONSTATE_NONE );
  248. m_nDeltaTick = -1;
  249. m_nSignonTick = 0;
  250. m_nStringTableAckTick = 0;
  251. m_pLastSnapshot = NULL;
  252. m_nForceWaitForTick = -1;
  253. m_bFakePlayer = false;
  254. m_bLowViolence = false;
  255. m_bSplitScreenUser = false;
  256. m_bSplitAllowFastDisconnect = false;
  257. m_bSplitPlayerDisconnecting = false;
  258. m_nSplitScreenPlayerSlot = 0;
  259. m_pAttachedTo = NULL;
  260. m_bIsHLTV = false;
  261. //???TODO: do we need to disconnect slave hltv server?
  262. //m_pHltvSlaveServer = NULL;
  263. #if defined( REPLAY_ENABLED )
  264. m_bIsReplay = false;
  265. #endif
  266. m_fNextMessageTime = 0;
  267. m_fSnapshotInterval = 0;
  268. m_bReceivedPacket = false;
  269. m_UserID = 0;
  270. m_Name[0] = 0;
  271. strcpy(m_Name, "EMPTY");
  272. m_FriendsName[0] = 0;
  273. m_nSendtableCRC = 0;
  274. m_nBaselineUpdateTick = -1;
  275. m_nBaselineUsed = 0;
  276. m_nFilesDownloaded = 0;
  277. m_bConVarsChanged = false;
  278. m_bSendServerInfo = false;
  279. m_nLoadingProgress = 0;
  280. m_bFullyAuthenticated = false;
  281. m_ClientPlatform = CROSSPLAYPLATFORM_THISPLATFORM;
  282. m_msgAvatarData.Clear();
  283. Q_memset( m_nCustomFiles, 0, sizeof(m_nCustomFiles) );
  284. }
  285. bool CBaseClient::ProcessSignonStateMsg(int state, int spawncount)
  286. {
  287. if ( IsSplitScreenUser() )
  288. return true;
  289. COM_TimestampedLog( "CBaseClient::ProcessSignonStateMsg: %s : %d", GetClientName(), GetSignonState() );
  290. MDLCACHE_COARSE_LOCK_(g_pMDLCache);
  291. switch( GetSignonState() )
  292. {
  293. case SIGNONSTATE_CONNECTED : // client is connected, leave client in this state and let SendPendingSignonData do the rest
  294. m_bSendServerInfo = true;
  295. break;
  296. case SIGNONSTATE_NEW : // client got server info, send prespawn datam_Client->SendServerInfo()
  297. if ( !SendSignonData() )
  298. return false;
  299. break;
  300. case SIGNONSTATE_PRESPAWN : SpawnPlayer();
  301. break;
  302. case SIGNONSTATE_SPAWN : {
  303. for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
  304. {
  305. if ( m_SplitScreenUsers[ i ] )
  306. {
  307. m_SplitScreenUsers[ i ]->ActivatePlayer();
  308. }
  309. }
  310. }
  311. break;
  312. case SIGNONSTATE_FULL : {
  313. for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
  314. {
  315. if ( m_SplitScreenUsers[ i ] )
  316. {
  317. m_SplitScreenUsers[ i ]->SendFullConnectEvent();
  318. }
  319. }
  320. // My net channel
  321. INetChannel *pMyNetChannel = GetNetChannel();
  322. // Force load known avatars for the users when they fully connect
  323. if ( ( GetServer() == &sv ) &&
  324. ( sv_reliableavatardata.GetInt() == 2 ) &&
  325. !this->IsFakeClient() && !this->IsHLTV() &&
  326. m_SteamID.IsValid() )
  327. {
  328. //
  329. // Try to load the avatar data for this player
  330. //
  331. CUtlBuffer bufAvatarData;
  332. CUtlBuffer bufAvatarDataDefault;
  333. CUtlBuffer *pbufUseRgb = NULL;
  334. if ( !pbufUseRgb &&
  335. g_pFullFileSystem->ReadFile( CFmtStr( "avatars/%llu.rgb", m_SteamID.ConvertToUint64() ), "MOD", bufAvatarData ) &&
  336. ( bufAvatarData.TellPut() == 64*64*3 ) )
  337. pbufUseRgb = &bufAvatarData;
  338. if ( !pbufUseRgb &&
  339. g_pFullFileSystem->ReadFile( "avatars/default.rgb", "MOD", bufAvatarDataDefault ) &&
  340. ( bufAvatarDataDefault.TellPut() == 64 * 64 * 3 ) )
  341. pbufUseRgb = &bufAvatarDataDefault;
  342. if ( pbufUseRgb )
  343. {
  344. m_msgAvatarData.set_rgb( pbufUseRgb->Base(), pbufUseRgb->TellPut() );
  345. m_msgAvatarData.set_accountid( m_SteamID.GetAccountID() );
  346. OnPlayerAvatarDataChanged();
  347. // Since we are forcing this avatar inform the user about it
  348. if ( pMyNetChannel )
  349. pMyNetChannel->EnqueueVeryLargeAsyncTransfer( m_msgAvatarData );
  350. }
  351. }
  352. // Also broadcast to this user all avatars that we have from other players!
  353. if ( ( GetServer() == &sv ) && pMyNetChannel )
  354. {
  355. // Broadcast to this user avatars of all other users who already uploaded their avatars
  356. for ( int iClient = 0; iClient < sv.GetClientCount(); ++iClient )
  357. {
  358. CBaseClient *pClient = dynamic_cast< CBaseClient * >( sv.GetClient( iClient ) );
  359. if ( !pClient->IsConnected() )
  360. continue;
  361. // In debug build we can set to echo my own avatar back to client
  362. if ( pClient == this )
  363. continue;
  364. if ( pClient->m_msgAvatarData.rgb().size() != 64 * 64 * 3 )
  365. continue;
  366. pMyNetChannel->EnqueueVeryLargeAsyncTransfer( pClient->m_msgAvatarData );
  367. }
  368. }
  369. }
  370. break;
  371. case SIGNONSTATE_CHANGELEVEL: break;
  372. }
  373. return true;
  374. }
  375. void CBaseClient::Reconnect( void )
  376. {
  377. ConMsg("Forcing client reconnect (%i)\n", GetSignonState() );
  378. m_NetChannel->Clear();
  379. SetSignonState( SIGNONSTATE_CONNECTED );
  380. CNETMsg_SignonState_t signon( GetSignonState(), -1 );
  381. FillSignOnFullServerInfo( signon );
  382. m_NetChannel->SendNetMsg( signon );
  383. }
  384. void CBaseClient::Inactivate( void )
  385. {
  386. FreeBaselines();
  387. m_nDeltaTick = -1;
  388. m_nSignonTick = 0;
  389. m_nStringTableAckTick = 0;
  390. m_pLastSnapshot = NULL;
  391. m_nForceWaitForTick = -1;
  392. SetSignonState( SIGNONSTATE_CHANGELEVEL );
  393. if ( m_NetChannel )
  394. {
  395. // don't do that for fakeclients
  396. m_NetChannel->Clear();
  397. if ( NET_IsMultiplayer() && !IsSplitScreenUser() )
  398. {
  399. CNETMsg_SignonState_t signon( GetSignonState(), m_Server->GetSpawnCount() );
  400. FillSignOnFullServerInfo( signon );
  401. SendNetMsg( signon );
  402. // force sending message now
  403. m_NetChannel->Transmit();
  404. }
  405. }
  406. // don't receive event messages anymore
  407. g_GameEventManager.RemoveListener( this );
  408. }
  409. void CBaseClient::SetName(const char * name)
  410. {
  411. if ( StringHasPrefix( name, m_Name ) )
  412. return; // didn't change
  413. int i;
  414. int dupc = 1;
  415. char *p, *val;
  416. char newname[MAX_PLAYER_NAME_LENGTH];
  417. // remove evil char '%'
  418. char *pFrom = (char *)name;
  419. char *pTo = m_Name;
  420. char *pLimit = &m_Name[sizeof(m_Name)-1];
  421. while ( *pFrom && pTo < pLimit )
  422. {
  423. // Don't copy '%' or '~' chars across
  424. // Don't copy '#' chars across if they would go into the first position in the name
  425. if ( *pFrom != '%' &&
  426. *pFrom != '~' &&
  427. ( *pFrom != '#' || pTo != &m_Name[0] ) )
  428. {
  429. *pTo++ = *pFrom;
  430. }
  431. else
  432. {
  433. *pTo++ = '?';
  434. }
  435. pFrom++;
  436. }
  437. *pTo = 0;
  438. if ( Q_strlen( m_Name ) <= 0 )
  439. {
  440. Q_snprintf( m_Name, sizeof(m_Name), "unnamed" );
  441. }
  442. val = m_Name;
  443. // Don't care about duplicate names on the xbox. It can only occur when a player
  444. // is reconnecting after crashing, and we don't want to ever show the (X) then.
  445. // We also don't care for tournaments to use (1) in names since names are baked into the GC schema
  446. // also don't care in coop because bots can have the same names
  447. static char const * s_pchTournamentServer = CommandLine()->ParmValue( "-tournament", ( char const * ) NULL );
  448. if ( !s_pchTournamentServer && !IsX360() && !NET_IsDedicatedForXbox() && !sv_duplicate_playernames_ok.GetBool() )
  449. {
  450. // Check to see if another user by the same name exists
  451. while ( true )
  452. {
  453. for ( i = 0; i < m_Server->GetClientCount(); i++ )
  454. {
  455. IClient *client = m_Server->GetClient( i );
  456. if( !client->IsConnected() || client == this )
  457. continue;
  458. if( !Q_stricmp( client->GetClientName(), val ) )
  459. break;
  460. }
  461. if (i >= m_Server->GetClientCount())
  462. break;
  463. p = val;
  464. if (val[0] == '(')
  465. {
  466. if (val[2] == ')')
  467. {
  468. p = val + 3;
  469. }
  470. else if (val[3] == ')') //assumes max players is < 100
  471. {
  472. p = val + 4;
  473. }
  474. }
  475. Q_snprintf(newname, sizeof(newname), "(%d)%-.*s", dupc++, MAX_PLAYER_NAME_LENGTH - 4, p );
  476. Q_strncpy(m_Name, newname, sizeof(m_Name));
  477. val = m_Name;
  478. }
  479. }
  480. m_ConVars->SetString( "name", m_Name );
  481. m_Server->UserInfoChanged( m_nClientSlot );
  482. }
  483. void CBaseClient::ActivatePlayer()
  484. {
  485. COM_TimestampedLog( "CBaseClient::ActivatePlayer" );
  486. // tell server to update the user info table (if not already done)
  487. m_Server->UserInfoChanged( m_nClientSlot );
  488. SetSignonState( SIGNONSTATE_FULL );
  489. MapReslistGenerator().OnPlayerSpawn();
  490. // update the UI
  491. NotifyDedicatedServerUI("UpdatePlayers");
  492. }
  493. void CBaseClient::SpawnPlayer( void )
  494. {
  495. COM_TimestampedLog( "CBaseClient::SpawnPlayer" );
  496. if ( !IsFakeClient() )
  497. {
  498. // free old baseline snapshot
  499. FreeBaselines();
  500. // create baseline snapshot for real clients
  501. m_pBaseline = framesnapshotmanager->CreateEmptySnapshot(
  502. #ifdef DEBUG_SNAPSHOT_REFERENCES
  503. CFmtStr( "CBaseClient[%d,%s]::SpawnPlayer", m_nClientSlot, GetClientName() ).Access(),
  504. #endif
  505. 0, MAX_EDICTS );
  506. }
  507. // Set client clock to match server's
  508. CNETMsg_Tick_t tick( m_Server->GetTick(), host_frameendtime_computationduration, host_frametime_stddeviation, host_framestarttime_stddeviation );
  509. if ( GetHltvReplayDelay() )
  510. {
  511. tick.set_hltv_replay_flags( 1 );
  512. }
  513. SendNetMsg( tick, true );
  514. // Spawned into server, not fully active, though
  515. SetSignonState( SIGNONSTATE_SPAWN );
  516. CNETMsg_SignonState_t signonState( GetSignonState(), m_Server->GetSpawnCount() );
  517. FillSignOnFullServerInfo( signonState );
  518. SendNetMsg( signonState );
  519. }
  520. bool CBaseClient::SendSignonData( void )
  521. {
  522. COM_TimestampedLog( " CBaseClient::SendSignonData" );
  523. #ifndef DEDICATED
  524. EngineVGui()->UpdateProgressBar(PROGRESS_SENDSIGNONDATA, false );
  525. #endif
  526. if ( m_Server->m_Signon.IsOverflowed() )
  527. {
  528. Host_Error( "Signon buffer overflowed %i bytes!!!\n", m_Server->m_Signon.GetNumBytesWritten() );
  529. return false;
  530. }
  531. m_NetChannel->SendData( m_Server->m_Signon );
  532. #ifndef DEDICATED
  533. S_PreventSound( false ); //it is now safe to use audio again.
  534. #endif
  535. SetSignonState( SIGNONSTATE_PRESPAWN );
  536. CNETMsg_SignonState_t signonState( GetSignonState(), m_Server->GetSpawnCount() );
  537. FillSignOnFullServerInfo( signonState );
  538. return m_NetChannel->SendNetMsg( signonState );
  539. }
  540. void CBaseClient::Connect( const char *szName, int nUserID, INetChannel *pNetChannel, bool bFakePlayer, CrossPlayPlatform_t clientPlatform, const CMsg_CVars *pVecCvars /*= NULL*/ )
  541. {
  542. COM_TimestampedLog( "CBaseClient::Connect" );
  543. #ifndef DEDICATED
  544. if ( !bFakePlayer )
  545. {
  546. EngineVGui()->UpdateProgressBar(PROGRESS_SIGNONCONNECT, false);
  547. }
  548. #endif
  549. Clear();
  550. m_UserID = nUserID;
  551. m_ConVars = new KeyValues("userinfo");
  552. if ( pVecCvars )
  553. {
  554. ApplyConVars( *pVecCvars, true ); // set all initial user info cvars
  555. char const *pchName = GetUserSetting( "name" );
  556. pchName = serverGameClients->ClientNameHandler( m_SteamID.ConvertToUint64(), pchName );
  557. SetName( ( pchName && *pchName ) ? pchName : szName );
  558. }
  559. else
  560. {
  561. szName = serverGameClients->ClientNameHandler( m_SteamID.ConvertToUint64(), szName );
  562. SetName( szName );
  563. }
  564. m_bFakePlayer = bFakePlayer;
  565. if ( bFakePlayer )
  566. {
  567. Steam3Server().NotifyLocalClientConnect( this );
  568. }
  569. m_NetChannel = pNetChannel;
  570. if ( m_NetChannel && m_Server && m_Server->IsMultiplayer() )
  571. {
  572. m_NetChannel->SetCompressionMode( true );
  573. }
  574. m_ClientPlatform = clientPlatform;
  575. SetSignonState( SIGNONSTATE_CONNECTED );
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Purpose: Drops client from server, with explanation
  579. // Input : *cl -
  580. // crash -
  581. // *fmt -
  582. // ... -
  583. //-----------------------------------------------------------------------------
  584. void CBaseClient::PerformDisconnection( const char *pReason )
  585. {
  586. #if !defined( DEDICATED ) && defined( ENABLE_RPT )
  587. SV_NotifyRPTOfDisconnect( m_nClientSlot );
  588. #endif
  589. Steam3Server().NotifyClientDisconnect( this );
  590. SetSignonState( SIGNONSTATE_NONE );
  591. // Make sure the client is valid to be disconnected
  592. // Splitscreen parasites end up disconnecting twice
  593. // sometimes which may cause havoc because
  594. // m_Clients is accessed at the wrong index -- Vitaliy
  595. if ( m_nClientSlot < 0 ||
  596. m_nClientSlot >= m_Server->GetClientCount() ||
  597. m_Server->GetClient( m_nClientSlot ) != ( IClient * ) this )
  598. {
  599. return;
  600. }
  601. m_Server->UserInfoChanged( m_nClientSlot );
  602. // L4D: don't print when bots remove themselves
  603. if ( developer.GetInt() > 1 || !IsFakeClient() || IsSplitScreenUser() )
  604. {
  605. ConMsg("Dropped %s from server: %s\n", GetClientName(), pReason );
  606. }
  607. // remove the client as listener
  608. g_GameEventManager.RemoveListener( this );
  609. if ( m_pAttachedTo && m_pAttachedTo->GetNetChannel() )
  610. {
  611. m_pAttachedTo->GetNetChannel()->DetachSplitPlayer( m_nSplitScreenPlayerSlot );
  612. m_pAttachedTo = NULL;
  613. }
  614. // Send the remaining reliable buffer so the client finds out the server is shutting down.
  615. if ( m_NetChannel )
  616. {
  617. m_NetChannel->Shutdown( pReason );
  618. m_NetChannel = NULL;
  619. }
  620. Clear(); // clear state
  621. }
  622. void CBaseClient::Disconnect( const char *fmt )
  623. {
  624. if ( GetSignonState() == SIGNONSTATE_NONE )
  625. return; // no recursion
  626. // Make sure the client is valid to be disconnected
  627. // During server shutdown splitscreen parasites end up
  628. // disconnecting twice sometimes which may cause havoc because
  629. // m_Clients is accessed at the wrong index -- Vitaliy
  630. if ( m_nClientSlot < 0 ||
  631. m_nClientSlot >= m_Server->GetClientCount() ||
  632. m_Server->GetClient( m_nClientSlot ) != ( IClient * ) this )
  633. {
  634. return;
  635. }
  636. if ( IsSplitScreenUser() && !m_bSplitAllowFastDisconnect )
  637. {
  638. CNETMsg_StringCmd_t stringCmd( va( "ss_disconnect %d\n", m_nSplitScreenPlayerSlot ) );
  639. SendNetMsg( stringCmd, true );
  640. return;
  641. }
  642. // Need to have all splitscreen parasites go away too
  643. if ( !IsSplitScreenUser() )
  644. {
  645. for ( int j = host_state.max_splitscreen_players; j -- > 1; )
  646. {
  647. if ( !m_SplitScreenUsers[ j ] )
  648. continue;
  649. m_SplitScreenUsers[ j ]->PerformDisconnection( "leaving splitscreen" );
  650. m_SplitScreenUsers[ j ] = NULL;
  651. }
  652. }
  653. // Strip trailing return character
  654. // while ( len > 0 )
  655. // {
  656. // if ( string[ len - 1 ] != '\n' )
  657. // {
  658. // break;
  659. // }
  660. //
  661. // string[ len - 1 ] = 0;
  662. // --len;
  663. // }
  664. PerformDisconnection( fmt );
  665. NotifyDedicatedServerUI("UpdatePlayers");
  666. Steam3Server().SendUpdatedServerDetails(); // Update the master server.
  667. }
  668. void CBaseClient::FireGameEvent( IGameEvent *event, bool bPassthrough )
  669. {
  670. CSVCMsg_GameEvent_t eventMsg;
  671. // create bitstream from KeyValues
  672. if ( g_GameEventManager.SerializeEvent( event, &eventMsg ) )
  673. {
  674. if ( m_NetChannel )
  675. {
  676. if ( bPassthrough )
  677. eventMsg.set_passthrough( 1 );
  678. m_NetChannel->SendNetMsg( eventMsg, event->IsReliable() );
  679. // This is our last chance to deliver this message out since the
  680. // secure channels will be closed!
  681. if ( !Q_stricmp( event->GetName(), "server_pre_shutdown" ) )
  682. m_NetChannel->Transmit();
  683. }
  684. }
  685. else
  686. {
  687. DevMsg("GameEventManager: failed to serialize event '%s'.\n", event->GetName() );
  688. }
  689. }
  690. int CBaseClient::GetEventDebugID( void )
  691. {
  692. return m_nDebugID;
  693. }
  694. bool CBaseClient::SendServerInfo( void )
  695. {
  696. COM_TimestampedLog( " CBaseClient::SendServerInfo: %s : %d", GetClientName(), GetSignonState() );
  697. // supporting smaller stack
  698. net_scratchbuffer_t scratch;
  699. bf_write msg( "SV_SendServerinfo->msg", scratch.GetBuffer(), scratch.Size() );
  700. // Only send this message to developer console, or multiplayer clients.
  701. if ( developer.GetBool() || m_Server->IsMultiplayer() )
  702. {
  703. char devtext[ 2048 ];
  704. int nHumans;
  705. int nMaxHumans;
  706. int nBots;
  707. sv.GetMasterServerPlayerCounts( nHumans, nMaxHumans, nBots );
  708. Q_snprintf( devtext, sizeof( devtext ),
  709. "\n%s\nMap: %s\nPlayers: %i (%i bots) / %i humans\nBuild: %d\nServer Number: %i\n\n",
  710. serverGameDLL->GetGameDescription(),
  711. m_Server->GetMapName(),
  712. nHumans, nBots, nMaxHumans,
  713. build_number(),
  714. m_Server->GetSpawnCount() );
  715. CSVCMsg_Print_t printMsg;
  716. printMsg.set_text( devtext );
  717. printMsg.WriteToBuffer( msg );
  718. }
  719. // write additional server payload
  720. if ( KeyValues *kvExtendedServerInfo = serverGameDLL->GetExtendedServerInfoForNewClient() )
  721. {
  722. // This field must be always set when sending the packet to client,
  723. // because kvExtendedServerInfo describes the game and is cached in server.dll,
  724. // but the clients can connect on SERVER port or on GOTV port and must
  725. // receive appropriate server info for the port that they are using
  726. kvExtendedServerInfo->SetInt( "gotv", m_Server->IsHLTV() );
  727. CSVCMsg_CmdKeyValues_t cmdExtendedServerInfo;
  728. CmdKeyValuesHelper::SVCMsg_SetKeyValues( cmdExtendedServerInfo, kvExtendedServerInfo );
  729. cmdExtendedServerInfo.WriteToBuffer( msg );
  730. }
  731. CSVCMsg_ServerInfo_t serverinfo; // create serverinfo message
  732. serverinfo.set_player_slot( m_nClientSlot ); // own slot number
  733. m_Server->FillServerInfo( serverinfo ); // fill rest of info message
  734. serverinfo.WriteToBuffer( msg );
  735. if ( g_pMatchFramework && !sv.GetReservationCookie() )
  736. {
  737. KeyValues *kvUpdate = new KeyValues( "OnEngineListenServerStarted" );
  738. if ( Steam3Server().SteamGameServer() )
  739. kvUpdate->SetInt( "externalIP", Steam3Server().SteamGameServer()->GetPublicIP() );
  740. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvUpdate );
  741. }
  742. // send first tick
  743. m_nSignonTick = m_Server->m_nTickCount;
  744. CNETMsg_Tick_t signonTick( m_nSignonTick, 0, 0, 0 );
  745. signonTick.WriteToBuffer( msg );
  746. // Write replicated ConVars to non-listen server clients only
  747. if ( !m_NetChannel->IsLoopback() )
  748. {
  749. CNETMsg_SetConVar_t convars;
  750. Host_BuildConVarUpdateMessage( convars.mutable_convars(), FCVAR_REPLICATED, true );
  751. if ( m_Server->IsHLTV() )
  752. {
  753. static_cast< CHLTVServer* >( m_Server )->FixupConvars( convars );
  754. }
  755. convars.WriteToBuffer( msg );
  756. }
  757. // write stringtable baselines
  758. #ifndef SHARED_NET_STRING_TABLES
  759. m_Server->m_StringTables->WriteBaselines( m_Server->GetMapName(), msg );
  760. #endif
  761. m_bSendServerInfo = false;
  762. // send signon state
  763. SetSignonState( SIGNONSTATE_NEW );
  764. CNETMsg_SignonState_t signonMsg( GetSignonState(), m_Server->GetSpawnCount() );
  765. FillSignOnFullServerInfo( signonMsg );
  766. signonMsg.WriteToBuffer( msg );
  767. // send server info as one data block
  768. DevMsg( "Sending server info signon packet for %s: %u / %u buffer %s\n",
  769. m_NetChannel->GetAddress(), msg.GetNumBytesWritten(), NET_MAX_PAYLOAD,
  770. ( msg.IsOverflowed() ? " OVERFLOW" : "" ) );
  771. if ( msg.IsOverflowed() ||
  772. !m_NetChannel->SendData( msg ) )
  773. {
  774. Disconnect("Server info data overflow");
  775. return false;
  776. }
  777. COM_TimestampedLog( " CBaseClient::SendServerInfo(finished)" );
  778. return true;
  779. }
  780. void CBaseClient::OnSteamServerLogonSuccess( uint32 externalIP )
  781. {
  782. if ( g_pMatchFramework && !sv.GetReservationCookie() )
  783. {
  784. KeyValues *kvUpdate = new KeyValues( "OnEngineListenServerStarted" );
  785. kvUpdate->SetInt( "externalIP", externalIP );
  786. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvUpdate );
  787. }
  788. }
  789. CClientFrame *CBaseClient::GetDeltaFrame( int nTick )
  790. {
  791. Assert( 0 ); // derive moe
  792. return NULL; // CBaseClient has no delta frames
  793. }
  794. void CBaseClient::WriteGameSounds(bf_write &buf, int nMaxSounds )
  795. {
  796. // CBaseClient has no events
  797. }
  798. void CBaseClient::ConnectionStart(INetChannel *chan)
  799. {
  800. m_NetMessages[ NETMSG_Tick ].Bind< CNETMsg_Tick_t >( chan, UtlMakeDelegate( this, &CBaseClient::NETMsg_Tick ) );
  801. m_NetMessages[ NETMSG_StringCmd ].Bind< CNETMsg_StringCmd_t >( chan, UtlMakeDelegate( this, &CBaseClient::NETMsg_StringCmd ) );
  802. m_NetMessages[ NETMSG_SignonState ].Bind< CNETMsg_SignonState_t >( chan, UtlMakeDelegate( this, &CBaseClient::NETMsg_SignonState ) );
  803. m_NetMessages[ NETMSG_SetConVar ].Bind< CNETMsg_SetConVar_t >( chan, UtlMakeDelegate( this, &CBaseClient::NETMsg_SetConVar ) );
  804. m_NetMessages[ NETMSG_PlayerAvatarData ].Bind< CNETMsg_PlayerAvatarData_t >( chan, UtlMakeDelegate( this, &CBaseClient::NETMsg_PlayerAvatarData ) );
  805. m_NetMessages[ NETMSG_ClientInfo ].Bind< CCLCMsg_ClientInfo_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_ClientInfo ) );
  806. m_NetMessages[ NETMSG_Move ].Bind< CCLCMsg_Move_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_Move ) );
  807. m_NetMessages[ NETMSG_VoiceData ].Bind< CCLCMsg_VoiceData_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_VoiceData ) );
  808. m_NetMessages[ NETMSG_BaselineAck ].Bind< CCLCMsg_BaselineAck_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_BaselineAck ) );
  809. m_NetMessages[ NETMSG_ListenEvents ].Bind< CCLCMsg_ListenEvents_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_ListenEvents ) );
  810. m_NetMessages[ NETMSG_RespondCvarValue ].Bind< CCLCMsg_RespondCvarValue_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_RespondCvarValue ) );
  811. m_NetMessages[ NETMSG_FileCRCCheck ].Bind< CCLCMsg_FileCRCCheck_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_FileCRCCheck ) );
  812. m_NetMessages[ NETMSG_SplitPlayerConnect ].Bind< CCLCMsg_SplitPlayerConnect_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_SplitPlayerConnect ) );
  813. m_NetMessages[ NETMSG_LoadingProgress ].Bind< CCLCMsg_LoadingProgress_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_LoadingProgress ) );
  814. m_NetMessages[ NETMSG_CmdKeyValues ].Bind< CCLCMsg_CmdKeyValues_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_CmdKeyValues ) );
  815. m_NetMessages[ NETMSG_HltvReplay ].Bind< CCLCMsg_HltvReplay_t >( chan, UtlMakeDelegate( this, &CBaseClient::CLCMsg_HltvReplay ) );
  816. m_NetMessages[ NETMSG_UserMessage ].Bind< CSVCMsg_UserMessage_t >( chan, UtlMakeDelegate( this, &CBaseClient::SVCMsg_UserMessage ) );
  817. }
  818. void CBaseClient::ConnectionStop( )
  819. {
  820. m_NetMessages[ NETMSG_Tick ].Unbind();
  821. m_NetMessages[ NETMSG_StringCmd ].Unbind();
  822. m_NetMessages[ NETMSG_SignonState ].Unbind();
  823. m_NetMessages[ NETMSG_SetConVar ].Unbind();
  824. m_NetMessages[ NETMSG_PlayerAvatarData ].Unbind();
  825. m_NetMessages[ NETMSG_ClientInfo ].Unbind();
  826. m_NetMessages[ NETMSG_Move ].Unbind();
  827. m_NetMessages[ NETMSG_VoiceData ].Unbind();
  828. m_NetMessages[ NETMSG_BaselineAck ].Unbind();
  829. m_NetMessages[ NETMSG_ListenEvents ].Unbind();
  830. m_NetMessages[ NETMSG_RespondCvarValue ].Unbind();
  831. m_NetMessages[ NETMSG_FileCRCCheck ].Unbind();
  832. m_NetMessages[ NETMSG_SplitPlayerConnect ].Unbind();
  833. m_NetMessages[ NETMSG_LoadingProgress ].Unbind();
  834. m_NetMessages[ NETMSG_CmdKeyValues ].Unbind();
  835. m_NetMessages[ NETMSG_HltvReplay ].Unbind();
  836. m_NetMessages[ NETMSG_UserMessage ].Unbind();
  837. }
  838. bool CBaseClient::NETMsg_Tick( const CNETMsg_Tick& msg )
  839. {
  840. // framerate stats is the same whether we're in replay or not
  841. m_NetChannel->SetRemoteFramerate(
  842. CNETMsg_Tick_t::FrametimeToFloat( msg.host_computationtime() ),
  843. CNETMsg_Tick_t::FrametimeToFloat( msg.host_computationtime_std_deviation() ),
  844. CNETMsg_Tick_t::FrametimeToFloat( msg.host_framestarttime_std_deviation() ) );
  845. int nTick = msg.tick();
  846. if ( nTick == -1 // tick == -1 is a call from client to send the full frame update, the client may be in bad state w.r.t. hltv replay
  847. || !msg.hltv_replay_flags() == !GetHltvReplayDelay() ) // the ack should be from the frame from the same timeline as we're feeding the player. Real-time-line acks shouldn't mix up with Replay-time-line acks
  848. {
  849. return UpdateAcknowledgedFramecount( nTick );
  850. }
  851. else
  852. {
  853. // we're fine, the ack is probably from the frame before switching to/from replay
  854. return true;
  855. }
  856. }
  857. bool CBaseClient::NETMsg_StringCmd( const CNETMsg_StringCmd& msg )
  858. {
  859. ExecuteStringCommand( msg.command().c_str() );
  860. return true;
  861. }
  862. bool CBaseClient::NETMsg_PlayerAvatarData( const CNETMsg_PlayerAvatarData& msg )
  863. {
  864. if ( sv_reliableavatardata.GetInt() != 1 )
  865. return true;
  866. if ( ( GetServer() == &sv ) && ( msg.rgb().size() == 64*64*3 ) )
  867. {
  868. m_msgAvatarData.CopyFrom( msg );
  869. m_msgAvatarData.set_accountid( m_SteamID.GetAccountID() );
  870. OnPlayerAvatarDataChanged();
  871. }
  872. return true;
  873. }
  874. void CBaseClient::OnPlayerAvatarDataChanged()
  875. {
  876. // Broadcast this user's avatar to all other users who already got other updates
  877. for ( int iClient = 0; iClient < sv.GetClientCount(); ++iClient )
  878. {
  879. CBaseClient *pClient = dynamic_cast< CBaseClient * >( sv.GetClient( iClient ) );
  880. if ( !pClient->IsActive() )
  881. continue;
  882. // In debug build we can set to echo my own avatar back to client
  883. if ( pClient == this )
  884. continue;
  885. // If this is a GOTV thunk then forward them the raw data
  886. if ( pClient->IsHLTV() )
  887. {
  888. if ( CHLTVServer *hltv = pClient->GetAnyConnectedHltvServer() )
  889. {
  890. hltv->NETMsg_PlayerAvatarData( m_msgAvatarData );
  891. }
  892. continue;
  893. }
  894. if ( INetChannel *pNetChannel = pClient->GetNetChannel() )
  895. {
  896. pNetChannel->EnqueueVeryLargeAsyncTransfer( m_msgAvatarData );
  897. }
  898. }
  899. }
  900. void CBaseClient::ApplyConVars( const CMsg_CVars& list, bool bCreateIfNotExisting )
  901. {
  902. int convars_size = list.cvars_size();
  903. for ( int i = 0; i < convars_size; ++i )
  904. {
  905. const char *name = NetMsgGetCVarUsingDictionary( list.cvars(i) );
  906. const char *value = list.cvars(i).value().c_str();
  907. if ( !V_stricmp( name, "name" ) )
  908. {
  909. value = serverGameClients->ClientNameHandler( m_SteamID.ConvertToUint64(), value );
  910. }
  911. if ( !bCreateIfNotExisting && !m_ConVars->FindKey( name ) )
  912. {
  913. static double s_dblLastWarned = 0.0;
  914. double dblTimeNow = Plat_FloatTime();
  915. #ifndef _DEBUG // warn all the time in debug build
  916. if ( dblTimeNow - s_dblLastWarned > 10 )
  917. #endif
  918. {
  919. s_dblLastWarned = dblTimeNow;
  920. Warning( "Client \"%s\" SteamID %s userinfo ignored: \"%s\" = \"%s\"\n",
  921. this->GetClientName(), CSteamID( this->GetClientXuid() ).Render(), name, value );
  922. }
  923. continue;
  924. }
  925. m_ConVars->SetString( name, value );
  926. m_bConVarsChanged = true;
  927. }
  928. }
  929. bool CBaseClient::NETMsg_SetConVar( const CNETMsg_SetConVar& msg )
  930. {
  931. ApplyConVars( msg.convars(), false ); // followup cvars, must be set on connect
  932. return true;
  933. }
  934. bool CBaseClient::NETMsg_SignonState( const CNETMsg_SignonState& msg )
  935. {
  936. if ( msg.signon_state() == SIGNONSTATE_CHANGELEVEL )
  937. {
  938. return true; // ignore this message
  939. }
  940. if ( msg.signon_state() > SIGNONSTATE_CONNECTED )
  941. {
  942. if ( msg.spawn_count() != (uint32)m_Server->GetSpawnCount() )
  943. {
  944. Reconnect();
  945. return true;
  946. }
  947. }
  948. // client must acknowledge our current state, otherwise start again
  949. if ( msg.signon_state() != (uint32)GetSignonState() )
  950. {
  951. Reconnect();
  952. return true;
  953. }
  954. return ProcessSignonStateMsg( msg.signon_state(), msg.spawn_count() );
  955. }
  956. bool CBaseClient::CLCMsg_ClientInfo( const CCLCMsg_ClientInfo& msg )
  957. {
  958. m_nSendtableCRC = msg.send_table_crc();
  959. m_bIsHLTV = msg.is_hltv();
  960. #if defined( REPLAY_ENABLED )
  961. m_bIsReplay = msg.is_replay();
  962. #endif
  963. m_nFilesDownloaded = 0;
  964. Q_strncpy( m_FriendsName, msg.friends_name().c_str(), sizeof(m_FriendsName) );
  965. for ( int i=0; i<MAX_CUSTOM_FILES; i++ )
  966. {
  967. CRC32_t crc = ( i < msg.custom_files_size() ) ? msg.custom_files( i ) : 0;
  968. m_nCustomFiles[i].crc = crc;
  969. m_nCustomFiles[i].reqID = 0;
  970. }
  971. if ( msg.server_count() != ( uint32 )m_Server->GetSpawnCount() )
  972. {
  973. Reconnect(); // client still in old game, reconnect
  974. }
  975. return true;
  976. }
  977. bool CBaseClient::CLCMsg_LoadingProgress( const CCLCMsg_LoadingProgress& msg )
  978. {
  979. m_nLoadingProgress = msg.progress();
  980. return true;
  981. }
  982. bool CBaseClient::CLCMsg_BaselineAck( const CCLCMsg_BaselineAck& msg )
  983. {
  984. if ( msg.baseline_tick() != m_nBaselineUpdateTick )
  985. {
  986. // This occurs when there are multiple ack's queued up for processing from a client.
  987. return true;
  988. }
  989. if ( msg.baseline_nr() != m_nBaselineUsed )
  990. {
  991. DevMsg("CBaseClient::ProcessBaselineAck: wrong baseline nr received (%i)\n", msg.baseline_tick() );
  992. return true;
  993. }
  994. Assert( m_pBaseline );
  995. // copy ents send as full updates this frame into baseline stuff
  996. CClientFrame *frame = GetDeltaFrame( m_nBaselineUpdateTick );
  997. if ( frame == NULL )
  998. {
  999. // Will get here if we have a lot of packet loss and finally receive a stale ack from
  1000. // remote client. Our "window" could be well beyond what it's acking, so just ignore the ack.
  1001. DevMsg( "Dropping baseline ack %d\n", m_nBaselineUpdateTick );
  1002. return true;
  1003. }
  1004. CFrameSnapshot *pSnapshot = frame->GetSnapshot();
  1005. if ( pSnapshot == NULL )
  1006. {
  1007. // TODO if client lags for a couple of seconds the snapshot is lost
  1008. // fix: don't remove snapshots that are labled a possible basline candidates
  1009. // or: send full update
  1010. DevMsg("CBaseClient::ProcessBaselineAck: invalid frame snapshot (%i)\n", m_nBaselineUpdateTick );
  1011. return false;
  1012. }
  1013. int index = m_BaselinesSent.FindNextSetBit( 0 );
  1014. while ( index >= 0 )
  1015. {
  1016. // get new entity
  1017. PackedEntityHandle_t hNewEntity = pSnapshot->m_pEntities[index].m_pPackedData;
  1018. if ( hNewEntity == INVALID_PACKED_ENTITY_HANDLE )
  1019. {
  1020. DevMsg("CBaseClient::ProcessBaselineAck: invalid packet handle (%i)\n", index );
  1021. return false;
  1022. }
  1023. PackedEntityHandle_t hOldEntity = m_pBaseline->m_pEntities[index].m_pPackedData;
  1024. if ( hOldEntity != INVALID_PACKED_ENTITY_HANDLE )
  1025. {
  1026. // remove reference before overwriting packed entity
  1027. framesnapshotmanager->RemoveEntityReference( hOldEntity );
  1028. }
  1029. // increase reference
  1030. framesnapshotmanager->AddEntityReference( hNewEntity );
  1031. // copy entity handle, class & serial number to
  1032. m_pBaseline->m_pEntities[index] = pSnapshot->m_pEntities[index];
  1033. // go to next entity
  1034. index = m_BaselinesSent.FindNextSetBit( index + 1 );
  1035. }
  1036. m_pBaseline->m_nTickCount = m_nBaselineUpdateTick;
  1037. // flip used baseline flag
  1038. m_nBaselineUsed = (m_nBaselineUsed==1)?0:1;
  1039. m_nBaselineUpdateTick = -1; // ready to update baselines again
  1040. return true;
  1041. }
  1042. bool CBaseClient::CLCMsg_ListenEvents( const CCLCMsg_ListenEvents& msg )
  1043. {
  1044. // first remove the client as listener
  1045. g_GameEventManager.RemoveListener( this );
  1046. CBitVec<MAX_EVENT_NUMBER> EventArray;
  1047. for( int i = 0; i < msg.event_mask_size(); i++ )
  1048. {
  1049. EventArray.SetDWord( i, msg.event_mask( i ) );
  1050. }
  1051. int index = EventArray.FindNextSetBit( 0 );
  1052. while( index >= 0 )
  1053. {
  1054. CGameEventDescriptor *descriptor = g_GameEventManager.GetEventDescriptor( index );
  1055. if ( descriptor )
  1056. {
  1057. g_GameEventManager.AddListener( this, descriptor, CGameEventManager::CLIENTSTUB );
  1058. }
  1059. else
  1060. {
  1061. DevMsg("ProcessListenEvents: game event %i not found.\n", index );
  1062. return false;
  1063. }
  1064. index = EventArray.FindNextSetBit( index + 1 );
  1065. }
  1066. return true;
  1067. }
  1068. bool CBaseClient::IsTracing() const
  1069. {
  1070. return m_Trace.m_nMinWarningBytes != 0;
  1071. }
  1072. void CBaseClient::StartTrace( bf_write &msg )
  1073. {
  1074. if ( !IsTracing() )
  1075. return;
  1076. m_Trace.m_nStartBit = msg.GetNumBitsWritten();
  1077. m_Trace.m_nCurBit = m_Trace.m_nStartBit;
  1078. }
  1079. #define SERVER_PACKETS_LOG "netspike.txt"
  1080. void CBaseClient::EndTrace( bf_write &msg )
  1081. {
  1082. if ( !IsTracing() )
  1083. return;
  1084. int bits = m_Trace.m_nCurBit - m_Trace.m_nStartBit;
  1085. if ( bits < ( m_Trace.m_nMinWarningBytes << 3 ) )
  1086. {
  1087. m_Trace.m_Records.RemoveAll();
  1088. return;
  1089. }
  1090. CNetChan *chan = static_cast< CNetChan * >( m_NetChannel );
  1091. if ( chan )
  1092. {
  1093. int bufReliable = chan->GetBuffer( CNetChan::BUF_RELIABLE ).GetNumBitsWritten();
  1094. int bufUnreliable = chan->GetBuffer( CNetChan::BUF_UNRELIABLE ).GetNumBitsWritten();
  1095. int bufVoice = chan->GetBuffer( CNetChan::BUF_VOICE ).GetNumBitsWritten();
  1096. TraceNetworkMsg( bufReliable, "[Reliable payload]" );
  1097. TraceNetworkMsg( bufUnreliable, "[Unreliable payload]" );
  1098. TraceNetworkMsg( bufVoice, "[Voice payload]" );
  1099. }
  1100. CUtlBuffer logData( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1101. logData.Printf( "%f/%d Player [%s][%d][adr:%s] was sent a datagram %d bits (%8.3f bytes)\n",
  1102. realtime,
  1103. host_tickcount,
  1104. GetClientName(),
  1105. GetPlayerSlot(),
  1106. GetNetChannel()->GetAddress(),
  1107. bits, (float)bits / 8.0f );
  1108. const int WriteSize = 10*1024;
  1109. for ( int i = 0 ; i < m_Trace.m_Records.Count() ; ++i )
  1110. {
  1111. Spike_t &sp = m_Trace.m_Records[ i ];
  1112. logData.Printf( "%64.64s : %8d bits (%8.3f bytes)\n", sp.m_szDesc, sp.m_nBits, (float)sp.m_nBits / 8.0f );
  1113. if ( logData.TellPut() > WriteSize && i != m_Trace.m_Records.Count()-1 )
  1114. {
  1115. COM_LogString( SERVER_PACKETS_LOG, (char *)logData.Base() );
  1116. logData.Clear();
  1117. }
  1118. }
  1119. COM_LogString( SERVER_PACKETS_LOG, (char *)logData.Base() );
  1120. m_Trace.m_Records.RemoveAll();
  1121. }
  1122. void CBaseClient::TraceNetworkData( bf_write &msg, char const *fmt, ... )
  1123. {
  1124. if ( !IsTracing() )
  1125. return;
  1126. char buf[ 64 ];
  1127. va_list argptr;
  1128. va_start( argptr, fmt );
  1129. Q_vsnprintf( buf, sizeof( buf ), fmt, argptr );
  1130. va_end( argptr );
  1131. Spike_t t;
  1132. Q_strncpy( t.m_szDesc, buf, sizeof( t.m_szDesc ) );
  1133. t.m_nBits = msg.GetNumBitsWritten() - m_Trace.m_nCurBit;
  1134. m_Trace.m_Records.AddToTail( t );
  1135. m_Trace.m_nCurBit = msg.GetNumBitsWritten();
  1136. }
  1137. void CBaseClient::TraceNetworkMsg( int nBits, char const *fmt, ... )
  1138. {
  1139. if ( !IsTracing() )
  1140. return;
  1141. char buf[ 64 ];
  1142. va_list argptr;
  1143. va_start( argptr, fmt );
  1144. Q_vsnprintf( buf, sizeof( buf ), fmt, argptr );
  1145. va_end( argptr );
  1146. Spike_t t;
  1147. Q_strncpy( t.m_szDesc, buf, sizeof( t.m_szDesc ) );
  1148. t.m_nBits = nBits;
  1149. m_Trace.m_Records.AddToTail( t );
  1150. }
  1151. void CBaseClient::SetTraceThreshold( int nThreshold )
  1152. {
  1153. m_Trace.m_nMinWarningBytes = nThreshold;
  1154. }
  1155. static ConVar sv_multiplayer_maxtempentities( "sv_multiplayer_maxtempentities", "32" );
  1156. ConVar sv_multiplayer_maxsounds( "sv_multiplayer_sounds", "20" );
  1157. bool CBaseClient::SendSnapshot( CClientFrame *pFrame )
  1158. {
  1159. SNPROF( "SendSnapshot" );
  1160. // never send the same snapshot twice
  1161. if ( m_pLastSnapshot == pFrame->GetSnapshot() )
  1162. {
  1163. m_NetChannel->Transmit();
  1164. return false;
  1165. }
  1166. // if we send a full snapshot (no delta-compression) before, wait until client
  1167. // received and acknowledge that update. don't spam client with full updates
  1168. if ( m_nForceWaitForTick > 0 )
  1169. {
  1170. // just continue transmitting reliable data
  1171. m_NetChannel->Transmit();
  1172. return false;
  1173. }
  1174. VPROF_BUDGET( "SendSnapshot", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1175. net_scratchbuffer_t scratch;
  1176. bf_write msg( "CBaseClient::SendSnapshot",
  1177. scratch.GetBuffer(), scratch.Size() );
  1178. TRACE_PACKET( ( "SendSnapshot(%d)\n", pFrame->tick_count ) );
  1179. // now create client snapshot packet
  1180. CClientFrame * deltaFrame = m_nDeltaTick < 0 ? NULL : GetDeltaFrame( m_nDeltaTick ); // NULL if delta_tick is not found
  1181. if ( !deltaFrame )
  1182. {
  1183. // We need to send a full update and reset the instanced baselines
  1184. char reason[ 128 ];
  1185. Q_snprintf( reason, sizeof( reason ), "%s can't find frame from tick %d", GetClientName(), m_nDeltaTick );
  1186. OnRequestFullUpdate( reason );
  1187. }
  1188. if ( IsTracing() )
  1189. {
  1190. StartTrace( msg );
  1191. }
  1192. // send tick time
  1193. {
  1194. CNETMsg_Tick_t tickmsg( pFrame->tick_count, host_frameendtime_computationduration, host_frametime_stddeviation, host_framestarttime_stddeviation );
  1195. if ( !tickmsg.WriteToBuffer( msg ) )
  1196. {
  1197. Disconnect( "#GameUI_Disconnect_TickMessage" );
  1198. return false;
  1199. }
  1200. }
  1201. if ( IsTracing() )
  1202. {
  1203. TraceNetworkData( msg, "NET_Tick" );
  1204. }
  1205. #ifndef SHARED_NET_STRING_TABLES
  1206. // in LocalNetworkBackdoor mode we updated the stringtables already in SV_ComputeClientPacks()
  1207. if ( !g_pLocalNetworkBackdoor )
  1208. {
  1209. // Update shared client/server string tables. Must be done before sending entities
  1210. m_Server->m_StringTables->WriteUpdateMessage( this, GetMaxAckTickCount(), msg );
  1211. }
  1212. #endif
  1213. int nDeltaStartBit = 0;
  1214. if ( IsTracing() )
  1215. {
  1216. nDeltaStartBit = msg.GetNumBitsWritten();
  1217. }
  1218. // send entity update, delta compressed if deltaFrame != NULL
  1219. {
  1220. m_Server->WriteDeltaEntities( this, pFrame, deltaFrame, m_packetmsg );
  1221. if ( !m_packetmsg.WriteToBuffer( msg ) )
  1222. {
  1223. Disconnect( "#GameUI_Disconnect_DeltaEntMessage" );
  1224. return false;
  1225. }
  1226. }
  1227. if ( IsTracing() )
  1228. {
  1229. int nBits = msg.GetNumBitsWritten() - nDeltaStartBit;
  1230. TraceNetworkMsg( nBits, "Total Delta" );
  1231. }
  1232. // send all unreliable temp entities between last and current frame
  1233. // send max 64 events in multi player, 255 in SP
  1234. int nMaxTempEnts = m_Server->IsMultiplayer() ? sv_multiplayer_maxtempentities.GetInt() : 255;
  1235. m_Server->WriteTempEntities( this, pFrame->GetSnapshot(), m_pLastSnapshot.GetObject(), m_tempentsmsg, nMaxTempEnts );
  1236. if ( m_tempentsmsg.num_entries() )
  1237. {
  1238. m_tempentsmsg.WriteToBuffer( msg );
  1239. }
  1240. if ( IsTracing() )
  1241. {
  1242. TraceNetworkData( msg, "Temp Entities" );
  1243. }
  1244. int nMaxSounds = m_Server->IsMultiplayer() ? sv_multiplayer_maxsounds.GetInt() : 255;
  1245. WriteGameSounds( msg, nMaxSounds );
  1246. if ( IsTracing() )
  1247. {
  1248. TraceNetworkMsg( 0, "Finished [delta %s]", deltaFrame ? "yes" : "no" );
  1249. EndTrace( msg );
  1250. }
  1251. // write message to packet and check for overflow
  1252. if ( msg.IsOverflowed() )
  1253. {
  1254. if ( !deltaFrame )
  1255. {
  1256. // if this is a reliable snapshot, drop the client
  1257. Disconnect( "ERROR! Reliable snaphsot overflow." );
  1258. return false;
  1259. }
  1260. else
  1261. {
  1262. // unreliable snapshots may be dropped
  1263. ConMsg ("WARNING: msg overflowed for %s\n", m_Name);
  1264. msg.Reset();
  1265. }
  1266. }
  1267. // remember this snapshot
  1268. m_pLastSnapshot = pFrame->GetSnapshot();
  1269. // Don't send the datagram to fakeplayers unless sv_stressbots is on (which will make m_NetChannel non-null).
  1270. if ( m_bFakePlayer && !m_NetChannel )
  1271. {
  1272. m_nDeltaTick = pFrame->tick_count;
  1273. m_nStringTableAckTick = m_nDeltaTick;
  1274. return true;
  1275. }
  1276. bool bSendOK;
  1277. // is this is a full entity update (no delta) ?
  1278. if ( !deltaFrame )
  1279. {
  1280. // transmit snapshot as reliable data chunk
  1281. bSendOK = m_NetChannel->SendData( msg );
  1282. bSendOK = bSendOK && m_NetChannel->Transmit();
  1283. // remember this tickcount we send the reliable snapshot
  1284. // so we can continue sending other updates if this has been acknowledged
  1285. m_nForceWaitForTick = pFrame->tick_count;
  1286. }
  1287. else
  1288. {
  1289. // just send it as unreliable snapshot
  1290. bSendOK = m_NetChannel->SendDatagram( &msg ) > 0;
  1291. }
  1292. if ( !bSendOK )
  1293. {
  1294. Disconnect( "ERROR! Couldn't send snapshot." );
  1295. return false;
  1296. }
  1297. return true;
  1298. }
  1299. bool CBaseClient::ExecuteStringCommand( const char *pCommand )
  1300. {
  1301. if ( !pCommand || !pCommand[0] )
  1302. return false;
  1303. if ( !Q_stricmp( pCommand, "demorestart" ) )
  1304. {
  1305. DemoRestart();
  1306. // trick, dont return true, so serverGameClients gets this command too
  1307. return false;
  1308. }
  1309. return false;
  1310. }
  1311. void CBaseClient::DemoRestart()
  1312. {
  1313. }
  1314. bool CBaseClient::ShouldSendMessages( void )
  1315. {
  1316. if ( !IsConnected() )
  1317. return false;
  1318. // if the reliable message overflowed, drop the client
  1319. if ( m_NetChannel && m_NetChannel->IsOverflowed() )
  1320. {
  1321. m_NetChannel->Reset();
  1322. Disconnect( CFmtStr( "%s overflowed reliable buffer\n", m_Name ) );
  1323. return false;
  1324. }
  1325. // check, if it's time to send the next packet
  1326. bool bSendMessage = m_fNextMessageTime <= net_time ;
  1327. // don't throttle loopback connections
  1328. if ( m_NetChannel && m_NetChannel->IsLoopback() )
  1329. {
  1330. bSendMessage = true;
  1331. }
  1332. if ( !bSendMessage && !IsActive() )
  1333. {
  1334. // if we are in signon modem instantly reply if
  1335. // we got a answer and have reliable data waiting
  1336. if ( m_bReceivedPacket && m_NetChannel && m_NetChannel->HasPendingReliableData() )
  1337. {
  1338. bSendMessage = true;
  1339. }
  1340. }
  1341. if ( bSendMessage && m_NetChannel && !m_NetChannel->CanPacket() )
  1342. {
  1343. // we would like to send a message, but bandwidth isn't available yet
  1344. // tell netchannel that we are choking a packet
  1345. m_NetChannel->SetChoked();
  1346. // Record an ETW event to indicate that we are throttling.
  1347. ETWThrottled();
  1348. bSendMessage = false;
  1349. }
  1350. return bSendMessage;
  1351. }
  1352. void CBaseClient::UpdateSendState( void )
  1353. {
  1354. // wait for next incoming packet
  1355. m_bReceivedPacket = false;
  1356. // in single player mode always send messages
  1357. if ( !m_Server->IsMultiplayer() && !host_limitlocal.GetFloat() )
  1358. {
  1359. m_fNextMessageTime = net_time; // send ASAP and
  1360. m_bReceivedPacket = true; // don't wait for incoming packets
  1361. }
  1362. else if ( IsActive() ) // multiplayer mode
  1363. {
  1364. // snapshot mode: send snapshots frequently
  1365. float maxDelta = MIN( m_Server->GetTickInterval(), m_fSnapshotInterval );
  1366. float delta = clamp( net_time - m_fNextMessageTime, 0.0f, maxDelta );
  1367. m_fNextMessageTime = net_time + m_fSnapshotInterval - delta;
  1368. }
  1369. else // multiplayer signon mode
  1370. {
  1371. if ( m_NetChannel && m_NetChannel->HasPendingReliableData() &&
  1372. m_NetChannel->GetTimeSinceLastReceived() < 1.0f )
  1373. {
  1374. // if we have pending reliable data send as fast as possible
  1375. m_fNextMessageTime = net_time;
  1376. }
  1377. else
  1378. {
  1379. // signon mode: only respond on request or after 1 second
  1380. m_fNextMessageTime = net_time + 1.0f;
  1381. }
  1382. }
  1383. }
  1384. void CBaseClient::UpdateUserSettings()
  1385. {
  1386. // set user name
  1387. SetName( m_ConVars->GetString( "name", "unnamed") );
  1388. // set server to client network rate
  1389. SetRate( m_ConVars->GetInt( "rate", DEFAULT_RATE ), false );
  1390. // set server to client update rate
  1391. SetUpdateRate( m_ConVars->GetFloat( "cl_updaterate", 64 ), false );
  1392. SetMaxRoutablePayloadSize( m_ConVars->GetInt( "net_maxroutable", MAX_ROUTABLE_PAYLOAD ) );
  1393. m_Server->UserInfoChanged( m_nClientSlot );
  1394. m_bConVarsChanged = false;
  1395. }
  1396. void CBaseClient::OnRequestFullUpdate( char const *pchReason )
  1397. {
  1398. // client requests a full update
  1399. m_pLastSnapshot = NULL;
  1400. // free old baseline snapshot
  1401. FreeBaselines();
  1402. // and create new baseline snapshot
  1403. m_pBaseline = framesnapshotmanager->CreateEmptySnapshot(
  1404. #ifdef DEBUG_SNAPSHOT_REFERENCES
  1405. CFmtStr( "CBaseClient[%d,%s]::OnRequestFullUpdate(%s)", m_nClientSlot, GetClientName(), pchReason ).Access(),
  1406. #endif
  1407. 0, MAX_EDICTS );
  1408. DevMsg("Sending full update to Client %s (%s)\n", GetClientName(), pchReason );
  1409. }
  1410. //-----------------------------------------------------------------------------
  1411. // Purpose:
  1412. // Input : *cl -
  1413. //-----------------------------------------------------------------------------
  1414. bool CBaseClient::UpdateAcknowledgedFramecount(int tick)
  1415. {
  1416. if ( IsFakeClient() )
  1417. {
  1418. // fake clients are always fine
  1419. m_nDeltaTick = tick;
  1420. m_nStringTableAckTick = tick;
  1421. return true;
  1422. }
  1423. // are we waiting for full reliable update acknowledge
  1424. if ( m_nForceWaitForTick > 0 )
  1425. {
  1426. if ( tick > m_nForceWaitForTick )
  1427. {
  1428. // we should never get here since full updates are transmitted as reliable data now
  1429. ConDMsg( "Acknowledging reliable snapshot failed: ack %d while waiting for %d.\n", tick, m_nForceWaitForTick );
  1430. return true;
  1431. }
  1432. else if ( tick == -1 )
  1433. {
  1434. if( !m_NetChannel->HasPendingReliableData() )
  1435. {
  1436. // that's strange: we sent the client a full update, and it was fully received ( no reliable data in waiting buffers )
  1437. // but the client is requesting another full update.
  1438. //
  1439. // This can happen if they request full updates in succession really quickly (using cl_fullupdate or "record X;stop" quickly).
  1440. // There was a bug here where if we just return out, the client will have nuked its entities and we'd send it
  1441. // a supposedly uncompressed update but m_nDeltaTick was not -1, so it was delta'd and it'd miss lots of stuff.
  1442. // Led to clients getting full spectator mode radar while their player was not a spectator.
  1443. ConDMsg("Client forced immediate full update.\n");
  1444. m_nForceWaitForTick = m_nDeltaTick = -1;
  1445. OnRequestFullUpdate( "forced immediate full update" );
  1446. return true;
  1447. }
  1448. }
  1449. else if ( tick < m_nForceWaitForTick )
  1450. {
  1451. // keep on waiting, do nothing
  1452. return true;
  1453. }
  1454. else // ( tick == m_nForceWaitForTick )
  1455. {
  1456. // great, the client acknowledge the tick we send the full update
  1457. m_nForceWaitForTick = -1;
  1458. // continue sending snapshots...
  1459. }
  1460. }
  1461. else
  1462. {
  1463. if ( m_nDeltaTick == -1 )
  1464. {
  1465. // we still want to send a full update, don't change delta_tick from -1
  1466. return true;
  1467. }
  1468. if ( tick == -1 )
  1469. {
  1470. OnRequestFullUpdate( "client ack'd -1" );
  1471. }
  1472. else
  1473. {
  1474. if ( m_nDeltaTick > tick )
  1475. {
  1476. // client already acknowledged new tick and now switch back to older
  1477. // thats not allowed since we always delete older frames
  1478. Disconnect("Client delta ticks out of order.\n");
  1479. return false;
  1480. }
  1481. }
  1482. }
  1483. // get acknowledged client frame
  1484. m_nDeltaTick = tick;
  1485. if ( m_nDeltaTick > -1 )
  1486. {
  1487. m_nStringTableAckTick = m_nDeltaTick;
  1488. }
  1489. if ( (m_nBaselineUpdateTick > -1) && (m_nDeltaTick > m_nBaselineUpdateTick) )
  1490. {
  1491. // server sent a baseline update, but it wasn't acknowledged yet so it was probably lost.
  1492. m_nBaselineUpdateTick = -1;
  1493. }
  1494. return true;
  1495. }
  1496. //-----------------------------------------------------------------------------
  1497. // Purpose: return a string version of the userid
  1498. //-----------------------------------------------------------------------------
  1499. const char *GetUserIDString( const USERID_t& id )
  1500. {
  1501. static char idstr[ MAX_NETWORKID_LENGTH ];
  1502. idstr[ 0 ] = 0;
  1503. switch ( id.idtype )
  1504. {
  1505. case IDTYPE_STEAM:
  1506. {
  1507. TSteamGlobalUserID nullID;
  1508. Q_memset( &nullID, 0, sizeof( TSteamGlobalUserID ) );
  1509. if ( Steam3Server().BLanOnly() && !Q_memcmp( &id.uid.steamid, &nullID, sizeof( TSteamGlobalUserID ) ) )
  1510. {
  1511. strcpy( idstr, "STEAM_ID_LAN" );
  1512. }
  1513. else if ( !Q_memcmp( &id.uid.steamid, &nullID, sizeof( TSteamGlobalUserID ) ))
  1514. {
  1515. strcpy( idstr, "STEAM_ID_PENDING" );
  1516. }
  1517. else
  1518. {
  1519. Q_snprintf( idstr, sizeof( idstr ) - 1, "STEAM_%u:%u:%u", (SteamInstanceID_t)id.uid.steamid.m_SteamInstanceID,
  1520. (unsigned int)((SteamLocalUserID_t)id.uid.steamid.m_SteamLocalUserID.Split.High32bits),
  1521. (unsigned int)((SteamLocalUserID_t)id.uid.steamid.m_SteamLocalUserID.Split.Low32bits ));
  1522. idstr[ sizeof( idstr ) - 1 ] = '\0';
  1523. }
  1524. }
  1525. break;
  1526. case IDTYPE_HLTV:
  1527. {
  1528. strcpy( idstr, "HLTV" );
  1529. }
  1530. break;
  1531. case IDTYPE_REPLAY:
  1532. {
  1533. strcpy( idstr, "REPLAY" );
  1534. }
  1535. break;
  1536. default:
  1537. {
  1538. strcpy( idstr, "UNKNOWN" );
  1539. }
  1540. break;
  1541. }
  1542. return idstr;
  1543. }
  1544. //-----------------------------------------------------------------------------
  1545. // Purpose: return a string version of the userid
  1546. //-----------------------------------------------------------------------------
  1547. const char *CBaseClient::GetNetworkIDString() const
  1548. {
  1549. if ( IsFakeClient() )
  1550. {
  1551. return "BOT";
  1552. }
  1553. #if defined( _X360 )
  1554. if ( m_ConVars )
  1555. #elif defined( SERVER_XLSP )
  1556. if ( NET_IsDedicatedForXbox() && m_ConVars )
  1557. #else
  1558. if ( 0 )
  1559. #endif
  1560. {
  1561. const char * value = m_ConVars->GetString( "networkid_force", "" );
  1562. if ( value && *value )
  1563. return value;
  1564. }
  1565. return ( GetUserIDString( GetNetworkID() ) );
  1566. }
  1567. uint64 CBaseClient::GetClientXuid() const
  1568. {
  1569. // For 2nd SS player IsFakeClient() == true, so need to short-circuit it straight into forced network_id -- Vitaliy
  1570. const char * value = NULL;
  1571. #if defined( _X360 )
  1572. if ( m_ConVars )
  1573. #elif defined( SERVER_XLSP )
  1574. if ( NET_IsDedicatedForXbox() && m_ConVars )
  1575. #else
  1576. if ( 0 )
  1577. #endif
  1578. {
  1579. value = m_ConVars->GetString( "networkid_force", NULL );
  1580. }
  1581. if ( value && *value && strlen( value ) > 10 )
  1582. return ( uint64( strtoul( value, NULL, 16 ) ) << 32 ) | uint64( strtoul( value + 9, NULL, 16 ) );
  1583. if ( IsFakeClient() )
  1584. return 0ull;
  1585. else
  1586. return m_SteamID.ConvertToUint64();
  1587. }
  1588. bool CBaseClient::IgnoreTempEntity( CEventInfo *event )
  1589. {
  1590. int iPlayerIndex = GetPlayerSlot()+1;
  1591. return !event->filter.IncludesPlayer( iPlayerIndex );
  1592. }
  1593. const USERID_t CBaseClient::GetNetworkID() const
  1594. {
  1595. USERID_t userID;
  1596. m_SteamID.ConvertToSteam2( &userID.uid.steamid );
  1597. userID.idtype = IDTYPE_STEAM;
  1598. userID.uid.steamid.m_SteamInstanceID = 1;
  1599. return userID;
  1600. }
  1601. void CBaseClient::SetSteamID( const CSteamID &steamID )
  1602. {
  1603. m_SteamID = steamID;
  1604. }
  1605. void CBaseClient::SetMaxRoutablePayloadSize( int nMaxRoutablePayloadSize )
  1606. {
  1607. if ( m_NetChannel )
  1608. {
  1609. m_NetChannel->SetMaxRoutablePayloadSize( nMaxRoutablePayloadSize );
  1610. }
  1611. }
  1612. int CBaseClient::GetMaxAckTickCount() const
  1613. {
  1614. int nMaxTick = m_nSignonTick;
  1615. if ( m_nDeltaTick > nMaxTick )
  1616. {
  1617. nMaxTick = m_nDeltaTick;
  1618. }
  1619. if ( m_nStringTableAckTick > nMaxTick )
  1620. {
  1621. nMaxTick = m_nStringTableAckTick;
  1622. }
  1623. return nMaxTick;
  1624. }
  1625. int CBaseClient::GetAvailableSplitScreenSlot() const
  1626. {
  1627. for ( int i = 1; i < host_state.max_splitscreen_players; ++i )
  1628. {
  1629. if ( m_SplitScreenUsers[ i ] )
  1630. continue;
  1631. return i;
  1632. }
  1633. return -1;
  1634. }
  1635. void CBaseClient::SendFullConnectEvent()
  1636. {
  1637. IGameEvent *event = g_GameEventManager.CreateEvent( "player_connect_full" );
  1638. if ( event )
  1639. {
  1640. event->SetInt( "userid", m_UserID );
  1641. event->SetInt( "index", m_nClientSlot );
  1642. g_GameEventManager.FireEvent( event );
  1643. }
  1644. }
  1645. void CBaseClient::FillSignOnFullServerInfo( CNETMsg_SignonState_t &state )
  1646. {
  1647. //
  1648. // FillSignOnFullServerInfo
  1649. // fills the signon state message with full information about
  1650. // server clients connected to it at the moment
  1651. //
  1652. if ( IsX360() || sv.IsDedicatedForXbox() )
  1653. {
  1654. //
  1655. // We only do this on X360 listen server and X360-dedicated server
  1656. //
  1657. state.set_num_server_players (sv.GetClientCount());
  1658. for ( int j = 0 ; j < sv.GetClientCount() ; j++ )
  1659. {
  1660. IClient *client = sv.GetClient( j );
  1661. char const *szNetworkId = client->GetNetworkIDString();
  1662. state.add_players_networkids( szNetworkId );
  1663. }
  1664. }
  1665. const char *pMapname = HostState_GetNewLevel();
  1666. state.set_map_name( pMapname ? pMapname : "" );
  1667. }
  1668. struct SessionClient_t
  1669. {
  1670. uint64 xSession;
  1671. int numPlayers;
  1672. CCopyableUtlVector< IClient * > arrClients;
  1673. bool operator == ( const SessionClient_t & x ) const
  1674. {
  1675. return xSession == x.xSession;
  1676. }
  1677. static int Less( const SessionClient_t *a, const SessionClient_t *b )
  1678. {
  1679. // Groups with invalid session id should absolutely
  1680. // get dropped
  1681. if ( a->xSession != b->xSession )
  1682. {
  1683. if ( !a->xSession )
  1684. return 1;
  1685. if ( !b->xSession )
  1686. return -1;
  1687. }
  1688. // Keep more players if possible
  1689. if ( a->numPlayers != b->numPlayers )
  1690. return ( a->numPlayers > b->numPlayers ) ? -1 : 1;
  1691. // Keep more clients if possible
  1692. if ( a->arrClients.Count() != b->arrClients.Count() )
  1693. return ( a->arrClients.Count() > b->arrClients.Count() ) ? -1 : 1;
  1694. // Prefer to preserve the clients that have the original
  1695. // reservation session (that's the lobby leader)
  1696. if ( a->xSession != b->xSession )
  1697. {
  1698. if ( a->xSession == sv.GetReservationCookie() )
  1699. return -1;
  1700. if ( b->xSession == sv.GetReservationCookie() )
  1701. return 1;
  1702. }
  1703. // Otherwise keep the client that came first
  1704. return ( a->arrClients[0]->GetUserID() < b->arrClients[0]->GetUserID() ) ? -1 : 1;
  1705. }
  1706. };
  1707. void HostValidateSessionImpl()
  1708. {
  1709. if ( !sv.IsDedicatedForXbox() )
  1710. return;
  1711. Msg( "[SESSION] Validating Session Information...\n" );
  1712. CUtlVector< SessionClient_t > arrSessions;
  1713. //
  1714. // Collect all connected clients by their sessions
  1715. //
  1716. for ( int j = 0 ; j < sv.GetClientCount() ; j++ )
  1717. {
  1718. IClient *client = sv.GetClient( j );
  1719. if( !client )
  1720. continue;
  1721. if ( !client->IsConnected() )
  1722. continue;
  1723. if ( client->IsFakeClient() )
  1724. continue;
  1725. if ( client->IsSplitScreenUser() )
  1726. continue;
  1727. // Now we have a client who is a real human client
  1728. const char *szSession = client->GetUserSetting( "cl_session" );
  1729. uint64 uid = 0;
  1730. if ( sscanf( szSession, "$%llx", &uid ) != 1 )
  1731. {
  1732. Warning( "couldn't parse cl_session %s\n", szSession );
  1733. }
  1734. SessionClient_t sc;
  1735. sc.xSession = uid;
  1736. sc.numPlayers = 0;
  1737. int idx = arrSessions.Find( sc );
  1738. if ( idx == arrSessions.InvalidIndex() )
  1739. {
  1740. idx = arrSessions.AddToTail( sc );
  1741. }
  1742. arrSessions[idx].arrClients.AddToTail( client );
  1743. arrSessions[idx].numPlayers += client->GetNumPlayers();
  1744. }
  1745. //
  1746. // Sort the sessions
  1747. //
  1748. if ( !arrSessions.Count() )
  1749. {
  1750. Msg( "[SESSION] No clients.\n" );
  1751. return;
  1752. }
  1753. arrSessions.Sort( &SessionClient_t::Less );
  1754. //
  1755. // Set the new reservation cookie and drop the rest
  1756. //
  1757. int iDropIndex = 0;
  1758. if ( arrSessions[0].xSession )
  1759. {
  1760. Msg( "[SESSION] Updating reservation cookie: %llx, keeping %d players.\n",
  1761. arrSessions[0].xSession, arrSessions[0].numPlayers );
  1762. sv.SetReservationCookie( arrSessions[0].xSession, "HostValidateSession" );
  1763. iDropIndex = 1;
  1764. }
  1765. for ( int k = iDropIndex; k < arrSessions.Count(); ++ k )
  1766. {
  1767. for ( int clIdx = 0; clIdx < arrSessions[k].arrClients.Count(); ++ clIdx )
  1768. {
  1769. arrSessions[k].arrClients[clIdx]->Disconnect( "Session migrated" );
  1770. }
  1771. }
  1772. }
  1773. bool CBaseClient::CheckConnect()
  1774. {
  1775. return true;
  1776. }
  1777. bool CBaseClient::CLCMsg_SplitPlayerConnect( const CCLCMsg_SplitPlayerConnect& msg )
  1778. {
  1779. int slot = GetAvailableSplitScreenSlot();
  1780. if ( slot == -1 )
  1781. {
  1782. Warning( "no more split screen slots!\n" );
  1783. Disconnect( "No more split screen slots!" );
  1784. return true;
  1785. }
  1786. CBaseClient *pSplitClient = sv.CreateSplitClient( msg.convars(), this );
  1787. if ( pSplitClient )
  1788. {
  1789. Assert( pSplitClient->m_bSplitScreenUser );
  1790. pSplitClient->m_nSplitScreenPlayerSlot = slot;
  1791. Assert( slot < ARRAYSIZE(m_SplitScreenUsers) );
  1792. m_SplitScreenUsers[ slot ] = pSplitClient;
  1793. CSVCMsg_SplitScreen_t splitscreenmsg;
  1794. splitscreenmsg.set_player_index( pSplitClient->m_nEntityIndex );
  1795. splitscreenmsg.set_slot( slot );
  1796. splitscreenmsg.set_type( MSG_SPLITSCREEN_ADDUSER );
  1797. m_NetChannel->AttachSplitPlayer( slot, pSplitClient->m_NetChannel );
  1798. SendNetMsg( splitscreenmsg, true );
  1799. if ( pSplitClient->m_pAttachedTo->IsActive() )
  1800. {
  1801. //only activate if the main player is in a state where we would want to, otherwise the client will take care of it later.
  1802. pSplitClient->ActivatePlayer();
  1803. }
  1804. }
  1805. return true;
  1806. }
  1807. bool CBaseClient::CLCMsg_CmdKeyValues( const CCLCMsg_CmdKeyValues& msg )
  1808. {
  1809. return true;
  1810. }
  1811. void CBaseClient::SplitScreenDisconnect( const CCommand &args )
  1812. {
  1813. // Fixme, this will work for 2 players, but not 4 right now
  1814. int nSlot = 1;
  1815. if ( args.ArgC() > 1 )
  1816. {
  1817. nSlot = Q_atoi( args.Arg( 1 ) );
  1818. }
  1819. if ( nSlot <= 0 )
  1820. nSlot = 1;
  1821. if ( m_SplitScreenUsers[ nSlot ] != NULL )
  1822. {
  1823. CBaseClient *pSplitClient = m_SplitScreenUsers[ nSlot ];
  1824. DisconnectSplitScreenUser( pSplitClient );
  1825. }
  1826. }
  1827. void CBaseClient::DisconnectSplitScreenUser( CBaseClient *pSplitClient )
  1828. {
  1829. sv.QueueSplitScreenDisconnect( this, pSplitClient );
  1830. CSVCMsg_SplitScreen_t msg;
  1831. msg.set_player_index( pSplitClient->m_nEntityIndex );
  1832. msg.set_slot( pSplitClient->m_nSplitScreenPlayerSlot );
  1833. msg.set_type( MSG_SPLITSCREEN_REMOVEUSER );
  1834. m_NetChannel->DetachSplitPlayer( pSplitClient->m_nSplitScreenPlayerSlot );
  1835. SendNetMsg( msg, true );
  1836. }
  1837. bool CBaseClient::ChangeSplitscreenUser( int nSplitScreenUserSlot )
  1838. {
  1839. if ( IsSplitScreenUser() )
  1840. {
  1841. return m_pAttachedTo->ChangeSplitscreenUser( nSplitScreenUserSlot );
  1842. }
  1843. int other = nSplitScreenUserSlot;
  1844. bool success = false;
  1845. if ( other == -1 )
  1846. {
  1847. // Revert to self
  1848. success = m_NetChannel->SetActiveChannel( m_NetChannel );
  1849. }
  1850. else
  1851. {
  1852. if ( ( other >= 0 ) && ( other < ARRAYSIZE(m_SplitScreenUsers) ) && m_SplitScreenUsers[ other ] )
  1853. {
  1854. success = m_NetChannel->SetActiveChannel( m_SplitScreenUsers[ other ]->m_NetChannel );
  1855. }
  1856. }
  1857. if ( !success )
  1858. {
  1859. if ( !NET_IsDedicated() )
  1860. {
  1861. Msg( "Unable to set SetActiveChannel to user in slot %d\n", nSplitScreenUserSlot );
  1862. }
  1863. Assert( 0 );
  1864. return false;
  1865. }
  1866. return true;
  1867. }
  1868. bool CBaseClient::IsSplitScreenPartner( const CBaseClient *pOther ) const
  1869. {
  1870. if ( !pOther )
  1871. return false;
  1872. if ( pOther->IsSplitScreenUser() &&
  1873. pOther->m_pAttachedTo == this )
  1874. return true;
  1875. if ( IsSplitScreenUser() &&
  1876. m_pAttachedTo == pOther )
  1877. return true;
  1878. return false;
  1879. }
  1880. int CBaseClient::GetNumPlayers()
  1881. {
  1882. if ( IsSplitScreenUser() )
  1883. {
  1884. if ( m_pAttachedTo )
  1885. return m_pAttachedTo->GetNumPlayers();
  1886. else
  1887. return 0;
  1888. }
  1889. else
  1890. {
  1891. int numPlayers = 0;
  1892. for ( int k = 0; k < ARRAYSIZE( m_SplitScreenUsers ); ++ k )
  1893. {
  1894. if ( m_SplitScreenUsers[k] )
  1895. ++ numPlayers;
  1896. }
  1897. return numPlayers;
  1898. }
  1899. }
  1900. // Is an actual human player or splitscreen player (not a bot and not a HLTV slot)
  1901. bool CBaseClient::IsHumanPlayer() const
  1902. {
  1903. if ( !IsConnected() )
  1904. return false;
  1905. if ( IsHLTV() )
  1906. return false;
  1907. if ( IsFakeClient() && !IsSplitScreenUser() )
  1908. return false;
  1909. return true;
  1910. }