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.

509 lines
13 KiB

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