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.

742 lines
20 KiB

  1. //========= Copyright (c) Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "client_pch.h"
  8. #include "cl_demo.h"
  9. #include "cl_broadcast.h"
  10. #include "baseautocompletefilelist.h"
  11. #include "demostreamhttp.h"
  12. #include "dt_common_eng.h"
  13. #include "matchmaking/imatchframework.h"
  14. extern ConVar demo_debug;
  15. extern CNetworkStringTableContainer *networkStringTableContainerClient;
  16. extern bool IsControlCommand( unsigned char cmd );
  17. extern ConVar tv_playcast_delay_prediction;
  18. extern ConVar tv_playcast_max_rcvage;
  19. CBroadcastPlayer s_ClientBroadcastPlayer;
  20. CBroadcastPlayer::CBroadcastPlayer() :
  21. m_DemoStrider( NULL )
  22. {
  23. m_bPlayingBack = false;
  24. m_flPlaybackRateModifier = 1.0f;
  25. m_nSkipToTick = -1;
  26. m_flAutoResumeTime = 0.0f;
  27. m_bPlaybackPaused = false;
  28. m_nPacketTick = 0;
  29. m_nStartHostTick = 0;
  30. m_nStreamStartTick = 0;
  31. m_bInterpolateView = false;
  32. m_DemoStream.SetClient( this );
  33. m_nStreamState = STREAM_STOP;
  34. m_bPacketReadSuspended = false;
  35. m_dResyncTimerStart = 0;
  36. m_bIgnoreDemoStopCommand = false;
  37. }
  38. CBroadcastPlayer::~CBroadcastPlayer()
  39. {
  40. if ( m_bPlayingBack )
  41. {
  42. StopPlayback();
  43. if ( g_ClientDLL )
  44. {
  45. g_ClientDLL->OnDemoPlaybackStop();
  46. }
  47. }
  48. }
  49. IDemoStream * CBroadcastPlayer::GetDemoStream()
  50. {
  51. return &m_DemoStream;
  52. }
  53. void CBroadcastPlayer::StartStreaming( const char *url, const char *options )
  54. {
  55. if ( !options )
  56. options = "";
  57. m_bSkipSync = ( NULL != V_strstr( options, "c" ) ); // playback akamai cached content (sync isn't cached)
  58. m_bIgnoreDemoStopCommand = ( NULL != V_strstr( options, "b" ) );
  59. int nPlayFromFragment = 0;
  60. if ( const char *pFrame = V_strstr( options, "f" ) )
  61. nPlayFromFragment = V_atoi( pFrame + 1 );
  62. else if ( NULL != V_strstr( options, "a" ) )
  63. nPlayFromFragment = 1;
  64. StopPlayback();
  65. if ( g_pClientDemoPlayer )
  66. g_pClientDemoPlayer->StopPlayback();
  67. demoplayer = this;
  68. if ( CDemoPlaybackParameters_t *pParams = const_cast< CDemoPlaybackParameters_t * >( GetDemoPlaybackParameters() ) )
  69. {
  70. // the format of the id is MatchId# where # is a one-digit GoTv instance index
  71. pParams->m_uiLiveMatchID = CDemoStreamHttp::GetStreamId( url ).m_nMatchId;
  72. }
  73. if ( StartStreamingInternal() )
  74. {
  75. g_ClientDLL->OnDemoPlaybackStart( url );
  76. if ( m_bSkipSync )
  77. {
  78. int nGuessedStartFragment = Max( 1, nPlayFromFragment );
  79. m_DemoStream.StartStreamingCached( url, nGuessedStartFragment );
  80. }
  81. else
  82. {
  83. if ( nPlayFromFragment > 0 )
  84. m_DemoStream.StartStreaming( url, CDemoStreamHttp::SyncParams_t( nPlayFromFragment ) );
  85. else
  86. m_DemoStream.StartStreaming( url );
  87. }
  88. }
  89. }
  90. bool CBroadcastPlayer::OnEngineGotvSyncPacket( const CEngineGotvSyncPacket *pPkt )
  91. {
  92. return m_DemoStream.OnEngineGotvSyncPacket( pPkt );
  93. }
  94. bool CBroadcastPlayer::StartStreamingInternal()
  95. {
  96. SCR_BeginLoadingPlaque();
  97. // Disconnect from server or stop running one
  98. int oldn = GetBaseLocalClient().demonum;
  99. GetBaseLocalClient().demonum = -1;
  100. Host_Disconnect( false );
  101. // set current demo player to client demo player
  102. // disconnect before loading demo, to avoid sometimes loading into game instead of demo
  103. GetBaseLocalClient().Disconnect( false );
  104. GetBaseLocalClient().demonum = oldn;
  105. GetBaseLocalClient().m_nSignonState = SIGNONSTATE_CONNECTED;
  106. ResyncDemoClock();
  107. // create a fake channel with a NULL address (no encryption keys in demos)
  108. GetBaseLocalClient().m_NetChannel = NET_CreateNetChannel( NS_CLIENT, NULL, "BROADCAST", &GetBaseLocalClient(), NULL, false );
  109. if ( !GetBaseLocalClient().m_NetChannel )
  110. {
  111. ConMsg( "Broadcast Player: failed to create demo net channel\n" );
  112. m_DemoStream.StopStreaming();
  113. GetBaseLocalClient().demonum = -1; // stop demo loop
  114. Host_Disconnect( true );
  115. SCR_EndLoadingPlaque();
  116. return false;
  117. }
  118. GetBaseLocalClient().m_NetChannel->SetTimeout( -1.0f ); // never timeout
  119. m_bPlayingBack = true;
  120. m_bPlaybackPaused = false;
  121. m_flAutoResumeTime = 0.0f;
  122. m_flPlaybackRateModifier = 1.0f;
  123. m_bInterpolateView = false;
  124. m_nStartHostTick = -1;
  125. m_nStreamFragment = -1;
  126. m_nStreamStartTick = -1;
  127. V_memset( &m_DemoPacket, 0, sizeof( m_DemoPacket ) );
  128. // setup demo packet data buffer
  129. m_DemoPacket.data = NULL;
  130. m_DemoPacket.from.SetAddrType( NSAT_NETADR );
  131. m_DemoPacket.from.m_adr.SetType( NA_LOOPBACK );
  132. m_DemoStrider.Set( NULL );
  133. GetBaseLocalClient().chokedcommands = 0;
  134. GetBaseLocalClient().lastoutgoingcommand = -1;
  135. GetBaseLocalClient().m_flNextCmdTime = net_time;
  136. m_dResyncTimerStart = Plat_FloatTime();
  137. m_nStreamState = STREAM_SYNC;
  138. return true;
  139. }
  140. bool CBroadcastPlayer::OnDemoStreamRestarting()
  141. {
  142. return StartStreamingInternal();
  143. }
  144. void CBroadcastPlayer::ResyncStream()
  145. {
  146. if ( Plat_FloatTime() - m_dResyncTimerStart > m_DemoStream.GetBroadcastKeyframeInterval() )
  147. {
  148. m_dResyncTimerStart = Plat_FloatTime();
  149. DevMsg( "Stream Re-sync @%d...\n", m_nStreamFragment );
  150. m_nStreamFragment++; // resync from the next fragment
  151. m_nStreamState = STREAM_SYNC;
  152. m_DemoStream.Resync( );
  153. }
  154. }
  155. void CBroadcastPlayer::OnDemoStreamStart( const DemoStreamReference_t &start, int nResync )
  156. {
  157. m_dResyncTimerStart = Plat_FloatTime();
  158. m_nStreamState = nResync ? STREAM_FULLFRAME : STREAM_START;
  159. m_nStartHostTick = host_tickcount;
  160. m_nStreamStartTick = start.nTick;
  161. m_nStreamFragment = start.nFragment;
  162. }
  163. void CBroadcastPlayer::OnDemoStreamStop()
  164. {
  165. if ( m_bPlayingBack )
  166. {
  167. m_bPlayingBack = false;
  168. }
  169. m_flAutoResumeTime = 0.0f;
  170. m_flPlaybackRateModifier = 1.0f;
  171. m_DemoPacket.data = NULL;
  172. m_DemoStrider.Set( NULL );
  173. m_nStreamState = STREAM_STOP;
  174. if ( g_pMatchFramework )
  175. {
  176. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnDemoFileEndReached" ) );
  177. }
  178. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  179. {
  180. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  181. GetBaseLocalClient().Disconnect( true );
  182. }
  183. demoplayer = g_pClientDemoPlayer;
  184. g_ClientDLL->OnDemoPlaybackStop();
  185. }
  186. CON_COMMAND( playcast, "Play a broadcast" )
  187. {
  188. if ( args.ArgC() < 2 )
  189. {
  190. ConMsg( "Usage: playcast <url>\n" );
  191. return;
  192. }
  193. if ( !net_time && !NET_IsMultiplayer() )
  194. {
  195. ConMsg( "Deferring playcast command!\n" );
  196. return;
  197. }
  198. s_ClientBroadcastPlayer.StartStreaming( args[ 1 ], args.ArgC() >= 3 ? args[2] : "" );
  199. }
  200. void CBroadcastPlayer::PausePlayback( float seconds )
  201. {
  202. m_bPlaybackPaused = true;
  203. if ( seconds > 0.0f )
  204. {
  205. // Use true clock since everything else is frozen
  206. m_flAutoResumeTime = Sys_FloatTime() + seconds;
  207. }
  208. else
  209. {
  210. m_flAutoResumeTime = 0.0f;
  211. }
  212. }
  213. void CBroadcastPlayer::ResumePlayback()
  214. {
  215. m_bPlaybackPaused = false;
  216. m_flAutoResumeTime = 0.0f;
  217. }
  218. void CBroadcastPlayer::StopPlayback()
  219. {
  220. m_nStreamState = STREAM_STOP;
  221. m_DemoStream.StopStreaming();
  222. g_ClientDLL->OnDemoPlaybackStop();
  223. }
  224. bool CBroadcastPlayer::PreparePacket( void )
  225. {
  226. Assert( !m_DemoStrider.Get() || ( m_DemoStrider.Get() >= m_DemoBuffer->Base() && m_DemoStrider.Get() <= m_DemoBuffer->End() ) );
  227. double dTime = Plat_FloatTime();
  228. if ( !m_DemoStrider.Get() || m_DemoStrider.Get() >= m_DemoBuffer->End() )
  229. {
  230. // get the next packet
  231. switch ( m_nStreamState )
  232. {
  233. case STREAM_START:
  234. if ( CDemoStreamHttp::Buffer_t *pBuffer = m_DemoStream.GetStreamSignupBuffer() )
  235. {
  236. SetDemoBuffer( pBuffer );
  237. m_nStreamState = STREAM_FULLFRAME;
  238. if ( tv_playcast_delay_prediction.GetBool() )
  239. {
  240. m_nStreamState = STREAM_MAP_LOADED;
  241. }
  242. }
  243. else
  244. return false; // not implemented yet: the signup buffer isn't precached
  245. break;
  246. case STREAM_MAP_LOADED:
  247. {// recompute the start frame
  248. DemoStreamReference_t startRef = m_DemoStream.GetStreamStartReference( true );
  249. if ( demo_debug.GetBool() )
  250. Msg( "playcast: Adjusting fragment %d->%d, tick %d->%d\n", m_nStreamFragment, startRef.nFragment, m_nStreamStartTick, startRef.nTick );
  251. m_nStartHostTick = host_tickcount - startRef.nSkipTicks;
  252. m_nStreamStartTick = startRef.nTick;
  253. m_nStreamFragment = startRef.nFragment;
  254. m_DemoStream.BeginBuffering( m_nStreamFragment );
  255. m_nStreamState = STREAM_WAITING_FOR_KEYFRAME;
  256. m_dResyncTimerStart = m_dDelayedPrecacheTimeStart = dTime;
  257. return false; // the data isn't ready yet
  258. }
  259. break;
  260. case STREAM_WAITING_FOR_KEYFRAME:
  261. if ( m_dDelayedPrecacheTimeStart + tv_playcast_max_rcvage.GetFloat() < dTime )
  262. {
  263. ResyncStream(); // try to resync when the resync timeout passes; maybe the full fragment is about to come in
  264. return false;
  265. }
  266. if ( CDemoStreamHttp::Buffer_t *pBuffer = m_DemoStream.GetFragmentBuffer( m_nStreamFragment, CDemoStreamHttp::FRAGMENT_FULL ) )
  267. {
  268. // is the delta precached?
  269. if ( m_DemoStream.GetFragmentBuffer( m_nStreamFragment, CDemoStreamHttp::FRAGMENT_DELTA ) )
  270. {// the data is ready
  271. if ( demo_debug.GetBool() )
  272. Msg( "playcast: Fragment %d keyframe and delta frames ready, delayed precache took %.2f sec\n", m_nStreamFragment, dTime - m_dDelayedPrecacheTimeStart );
  273. SetDemoBuffer( pBuffer );
  274. m_nStreamState = STREAM_FULLFRAME;
  275. return true;
  276. }
  277. }
  278. return false;
  279. case STREAM_FULLFRAME:
  280. m_DemoStream.ReleaseFragment( m_nStreamFragment - 1 );
  281. if ( CDemoStreamHttp::Buffer_t *pBuffer = m_DemoStream.GetFragmentBuffer( m_nStreamFragment, CDemoStreamHttp::FRAGMENT_FULL ) )
  282. {
  283. if ( demo_debug.GetBool() )
  284. Msg( "playcast: Play keyframe Fragment %d\n", m_nStreamFragment );
  285. SetDemoBuffer( pBuffer );
  286. m_nStreamState = STREAM_BEFORE_DELTAFRAMES;
  287. }
  288. else
  289. {
  290. ResyncStream();
  291. return false;
  292. }
  293. break;
  294. case STREAM_BEFORE_DELTAFRAMES:
  295. if ( g_ClientDLL )
  296. g_ClientDLL->OnDemoPlaybackTimeJump();
  297. m_nStreamState = STREAM_DELTAFRAMES;
  298. // fall through and start streaming deltaframes now
  299. case STREAM_DELTAFRAMES:
  300. m_DemoStream.ReleaseFragment( m_nStreamFragment - 1 );
  301. if ( CDemoStreamHttp::Buffer_t *pBuffer = m_DemoStream.GetFragmentBuffer( m_nStreamFragment, CDemoStreamHttp::FRAGMENT_DELTA ) )
  302. {
  303. if ( demo_debug.GetBool() )
  304. Msg( "playcast: Play delta Fragment %d\n", m_nStreamFragment );
  305. SetDemoBuffer( pBuffer );
  306. m_nStreamState = STREAM_DELTAFRAMES;
  307. m_nStreamFragment++; // TODO : count the ticks, not fragments
  308. for ( int i = 1; i <= 4; ++i )
  309. m_DemoStream.RequestFragment( m_nStreamFragment + i, CDemoStreamHttp::FRAGMENT_DELTA );
  310. }
  311. else
  312. {
  313. // we don't have the delta... we can request the full fragment and restart, or we could do a partial re-sync (we don't need to reload the level, hence the partial)
  314. ResyncStream();
  315. return false;
  316. }
  317. break;
  318. }
  319. }
  320. m_dResyncTimerStart = dTime;
  321. return true;
  322. }
  323. void CBroadcastPlayer::ReadCmdHeader( unsigned char& cmd, int& tick, int &nPlayerSlot )
  324. {
  325. if ( !m_DemoStrider.Get() || m_DemoStrider.Get() + 6 > m_DemoBuffer->End() )
  326. {
  327. cmd = dem_stop;
  328. tick = m_nPacketTick;
  329. nPlayerSlot = 0;
  330. }
  331. else
  332. {
  333. cmd = m_DemoStrider.StrideUnaligned<uint8>();
  334. tick = m_DemoStrider.StrideUnaligned<int32>();
  335. nPlayerSlot = m_DemoStrider.StrideUnaligned<uint8>();
  336. if ( demo_debug.GetInt() > 2 )
  337. {
  338. if ( cmd == dem_packet )
  339. DevMsg( "playcast: Packet tick %d size %u\n", tick, *( uint32* )m_DemoStrider.Get() );
  340. }
  341. }
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Read in next demo message and send to local client over network channel, if it's time.
  345. // Output : bool
  346. //-----------------------------------------------------------------------------
  347. netpacket_t *CBroadcastPlayer::ReadPacket( void )
  348. {
  349. int tick = 0;
  350. byte cmd = dem_signon;
  351. uint8* curpos = NULL;
  352. m_DemoStream.Update();
  353. if ( m_DemoStream.IsIdle() )
  354. {
  355. m_bPlayingBack = false;
  356. Host_EndGame( true, "Tried to read a demo message with no demo file\n" );
  357. return NULL;
  358. }
  359. // dropped: timedemo
  360. // If game is still shutting down, then don't read any demo messages from file quite yet
  361. if ( HostState_IsGameShuttingDown() )
  362. {
  363. return NULL;
  364. }
  365. Assert( IsPlayingBack() );
  366. // External editor has paused playback
  367. if ( CheckPausedPlayback() )
  368. return NULL;
  369. if ( m_nStreamState <= STREAM_SYNC )
  370. return NULL; // waiting for data
  371. // dropped: highlights
  372. bool bStopReading = false;
  373. while ( !bStopReading )
  374. {
  375. if ( !PreparePacket() )
  376. return NULL; // packet is not ready
  377. curpos = m_DemoStrider.Get();
  378. int nPlayerSlot = 0;
  379. ReadCmdHeader( cmd, tick, nPlayerSlot );
  380. tick -= m_nStreamStartTick;
  381. m_nPacketTick = tick;
  382. // always read control commands
  383. if ( !IsControlCommand( cmd ) )
  384. {
  385. int playbacktick = GetPlaybackTick();
  386. if ( GetBaseLocalClient().IsActive() &&
  387. ( tick > playbacktick ) && !IsSkipping() )
  388. {
  389. // is not time yet
  390. bStopReading = true;
  391. }
  392. if ( bStopReading )
  393. {
  394. demoaction->Update( false, playbacktick, TICKS_TO_TIME( playbacktick ) );
  395. m_DemoStrider.Set( curpos ); // go back to start of current demo command
  396. return NULL; // Not time yet, dont return packet data.
  397. }
  398. }
  399. // COMMAND HANDLERS
  400. switch ( cmd )
  401. {
  402. case dem_synctick: // currently not used, but may need to rethink it in the future
  403. ResyncDemoClock();
  404. break;
  405. case dem_stop:
  406. if ( !m_bIgnoreDemoStopCommand )
  407. {
  408. if ( demo_debug.GetBool() )
  409. {
  410. Msg( "playcast: %d dem_stop\n", tick );
  411. }
  412. if ( g_pMatchFramework )
  413. {
  414. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnDemoFileEndReached" ) );
  415. }
  416. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  417. {
  418. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  419. GetBaseLocalClient().Disconnect( true );
  420. }
  421. return NULL;
  422. }
  423. break;
  424. case dem_consolecmd: // currently not used, not tested
  425. {
  426. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nPlayerSlot );
  427. if ( const char *command = m_DemoStrider.StrideString( m_DemoBuffer->End() ) )
  428. {
  429. if ( demo_debug.GetBool() )
  430. {
  431. Msg( "playcast: %d dem_consolecmd [%s]\n", tick, command );
  432. }
  433. Cbuf_AddText( Cbuf_GetCurrentPlayer(), command, kCommandSrcDemoFile );
  434. Cbuf_Execute();
  435. }
  436. }
  437. break;
  438. case dem_datatables:
  439. {
  440. if ( demo_debug.GetBool() )
  441. {
  442. Msg( "playcast: %d dem_datatables\n", tick );
  443. }
  444. // support for older engine demos
  445. bf_read buf( m_DemoStrider.Get(), GetReminingStrideLength() );
  446. if ( !DataTable_LoadDataTablesFromBuffer( &buf, m_DemoStream.GetDemoProtocol() ) )
  447. {
  448. Host_Error( "Error parsing network data tables during demo playback." );
  449. }
  450. m_DemoStrider.Stride<uint8>( buf.GetNumBytesRead() );
  451. }
  452. break;
  453. case dem_stringtables:
  454. {
  455. bf_read buf( m_DemoStrider.Get(), GetReminingStrideLength() );
  456. if ( !networkStringTableContainerClient->ReadStringTables( buf ) )
  457. {
  458. Host_Error( "Error parsing string tables during demo playback." );
  459. }
  460. m_DemoStrider.Stride<uint8>( buf.GetNumBytesRead() );
  461. }
  462. break;
  463. case dem_usercmd:
  464. {
  465. Assert( !"Not used, Not tested - probably doesn't work correctly!" );
  466. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nPlayerSlot );
  467. if ( demo_debug.GetBool() )
  468. {
  469. Msg( "playcast: %d dem_usercmd\n", tick );
  470. }
  471. int nCmdNumber = m_DemoStrider.StrideUnaligned<int32>(), nUserCmdLength = m_DemoStrider.StrideUnaligned<int32>();
  472. if ( m_DemoStrider.Get() + nUserCmdLength > m_DemoBuffer->End() )
  473. {
  474. Warning( "Invalid user cmd length %d\n", nUserCmdLength );
  475. m_DemoStrider.Set( m_DemoBuffer->End() ); // invalid user cmd length
  476. }
  477. else
  478. {
  479. bf_read msg( "ReadUserCmd", m_DemoStrider.Stride<uint8>( nUserCmdLength ), nUserCmdLength );
  480. g_ClientDLL->DecodeUserCmdFromBuffer( nPlayerSlot, msg, nCmdNumber );
  481. // Note, we need to have the current outgoing sequence correct so we can do prediction
  482. // correctly during playback
  483. GetBaseLocalClient().lastoutgoingcommand = nCmdNumber;
  484. }
  485. }
  486. break;
  487. case dem_customdata:
  488. {
  489. int iCallbackIndex = m_DemoStrider.StrideUnaligned<int32>(), nSize = m_DemoStrider.StrideUnaligned<int32>();
  490. m_DemoStrider.Stride<uint8>( nSize );
  491. Warning( "Unable to decode custom demo data %d bytes, callback %d not supported.\n", nSize, iCallbackIndex );
  492. }
  493. break;
  494. default:
  495. {
  496. bStopReading = true;
  497. if ( IsSkipping() )
  498. {
  499. // adjust playback host_tickcount when skipping
  500. m_nStartHostTick = host_tickcount - tick;
  501. }
  502. }
  503. break;
  504. }
  505. }
  506. if ( cmd == dem_packet )
  507. {
  508. // remember last frame we read a dem_packet update
  509. //m_nTimeDemoCurrentFrame = host_framecount;
  510. }
  511. //int inseq, outseqack, outseq = 0;
  512. // we're skipping cmd info in this protocol: see CHLTVBroadcast::WriteMessages, it doesn't write seq
  513. //GetBaseLocalClient().m_NetChannel->SetSequenceData( outseq, inseq, outseqack );
  514. int length = m_DemoStrider.StrideUnaligned< int32 >();
  515. if ( length < 0 || uint( length ) > GetReminingStrideLength() )
  516. {
  517. Warning( "Invalid broadcast packet size %d in fragment buffer size %d\n", length, m_DemoBuffer->m_nSize );
  518. StrideDemoPacket();
  519. return NULL;
  520. }
  521. else
  522. {
  523. StrideDemoPacket( length );
  524. if ( demo_debug.GetInt() > 2 )
  525. {
  526. Msg( "playcast: %d network packet [%d]\n", tick, length );
  527. }
  528. if ( length > 0 )
  529. {
  530. m_DemoPacket.received = realtime;
  531. if ( demo_debug.GetInt() > 2 )
  532. {
  533. Msg( "playcast: Demo message, tick %i, %i bytes\n", GetPlaybackTick(), length );
  534. }
  535. }
  536. // Try and jump ahead one frame
  537. m_bInterpolateView = true; //ParseAheadForInterval( tick, 8 ); TODO: NOT IMPLEMENTED, camera transitions will be jerky
  538. // ConMsg( "Reading message for %i : %f skip %i\n", m_nFrameCount, fElapsedTime, forceskip ? 1 : 0 );
  539. return &m_DemoPacket;
  540. }
  541. }
  542. void CBroadcastPlayer::SetDemoBuffer( CDemoStreamHttp::Buffer_t * pBuffer )
  543. {
  544. m_DemoStrider.Set( pBuffer->Base() );
  545. m_DemoBuffer = pBuffer;
  546. m_DemoPacket.received = realtime;
  547. m_DemoPacket.data = NULL;
  548. m_DemoPacket.size = 0;
  549. m_DemoPacket.message.StartReading( NULL, 0 ); // message must be set up later
  550. }
  551. void CBroadcastPlayer::StrideDemoPacket( int nLength )
  552. {
  553. m_DemoPacket.data = m_DemoStrider.Stride<unsigned char>( nLength );
  554. m_DemoPacket.size = nLength;
  555. m_DemoPacket.message.StartReading( m_DemoPacket.data, m_DemoPacket.size );
  556. }
  557. void CBroadcastPlayer::StrideDemoPacket( )
  558. {
  559. StrideDemoPacket( GetReminingStrideLength() );
  560. }
  561. uint CBroadcastPlayer::GetReminingStrideLength()
  562. {
  563. return m_DemoBuffer->End() - m_DemoStrider.Get();
  564. }
  565. CDemoPlaybackParameters_t Helper_GetBroadcastPlayerDemoPlaybackParameters()
  566. {
  567. CDemoPlaybackParameters_t params = {};
  568. params.m_bPlayingLiveRemoteBroadcast = true;
  569. params.m_numRoundStop = 999;
  570. return params;
  571. }
  572. CDemoPlaybackParameters_t const * CBroadcastPlayer::GetDemoPlaybackParameters()
  573. {
  574. static CDemoPlaybackParameters_t s_params = Helper_GetBroadcastPlayerDemoPlaybackParameters();
  575. return &s_params;
  576. }
  577. void CBroadcastPlayer::SetPacketReadSuspended( bool bSuspendPacketReading )
  578. {
  579. if ( m_bPacketReadSuspended == bSuspendPacketReading )
  580. return; // same state
  581. m_bPacketReadSuspended = bSuspendPacketReading;
  582. if ( !m_bPacketReadSuspended )
  583. ResyncDemoClock(); // Make sure we resync demo clock when we resume packet reading
  584. }
  585. int CBroadcastPlayer::GetPlaybackStartTick( void )
  586. {
  587. return m_nStartHostTick;
  588. }
  589. int CBroadcastPlayer::GetPlaybackTick( void )
  590. {
  591. return host_tickcount - m_nStartHostTick;
  592. }
  593. int CBroadcastPlayer::GetPlaybackDeltaTick( void )
  594. {
  595. return host_tickcount - m_nStartHostTick;
  596. }
  597. int CBroadcastPlayer::GetPacketTick()
  598. {
  599. return m_nPacketTick;
  600. }
  601. void CBroadcastPlayer::ResyncDemoClock()
  602. {
  603. m_nStartHostTick = host_tickcount;
  604. m_nPreviousTick = m_nStartHostTick;
  605. }
  606. bool CBroadcastPlayer::CheckPausedPlayback( void )
  607. {
  608. if ( m_bPacketReadSuspended )
  609. return true; // When packet reading is suspended it trumps all other states
  610. return m_bPlaybackPaused;
  611. }
  612. float CBroadcastPlayer::GetPlaybackTimeScale()
  613. {
  614. return m_flPlaybackRateModifier;
  615. }
  616. void CBroadcastPlayer::SetPlaybackTimeScale( float timescale )
  617. {
  618. m_flPlaybackRateModifier = timescale;
  619. }
  620. bool CBroadcastPlayer::IsPlaybackPaused( void ) const
  621. {
  622. return m_bPlayingBack && m_bPlaybackPaused;
  623. }