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.

537 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // hltvclient.cpp: implementation of the CHLTVClient class.
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include <tier0/vprof.h>
  9. #include "hltvclient.h"
  10. #include "netmessages.h"
  11. #include "hltvserver.h"
  12. #include "framesnapshot.h"
  13. #include "networkstringtable.h"
  14. #include "dt_send_eng.h"
  15. #include "GameEventManager.h"
  16. #include "cmd.h"
  17. #include "ihltvdirector.h"
  18. #include "host.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. static ConVar tv_maxrate( "tv_maxrate", "8000", 0, "Max SourceTV spectator bandwidth rate allowed, 0 == unlimited" );
  22. static ConVar tv_relaypassword( "tv_relaypassword", "", FCVAR_NOTIFY | FCVAR_PROTECTED | FCVAR_DONTRECORD, "SourceTV password for relay proxies" );
  23. static ConVar tv_chattimelimit( "tv_chattimelimit", "8", 0, "Limits spectators to chat only every n seconds" );
  24. static ConVar tv_chatgroupsize( "tv_chatgroupsize", "0", 0, "Set the default chat group size" );
  25. //////////////////////////////////////////////////////////////////////
  26. // Construction/Destruction
  27. //////////////////////////////////////////////////////////////////////
  28. CHLTVClient::CHLTVClient(int slot, CBaseServer *pServer)
  29. {
  30. Clear();
  31. Assert( hltv == pServer );
  32. m_nClientSlot = slot;
  33. m_Server = pServer;
  34. m_pHLTV = dynamic_cast<CHLTVServer*>(pServer);
  35. m_nEntityIndex = m_pHLTV->GetHLTVSlot() + 1;
  36. m_nLastSendTick = 0;
  37. m_fLastSendTime = 0.0f;
  38. m_flLastChatTime = 0.0f;
  39. m_bNoChat = false;
  40. if ( tv_chatgroupsize.GetInt() > 0 )
  41. {
  42. Q_snprintf( m_szChatGroup, sizeof(m_szChatGroup), "group%d", slot%tv_chatgroupsize.GetInt() );
  43. }
  44. else
  45. {
  46. Q_strncpy( m_szChatGroup, "all", sizeof(m_szChatGroup) );
  47. }
  48. }
  49. CHLTVClient::~CHLTVClient()
  50. {
  51. }
  52. bool CHLTVClient::SendSignonData( void )
  53. {
  54. // check class table CRCs
  55. if ( m_nSendtableCRC != SendTable_GetCRC() )
  56. {
  57. Disconnect( "Server uses different class tables" );
  58. return false;
  59. }
  60. else
  61. {
  62. // use your class infos, CRC is correct
  63. SVC_ClassInfo classmsg( true, m_Server->serverclasses );
  64. m_NetChannel->SendNetMsg( classmsg );
  65. }
  66. return CBaseClient::SendSignonData();
  67. }
  68. bool CHLTVClient::ProcessClientInfo( CLC_ClientInfo *msg )
  69. {
  70. if ( !CBaseClient::ProcessClientInfo( msg ) )
  71. return false;
  72. return true;
  73. }
  74. bool CHLTVClient::ProcessMove(CLC_Move *msg)
  75. {
  76. // HLTV clients can't move
  77. return true;
  78. }
  79. bool CHLTVClient::ProcessListenEvents( CLC_ListenEvents *msg )
  80. {
  81. // HLTV clients can't subscribe to events, we just send them
  82. return true;
  83. }
  84. bool CHLTVClient::ProcessRespondCvarValue( CLC_RespondCvarValue *msg )
  85. {
  86. return true;
  87. }
  88. bool CHLTVClient::ProcessFileCRCCheck( CLC_FileCRCCheck *msg )
  89. {
  90. return true;
  91. }
  92. bool CHLTVClient::ProcessSaveReplay( CLC_SaveReplay *msg )
  93. {
  94. return true;
  95. }
  96. bool CHLTVClient::ProcessVoiceData(CLC_VoiceData *msg)
  97. {
  98. // HLTV clients can't speak
  99. return true;
  100. }
  101. void CHLTVClient::ConnectionClosing(const char *reason)
  102. {
  103. Disconnect ( (reason!=NULL)?reason:"Connection closing" );
  104. }
  105. void CHLTVClient::ConnectionCrashed(const char *reason)
  106. {
  107. DebuggerBreakIfDebugging_StagingOnly();
  108. Disconnect ( (reason!=NULL)?reason:"Connection lost" );
  109. }
  110. void CHLTVClient::PacketStart(int incoming_sequence, int outgoing_acknowledged)
  111. {
  112. // During connection, only respond if client sends a packet
  113. m_bReceivedPacket = true;
  114. }
  115. void CHLTVClient::PacketEnd()
  116. {
  117. }
  118. void CHLTVClient::FileRequested(const char *fileName, unsigned int transferID )
  119. {
  120. DevMsg( "CHLTVClient::FileRequested: %s.\n", fileName );
  121. m_NetChannel->DenyFile( fileName, transferID );
  122. }
  123. void CHLTVClient::FileDenied(const char *fileName, unsigned int transferID )
  124. {
  125. DevMsg( "CHLTVClient::FileDenied: %s.\n", fileName );
  126. }
  127. void CHLTVClient::FileReceived( const char *fileName, unsigned int transferID )
  128. {
  129. DevMsg( "CHLTVClient::FileReceived: %s.\n", fileName );
  130. }
  131. void CHLTVClient::FileSent(const char *fileName, unsigned int transferID )
  132. {
  133. }
  134. CClientFrame *CHLTVClient::GetDeltaFrame( int nTick )
  135. {
  136. return m_pHLTV->GetDeltaFrame( nTick );
  137. }
  138. bool CHLTVClient::ExecuteStringCommand( const char *pCommandString )
  139. {
  140. // first let the baseclass handle it
  141. if ( CBaseClient::ExecuteStringCommand( pCommandString ) )
  142. return true;
  143. if ( !pCommandString || !pCommandString[0] )
  144. return true;
  145. CCommand args;
  146. if ( !args.Tokenize( pCommandString ) )
  147. return true;
  148. const char *cmd = args[ 0 ];
  149. if ( !Q_stricmp( cmd, "spec_next" ) ||
  150. !Q_stricmp( cmd, "spec_prev" ) ||
  151. !Q_stricmp( cmd, "spec_mode" ) )
  152. {
  153. ClientPrintf("Camera settings can't be changed during a live broadcast.\n");
  154. return true;
  155. }
  156. if ( !Q_stricmp( cmd, "say" ) && args.ArgC() > 1 )
  157. {
  158. // if tv_chattimelimit = 0, chat is turned off
  159. if ( tv_chattimelimit.GetFloat() <= 0 )
  160. return true;
  161. if ( (m_flLastChatTime + tv_chattimelimit.GetFloat()) > net_time )
  162. return true;
  163. m_flLastChatTime = net_time;
  164. char chattext[128];
  165. Q_snprintf( chattext, sizeof(chattext), "%s : %s", GetClientName(), args[1] );
  166. m_pHLTV->BroadcastLocalChat( chattext, m_szChatGroup );
  167. return true;
  168. }
  169. else if ( !Q_strcmp( cmd, "tv_chatgroup" ) )
  170. {
  171. if ( args.ArgC() > 1 )
  172. {
  173. Q_strncpy( m_szChatGroup, args[1], sizeof(m_szChatGroup) );
  174. }
  175. else
  176. {
  177. ClientPrintf("Your current chat group is \"%s\"\n", m_szChatGroup );
  178. }
  179. return true;
  180. }
  181. else if ( !Q_strcmp( cmd, "status" ) )
  182. {
  183. int slots, proxies, clients;
  184. char gd[MAX_OSPATH];
  185. Q_FileBase( com_gamedir, gd, sizeof( gd ) );
  186. if ( m_pHLTV->IsMasterProxy() )
  187. {
  188. ClientPrintf("SourceTV Master \"%s\", delay %.0f\n",
  189. m_pHLTV->GetName(), m_pHLTV->GetDirector()->GetDelay() );
  190. }
  191. else // if ( m_Server->IsRelayProxy() )
  192. {
  193. if ( m_pHLTV->GetRelayAddress() )
  194. {
  195. ClientPrintf("SourceTV Relay \"%s\", connected.\n",
  196. m_pHLTV->GetName() );
  197. }
  198. else
  199. {
  200. ClientPrintf("SourceTV Relay \"%s\", not connect.\n", m_pHLTV->GetName() );
  201. }
  202. }
  203. ClientPrintf("IP %s:%i, Online %s, Version %i (%s)\n",
  204. net_local_adr.ToString( true ), m_pHLTV->GetUDPPort(),
  205. COM_FormatSeconds( m_pHLTV->GetOnlineTime() ), build_number(),
  206. #ifdef _WIN32
  207. "Win32" );
  208. #else
  209. "Linux" );
  210. #endif
  211. ClientPrintf("Game Time %s, Mod \"%s\", Map \"%s\", Players %i\n", COM_FormatSeconds( m_pHLTV->GetTime() ),
  212. gd, m_pHLTV->GetMapName(), m_pHLTV->GetNumPlayers() );
  213. m_pHLTV->GetLocalStats( proxies, slots, clients );
  214. ClientPrintf("Local Slots %i, Spectators %i, Proxies %i\n",
  215. slots, clients-proxies, proxies );
  216. m_pHLTV->GetGlobalStats( proxies, slots, clients);
  217. ClientPrintf("Total Slots %i, Spectators %i, Proxies %i\n",
  218. slots, clients-proxies, proxies);
  219. }
  220. else
  221. {
  222. DevMsg( "CHLTVClient::ExecuteStringCommand: Unknown command %s.\n", pCommandString );
  223. }
  224. return true;
  225. }
  226. bool CHLTVClient::ShouldSendMessages( void )
  227. {
  228. if ( !IsActive() )
  229. {
  230. // during signon behave like normal client
  231. return CBaseClient::ShouldSendMessages();
  232. }
  233. // HLTV clients use snapshot rate used by HLTV server, not given by HLTV client
  234. // if the reliable message overflowed, drop the client
  235. if ( m_NetChannel->IsOverflowed() )
  236. {
  237. m_NetChannel->Reset();
  238. Disconnect ("%s overflowed reliable buffer\n", m_Name );
  239. return false;
  240. }
  241. // send a packet if server has a new tick we didn't already send
  242. bool bSendMessage = ( m_nLastSendTick != m_Server->m_nTickCount );
  243. // send a packet at least every 2 seconds
  244. if ( !bSendMessage && (m_fLastSendTime + 2.0f) < net_time )
  245. {
  246. bSendMessage = true; // force sending a message even if server didn't update
  247. }
  248. if ( bSendMessage && !m_NetChannel->CanPacket() )
  249. {
  250. // we would like to send a message, but bandwidth isn't available yet
  251. // in HLTV we don't send choke information, doesn't matter
  252. bSendMessage = false;
  253. }
  254. return bSendMessage;
  255. }
  256. void CHLTVClient::SpawnPlayer( void )
  257. {
  258. // set view entity
  259. SVC_SetView setView( m_pHLTV->m_nViewEntity );
  260. SendNetMsg( setView );
  261. m_pHLTV->BroadcastLocalTitle( this );
  262. m_flLastChatTime = net_time;
  263. CBaseClient::SpawnPlayer();
  264. }
  265. void CHLTVClient::SetRate(int nRate, bool bForce )
  266. {
  267. if ( !bForce )
  268. {
  269. if ( m_bIsHLTV )
  270. {
  271. // allow higher bandwidth rates for HLTV proxies
  272. nRate = clamp( nRate, MIN_RATE, MAX_RATE );
  273. }
  274. else if ( tv_maxrate.GetInt() > 0 )
  275. {
  276. // restrict rate for normal clients to hltv_maxrate
  277. nRate = clamp( nRate, MIN_RATE, tv_maxrate.GetInt() );
  278. }
  279. }
  280. CBaseClient::SetRate( nRate, bForce );
  281. }
  282. void CHLTVClient::SetUpdateRate(int udpaterate, bool bForce)
  283. {
  284. // for HLTV clients ignore update rate settings, speed is tv_snapshotrate
  285. m_fSnapshotInterval = 1.0f / 100.0f;
  286. }
  287. bool CHLTVClient::ProcessSetConVar(NET_SetConVar *msg)
  288. {
  289. if ( !CBaseClient::ProcessSetConVar( msg ) )
  290. return false;
  291. // if this is the first time we get user settings, check password etc
  292. if ( m_nSignonState == SIGNONSTATE_CONNECTED )
  293. {
  294. const char *checkpwd = NULL;
  295. m_bIsHLTV = m_ConVars->GetInt( "tv_relay", 0 ) != 0;
  296. if ( m_bIsHLTV )
  297. {
  298. // if the connecting client is a TV relay, check the password
  299. checkpwd = tv_relaypassword.GetString();
  300. if ( checkpwd && checkpwd[0] && Q_stricmp( checkpwd, "none") )
  301. {
  302. if ( Q_stricmp( m_szPassword, checkpwd ) )
  303. {
  304. Disconnect("Bad relay password");
  305. return false;
  306. }
  307. }
  308. }
  309. else
  310. {
  311. // if client is a normal spectator, check if we can to forward him to other relays
  312. if ( m_pHLTV->DispatchToRelay( this ) )
  313. {
  314. return false;
  315. }
  316. // if client stays here, check the normal password
  317. checkpwd = m_pHLTV->GetPassword();
  318. if ( checkpwd )
  319. {
  320. if ( Q_stricmp( m_szPassword, checkpwd ) )
  321. {
  322. Disconnect("Bad spectator password");
  323. return false;
  324. }
  325. }
  326. // check if server is LAN only
  327. if ( !m_pHLTV->CheckIPRestrictions( m_NetChannel->GetRemoteAddress(), PROTOCOL_HASHEDCDKEY ) )
  328. {
  329. Disconnect( "SourceTV server is restricted to local spectators (class C).\n" );
  330. return false;
  331. }
  332. }
  333. }
  334. return true;
  335. }
  336. void CHLTVClient::UpdateUserSettings()
  337. {
  338. // set voice loopback
  339. m_bNoChat = m_ConVars->GetInt( "tv_nochat", 0 ) != 0;
  340. CBaseClient::UpdateUserSettings();
  341. }
  342. void CHLTVClient::SendSnapshot( CClientFrame * pFrame )
  343. {
  344. VPROF_BUDGET( "CHLTVClient::SendSnapshot", "HLTV" );
  345. ALIGN4 byte buf[NET_MAX_PAYLOAD] ALIGN4_POST;
  346. bf_write msg( "CHLTVClient::SendSnapshot", buf, sizeof(buf) );
  347. // if we send a full snapshot (no delta-compression) before, wait until client
  348. // received and acknowledge that update. don't spam client with full updates
  349. if ( m_pLastSnapshot == pFrame->GetSnapshot() )
  350. {
  351. // never send the same snapshot twice
  352. m_NetChannel->Transmit();
  353. return;
  354. }
  355. if ( m_nForceWaitForTick > 0 )
  356. {
  357. // just continue transmitting reliable data
  358. Assert( !m_bFakePlayer ); // Should never happen
  359. m_NetChannel->Transmit();
  360. return;
  361. }
  362. CClientFrame *pDeltaFrame = GetDeltaFrame( m_nDeltaTick ); // NULL if delta_tick is not found
  363. CHLTVFrame *pLastFrame = (CHLTVFrame*) GetDeltaFrame( m_nLastSendTick );
  364. if ( pLastFrame )
  365. {
  366. // start first frame after last send
  367. pLastFrame = (CHLTVFrame*) pLastFrame->m_pNext;
  368. }
  369. // add all reliable messages between ]lastframe,currentframe]
  370. // add all tempent & sound messages between ]lastframe,currentframe]
  371. while ( pLastFrame && pLastFrame->tick_count <= pFrame->tick_count )
  372. {
  373. m_NetChannel->SendData( pLastFrame->m_Messages[HLTV_BUFFER_RELIABLE], true );
  374. if ( pDeltaFrame )
  375. {
  376. // if we send entities delta compressed, also send unreliable data
  377. m_NetChannel->SendData( pLastFrame->m_Messages[HLTV_BUFFER_UNRELIABLE], false );
  378. }
  379. pLastFrame = (CHLTVFrame*) pLastFrame->m_pNext;
  380. }
  381. // now create client snapshot packet
  382. // send tick time
  383. NET_Tick tickmsg( pFrame->tick_count, host_frametime_unbounded, host_frametime_stddeviation );
  384. tickmsg.WriteToBuffer( msg );
  385. // Update shared client/server string tables. Must be done before sending entities
  386. m_Server->m_StringTables->WriteUpdateMessage( NULL, GetMaxAckTickCount(), msg );
  387. // TODO delta cache whole snapshots, not just packet entities. then use net_Align
  388. // send entity update, delta compressed if deltaFrame != NULL
  389. m_Server->WriteDeltaEntities( this, pFrame, pDeltaFrame, msg );
  390. // write message to packet and check for overflow
  391. if ( msg.IsOverflowed() )
  392. {
  393. if ( !pDeltaFrame )
  394. {
  395. // if this is a reliable snapshot, drop the client
  396. Disconnect( "ERROR! Reliable snapshot overflow." );
  397. return;
  398. }
  399. else
  400. {
  401. // unreliable snapshots may be dropped
  402. ConMsg ("WARNING: msg overflowed for %s\n", m_Name);
  403. msg.Reset();
  404. }
  405. }
  406. // remember this snapshot
  407. m_pLastSnapshot = pFrame->GetSnapshot();
  408. m_nLastSendTick = pFrame->tick_count;
  409. // Don't send the datagram to fakeplayers
  410. if ( m_bFakePlayer )
  411. {
  412. m_nDeltaTick = pFrame->tick_count;
  413. return;
  414. }
  415. bool bSendOK;
  416. // is this is a full entity update (no delta) ?
  417. if ( !pDeltaFrame )
  418. {
  419. // transmit snapshot as reliable data chunk
  420. bSendOK = m_NetChannel->SendData( msg );
  421. bSendOK = bSendOK && m_NetChannel->Transmit();
  422. // remember this tickcount we send the reliable snapshot
  423. // so we can continue sending other updates if this has been acknowledged
  424. m_nForceWaitForTick = pFrame->tick_count;
  425. }
  426. else
  427. {
  428. // just send it as unreliable snapshot
  429. bSendOK = m_NetChannel->SendDatagram( &msg ) > 0;
  430. }
  431. if ( !bSendOK )
  432. {
  433. Disconnect( "ERROR! Couldn't send snapshot." );
  434. }
  435. }