summaryrefslogtreecommitdiff
path: root/replay/cl_replaycontext.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /replay/cl_replaycontext.cpp
downloadarchived-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.cpp421
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() );
+}
+
+//----------------------------------------------------------------------------------------