diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /replay/cl_replaycontext.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'replay/cl_replaycontext.cpp')
| -rw-r--r-- | replay/cl_replaycontext.cpp | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/replay/cl_replaycontext.cpp b/replay/cl_replaycontext.cpp new file mode 100644 index 0000000..441d5ea --- /dev/null +++ b/replay/cl_replaycontext.cpp @@ -0,0 +1,421 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "cl_replaycontext.h" +#include "replaysystem.h" +#include "replay/iclientreplay.h" +#include "replay/ireplaymovierenderer.h" +#include "replay/shared_defs.h" +#include "cl_replaymanager.h" +#include "replay_dbg.h" +#include "baserecordingsessionmanager.h" +#include "baserecordingsessionblockmanager.h" +#include "cl_replaymoviemanager.h" +#include "cl_screenshotmanager.h" +#include "cl_performancemanager.h" +#include "cl_sessionblockdownloader.h" +#include "cl_downloader.h" +#include "cl_recordingsession.h" +#include "cl_recordingsessionblock.h" +#include "cl_renderqueue.h" +#include "replay_reconstructor.h" +#include "globalvars_base.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +CClientReplayContext::CClientReplayContext() +: m_pReplayManager( NULL ), + m_pScreenshotManager( NULL ), + m_pMovieRenderer( NULL ), + m_pMovieManager( NULL ), + m_pPerformanceManager( NULL ), + m_pPerformanceController( NULL ), + m_pTestDownloader( NULL ), + m_pRenderQueue( NULL ), + m_bClientSideReplayDisabled( false ) +{ +} + +CClientReplayContext::~CClientReplayContext() +{ + delete m_pSessionBlockDownloader; + delete m_pReplayManager; + delete m_pScreenshotManager; + delete m_pMovieManager; + delete m_pPerformanceManager; + delete m_pShared; + delete m_pTestDownloader; +} + +bool CClientReplayContext::Init( CreateInterfaceFn fnFactory ) +{ + m_pShared = new CSharedReplayContext( this ); + m_pShared->m_strSubDir = SUBDIR_CLIENT; + m_pShared->m_pRecordingSessionManager = new CClientRecordingSessionManager( this ); + m_pShared->m_pRecordingSessionBlockManager = new CClientRecordingSessionBlockManager( this ); + m_pShared->m_pErrorSystem = new CErrorSystem( this ); + + if ( !m_pShared->Init( fnFactory ) ) + return false; + + m_pPerformanceManager = new CReplayPerformanceManager(); + m_pPerformanceManager->Init(); + + m_pReplayManager = new CReplayManager(); + m_pReplayManager->Init( fnFactory ); + + m_pScreenshotManager = new CScreenshotManager(); + m_pScreenshotManager->Init(); + + m_pMovieManager = new CReplayMovieManager(); + m_pMovieManager->Init(); + + m_pRenderQueue = new CRenderQueue(); + if ( !m_pRenderQueue ) + return false; + + m_pSessionBlockDownloader = new CSessionBlockDownloader(); + if ( !m_pSessionBlockDownloader ) + return false; + + m_pPerformanceController = new CPerformanceController(); + + // Cleanup any unneeded block data from disk - cleanup is done on the fly, but this will clean up + // blocks from the olden days, when block data was not cleaned up properly. + CleanupUnneededBlocks(); + + return true; +} + +void CClientReplayContext::Shutdown() +{ + // NOTE: Must come first, as any existing downloads are aborted and may cause status + // changes in replays, etc, which will need to be saved in CReplayManager::Shutdown(), etc. + m_pSessionBlockDownloader->Shutdown(); + + m_pShared->Shutdown(); + m_pReplayManager->Shutdown(); + m_pMovieManager->Shutdown(); +} + +void CClientReplayContext::DebugThink() +{ + if ( !replay_debug.GetBool() ) + return; + + int iLine = 15; + + // Recording session in progress + CClientRecordingSession *pRecordingSession = CL_GetRecordingSessionInProgress(); + if ( pRecordingSession ) + { + g_pEngineClient->Con_NPrintf( iLine++, "SESSION IN PROGRESS:" ); + g_pEngineClient->Con_NPrintf( iLine++, " BLOCKS: %i", pRecordingSession->GetNumBlocks() ); + g_pEngineClient->Con_NPrintf( iLine++, " NAME: %s", pRecordingSession->m_strName.Get() ); + g_pEngineClient->Con_NPrintf( iLine++, " URL: %s", pRecordingSession->m_strBaseDownloadURL.Get() ); + g_pEngineClient->Con_NPrintf( iLine++, " LAST CONSECUTIVE BLOCK DOWNLOADED: %i", pRecordingSession->GetGreatestConsecutiveBlockDownloaded() ); + g_pEngineClient->Con_NPrintf( iLine++, " LAST BLOCK TO DOWNLOAD: %i", pRecordingSession->GetLastBlockToDownload() ); + } + else + { + g_pEngineClient->Con_NPrintf( iLine++, "NO SESSION IN PROGRESS" ); + } + + iLine++; + + // Server state + CClientRecordingSessionManager::ServerRecordingState_t *pServerState = &CL_GetRecordingSessionManager()->m_ServerRecordingState; + g_pEngineClient->Con_NPrintf( iLine++, "SERVER STATE:" ); + g_pEngineClient->Con_NPrintf( iLine++, " NAME: %s\n", pServerState->m_strSessionName.Get() ); + g_pEngineClient->Con_NPrintf( iLine++, " DUMP INTERVAL: %i\n", pServerState->m_nDumpInterval ); + g_pEngineClient->Con_NPrintf( iLine++, " CURRENT BLOCK: %i\n", pServerState->m_nCurrentBlock ); +} + +void CClientReplayContext::Think() +{ + DebugThink(); + + if ( m_pTestDownloader ) + { + m_pTestDownloader->Think(); + if ( m_pTestDownloader->IsDone() ) + { + delete m_pTestDownloader; + m_pTestDownloader = NULL; + } + } + + if ( !g_pReplay->IsReplayEnabled() ) + return; + + m_pShared->Think(); +} + +CReplay *CClientReplayContext::GetReplay( ReplayHandle_t hReplay ) +{ + return m_pReplayManager->GetReplay( hReplay ); +} + +IReplayManager *CClientReplayContext::GetReplayManager() +{ + return m_pReplayManager; +} + +IReplayScreenshotManager *CClientReplayContext::GetScreenshotManager() +{ + return m_pScreenshotManager; +} + +IReplayPerformanceManager *CClientReplayContext::GetPerformanceManager() +{ + return m_pPerformanceManager; +} + +IReplayPerformanceController *CClientReplayContext::GetPerformanceController() +{ + return m_pPerformanceController; +} + +IReplayRenderQueue *CClientReplayContext::GetRenderQueue() +{ + return m_pRenderQueue; +} + +void CClientReplayContext::SetMovieRenderer( IReplayMovieRenderer *pMovieRenderer ) +{ + m_pMovieRenderer = pMovieRenderer; +} + +IReplayMovieRenderer *CClientReplayContext::GetMovieRenderer() +{ + return m_pMovieRenderer; +} + +IReplayMovieManager *CClientReplayContext::GetMovieManager() +{ + return m_pMovieManager; +} + +void CClientReplayContext::TestDownloader( const char *pURL ) +{ + // Don't overwrite existing test + if ( m_pTestDownloader ) + return; + + // Download the file + m_pTestDownloader = new CHttpDownloader(); + m_pTestDownloader->BeginDownload( pURL, NULL ); +} + +void CClientReplayContext::OnSignonStateFull() +{ + // Notify the demo player that we've reached full signon state + if ( g_pEngineClient->IsPlayingReplayDemo() ) + { + g_pReplayDemoPlayer->OnSignonStateFull(); + } + + // Play a performance? This will play a performance from the beginning, if we're loading + // one (ie the 'watch' button in the details panel of the replay browser), or will continue + // playback if the user rewound while watching or editing a performance. + CL_GetPerformanceController()->OnSignonStateFull(); + + // If we're rendering, display the viewport + if ( CL_GetMovieManager()->IsRendering() ) + { + extern IClientReplay *g_pClient; + g_pClient->OnRenderStart(); + + // Prepare audio system for recording. + g_pEngineClient->InitSoundRecord(); + + // Init renderer + IReplayMovie *pMovie = CL_GetMovieManager()->GetPendingMovie(); + if ( !m_pMovieRenderer->SetupRenderer( CL_GetMovieManager()->GetRenderMovieSettings(), pMovie ) ) + { + Warning( "Render failed!\n" ); + CL_GetMovieManager()->CancelRender(); + } + } + + // If we're not rendering and are playing back a replay, initialize the performance editor - + // won't actually show until the user presses space, if they do at all. + else if ( g_pEngineClient->IsPlayingReplayDemo() ) + { + const CReplay *pReplay = g_pReplayDemoPlayer->GetCurrentReplay(); + if ( pReplay ) + { + g_pClient->InitPerformanceEditor( pReplay->GetHandle() ); + } + else + { + AssertMsg( 0, "Replay should exist here!" ); + Warning( "No current replay in demo player!\n" ); + } + } +} + +void CClientReplayContext::OnClientSideDisconnect() +{ + if ( !g_pEngine->IsSupportedModAndPlatform() ) + return; + + // Reset replay_recording or we'll continue to think we're recording + extern ConVar replay_recording; + replay_recording.SetValue( 0 ); + + if ( !g_pEngineClient->IsPlayingReplayDemo() ) + { + // Saves dangling replay, if there is one, clears out everything + // NOTE: We need to let the replay manager deal before we end the session, otherwise the + // state of the session will be cleared. + m_pReplayManager->OnClientSideDisconnect(); + + // Mark the session as no longer recording. + CClientRecordingSession *pSession = CL_GetRecordingSessionInProgress(); + if ( pSession ) + { + pSession->OnStopRecording(); + } + + // Sets recording flag to false in session in progress, clears session in progress, + // and clears server state + CL_GetRecordingSessionManager()->OnSessionEnd(); + } +} + +void CClientReplayContext::PlayReplay( ReplayHandle_t hReplay, int iPerformance, bool bPlaySound ) +{ + CReplay *pReplay = m_pReplayManager->GetReplay( hReplay ); + if ( !pReplay ) + return; + + if ( !ReconstructReplayIfNecessary( pReplay ) ) + { + Replay_MsgBox( iPerformance < 0 ? "#Replay_Err_User_FailedToPlayReplay" : "#Replay_Err_User_FailedToPlayTake" ); + return; + } + + // Play a sound? + if ( bPlaySound ) + { + g_pClient->PlaySound( iPerformance >= 0 ? "replay\\playperformance.wav" : "replay\\playoriginalreplay.wav" ); + } + + // Play the replay! + g_pReplayDemoPlayer->PlayReplay( hReplay, iPerformance ); +} + +bool CClientReplayContext::ReconstructReplayIfNecessary( CReplay *pReplay ) +{ + // If reconstruction hasn't happened yet, try to reconstruct + extern ConVar replay_forcereconstruct; + if ( !pReplay->HasReconstructedReplay() || replay_forcereconstruct.GetBool() ) + { + if ( !Replay_Reconstruct( pReplay ) ) + { + CL_GetErrorSystem()->AddErrorFromTokenName( "#Replay_Err_Reconstruction_Fail" ); + return false; + } + } + + return true; +} + +void CClientReplayContext::OnPlayerSpawn() +{ + DBG( "OnPlayerSpawn()\n" ); + m_pReplayManager->AttemptToSetupNewReplay(); +} + +void CClientReplayContext::OnPlayerClassChanged() +{ + DBG( "OnPlayerClassChanged()\n" ); + m_pReplayManager->CompletePendingReplay(); +} + +void CClientReplayContext::GetPlaybackTimes( float &flOutTime, float &flOutLength, const CReplay *pReplay, const CReplayPerformance *pPerformance ) +{ + flOutTime = 0.0f; + flOutLength = 0.0f; + + // Get server start record tick + const int nServerRecordStartTick = CL_GetRecordingSessionManager()->GetServerStartTickForSession( pReplay->m_hSession ); + + // Don't let it be -1. Take performance in tick into account. + int nStartTick = MAX( 0, pReplay->m_nSpawnTick ); + if ( pPerformance && pPerformance->m_nTickIn >= 0 ) + { + nStartTick = pPerformance->m_nTickIn; + } + + // Calculate length + const int nReplayEndTick = pReplay->m_nSpawnTick + g_pEngine->TimeToTicks( pReplay->m_flLength ); + const int nEndTick = ( pPerformance && pPerformance->m_nTickOut > 0 ) ? pPerformance->m_nTickOut : nReplayEndTick; + flOutLength = pPerformance ? g_pEngine->TicksToTime( nEndTick - nStartTick ) : pReplay->m_flLength; + + // Calculate current time + const int nCurTick = MAX( g_pEngineClient->GetClientGlobalVars()->tickcount - nStartTick - nServerRecordStartTick, 0 ); + flOutTime = MIN( g_pEngine->TicksToTime( nCurTick ), flOutLength ); +} + +uint64 CClientReplayContext::GetServerSessionId( ReplayHandle_t hReplay ) +{ + CReplay *pReplay = GetReplay( hReplay ); + if ( !pReplay ) + return 0; + + CClientRecordingSession *pSession = CL_CastSession( CL_GetRecordingSessionManager()->FindSession( pReplay->m_hSession ) ); + if ( !pSession ) + return 0; + + return pSession->GetServerSessionID(); +} + +void CClientReplayContext::CleanupUnneededBlocks() +{ + CL_GetRecordingSessionManager()->CleanupUnneededBlocks(); +} + +void CClientReplayContext::ReportErrorsToUser( wchar_t *pErrorText ) +{ + // Display a message now +// Replay_MsgBox( pErrorText ); + + if ( !pErrorText || pErrorText[0] == L'\0' ) + return; + + const int nErrorLen = wcslen( pErrorText ); + static char s_szError[1024]; + wcstombs( s_szError, pErrorText, MIN( 1024, nErrorLen ) ); + Warning( "Replay error system: %s\n", s_szError ); +} + +void CClientReplayContext::DisableReplayOnClient( bool bDisable ) +{ + if ( m_bClientSideReplayDisabled == bDisable ) + return; + + m_bClientSideReplayDisabled = bDisable; + + // Display a message to the user + Replay_HudMsg( bDisable ? "#Replay_ClientSideDisabled" : "#Replay_ClientSideEnabled", NULL, true ); +} + +//---------------------------------------------------------------------------------------- + +CClientRecordingSessionManager *CL_GetRecordingSessionManager() +{ + return static_cast< CClientRecordingSessionManager * >( g_pClientReplayContextInternal->GetRecordingSessionManager() ); +} + +CClientRecordingSession *CL_GetRecordingSessionInProgress() +{ + return CL_CastSession( CL_GetRecordingSessionManager()->GetRecordingSessionInProgress() ); +} + +//---------------------------------------------------------------------------------------- |