summaryrefslogtreecommitdiff
path: root/replay/common/replay.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/common/replay.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'replay/common/replay.cpp')
-rw-r--r--replay/common/replay.cpp374
1 files changed, 374 insertions, 0 deletions
diff --git a/replay/common/replay.cpp b/replay/common/replay.cpp
new file mode 100644
index 0000000..1d56def
--- /dev/null
+++ b/replay/common/replay.cpp
@@ -0,0 +1,374 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//=======================================================================================//
+
+#include "replay/replay.h"
+#include "replay/iclientreplaycontext.h"
+#include "replay/ireplaymanager.h"
+#include "replay/replayutils.h"
+#include "replay/screenshot.h"
+#include "replay/shared_defs.h"
+#include "replay/ireplayscreenshotmanager.h"
+#include "replay/ireplayperformancemanager.h"
+#include "replay/performance.h"
+#include "KeyValues.h"
+#include "filesystem.h"
+#include "vgui/ILocalize.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//----------------------------------------------------------------------------------------
+
+extern IClientReplayContext *g_pClientReplayContext;
+extern vgui::ILocalize *g_pVGuiLocalize;
+
+//----------------------------------------------------------------------------------------
+
+CReplay::CReplay()
+: m_pDownloadEventHandler( NULL ),
+ m_pUserData( NULL ),
+ m_bComplete( false ),
+ m_bRequestedByUser( false ),
+ m_bSaved( false ),
+ m_bRendered( false ),
+ m_bDirty( false ),
+ m_bSavedDuringThisSession( true ),
+ m_flLength( 0 ),
+ m_nPlayerSlot( -1 ),
+ m_nSpawnTick( -1 ),
+ m_nDeathTick( -1 ),
+ m_iMaxSessionBlockRequired( 0 ),
+ m_nStatus( REPLAYSTATUS_INVALID ),
+ m_hSession( REPLAY_HANDLE_INVALID ),
+ m_pFileURL( NULL ),
+ m_nPostDeathRecordTime( 0 ),
+ m_flStartTime( 0.0f ),
+ m_flNextUpdateTime( 0.0f )
+{
+ m_wszTitle[0] = L'\0';
+ m_szMapName[0] = 0;
+}
+
+bool CReplay::IsDownloaded() const
+{
+ return m_nStatus == REPLAYSTATUS_READYTOCONVERT;
+}
+
+const CReplayPerformance *CReplay::GetPerformance( int i ) const
+{
+ return const_cast< CReplay * >( this )->GetPerformance( i );
+}
+
+CReplayPerformance *CReplay::GetPerformance( int i )
+{
+ if ( i < 0 || i >= m_vecPerformances.Count() )
+ return NULL;
+
+ return m_vecPerformances[ i ];
+}
+
+bool CReplay::FindPerformance( CReplayPerformance *pPerformance, int &iResult )
+{
+ const int it = m_vecPerformances.Find( pPerformance );
+ if ( it == m_vecPerformances.InvalidIndex() )
+ {
+ iResult = -1;
+ return false;
+ }
+
+ iResult = it;
+ return true;
+}
+
+CReplayPerformance *CReplay::GetPerformanceWithTitle( const wchar_t *pTitle )
+{
+ FOR_EACH_VEC( m_vecPerformances, i )
+ {
+ CReplayPerformance *pCurPerformance = m_vecPerformances[ i ];
+ if ( !V_wcscmp( pTitle, pCurPerformance->m_wszTitle ) )
+ {
+ return pCurPerformance;
+ }
+ }
+ return NULL;
+}
+
+CReplayPerformance *CReplay::AddNewPerformance( bool bGenTitle/*=true*/, bool bGenFilename/*=true*/ )
+{
+ // Create a performance
+ IReplayPerformanceManager *pPerformanceManager = g_pClientReplayContext->GetPerformanceManager();
+ CReplayPerformance *pPerformance = pPerformanceManager->CreatePerformance( this );
+
+ if ( bGenTitle )
+ {
+ // Give the performance a name
+ pPerformance->AutoNameIfHasNoTitle( m_szMapName );
+ }
+
+ if ( bGenFilename )
+ {
+ // Generate a filename for the new performance
+ pPerformance->SetFilename( pPerformanceManager->GeneratePerformanceFilename( this ) );
+ }
+
+ // Cache
+ m_vecPerformances.AddToTail( pPerformance );
+
+ return pPerformance;
+}
+
+void CReplay::AddPerformance( KeyValues *pIn )
+{
+ // Create a performance
+ IReplayPerformanceManager *pPerformanceManager = g_pClientReplayContext->GetPerformanceManager();
+ CReplayPerformance *pPerformance = pPerformanceManager->CreatePerformance( this );
+
+ // Read
+ pPerformance->Read( pIn );
+
+ // Cache
+ m_vecPerformances.AddToTail( pPerformance );
+}
+
+void CReplay::AddPerformance( CReplayPerformance *pPerformance )
+{
+ Assert( pPerformance );
+ m_vecPerformances.AddToTail( pPerformance );
+}
+
+const CReplayTime &CReplay::GetItemDate() const
+{
+ return m_RecordTime;
+}
+
+bool CReplay::IsItemRendered() const
+{
+ return m_bRendered;
+}
+
+CReplay *CReplay::GetItemReplay()
+{
+ return this;
+}
+
+ReplayHandle_t CReplay::GetItemReplayHandle() const
+{
+ return GetHandle();
+}
+
+QueryableReplayItemHandle_t CReplay::GetItemHandle() const
+{
+ return GetHandle();
+}
+
+const wchar_t *CReplay::GetItemTitle() const
+{
+ return m_wszTitle;
+}
+
+void CReplay::SetItemTitle( const wchar_t *pTitle )
+{
+ V_wcsncpy( m_wszTitle, pTitle, sizeof( m_wszTitle ) );
+}
+
+float CReplay::GetItemLength() const
+{
+ return m_flLength;
+}
+
+void *CReplay::GetUserData()
+{
+ return m_pUserData;
+}
+
+void CReplay::SetUserData( void* pUserData )
+{
+ m_pUserData = pUserData;
+}
+
+bool CReplay::IsItemAMovie() const
+{
+ return false;
+}
+
+void CReplay::AddScreenshot( int nWidth, int nHeight, const char *pBaseFilename )
+{
+ m_vecScreenshots.AddToTail( new CReplayScreenshot( nWidth, nHeight, pBaseFilename ) );
+}
+
+void CReplay::AutoNameTitleIfEmpty()
+{
+ // Autoname it
+ if ( !m_wszTitle[0] )
+ {
+ Replay_GetAutoName( m_wszTitle, sizeof( m_wszTitle ), m_szMapName );
+ }
+}
+
+const char *CReplay::GetSubKeyTitle() const
+{
+ return Replay_va( "replay_%i", GetHandle() );
+}
+
+const char *CReplay::GetPath() const
+{
+ return Replay_va( "%s%s%c", g_pClientReplayContext->GetBaseDir(), SUBDIR_REPLAYS, CORRECT_PATH_SEPARATOR );
+}
+
+void CReplay::OnDelete()
+{
+ BaseClass::OnDelete();
+
+ // Delete reconstructed replay if one exists
+ if ( HasReconstructedReplay() )
+ {
+ g_pFullFileSystem->RemoveFile( m_strReconstructedFilename.Get() );
+ }
+
+ // Delete screenshots
+ g_pClientReplayContext->GetScreenshotManager()->DeleteScreenshotsForReplay( this );
+
+ // TODO: Delete performance(s)
+}
+
+bool CReplay::Read( KeyValues *pIn )
+{
+ if ( !BaseClass::Read( pIn ) )
+ return false;
+
+ m_hSession = (ReplayHandle_t)pIn->GetInt( "session", REPLAY_HANDLE_INVALID );
+ V_strcpy_safe( m_szMapName, pIn->GetString( "map", "" ) );
+ m_nSpawnTick = pIn->GetInt( "spawn_tick", -1 );
+ m_nDeathTick = pIn->GetInt( "death_tick", -1 );
+ m_nStatus = static_cast< CReplay::ReplayStatus_t >( pIn->GetInt( "status", (int)CReplay::REPLAYSTATUS_INVALID ) );
+ m_bComplete = pIn->GetInt( "complete" ) != 0;
+ m_flLength = pIn->GetFloat( "length" );
+ m_nPostDeathRecordTime = pIn->GetInt( "postdeathrecordtime" );
+ m_bRendered = pIn->GetInt( "rendered" ) != 0;
+ m_nPlayerSlot = pIn->GetInt( "player_slot", -1 );
+ m_iMaxSessionBlockRequired = pIn->GetInt( "max_block", 0 ); Assert( m_iMaxSessionBlockRequired >= 0 );
+ m_flStartTime = pIn->GetFloat( "start_time", -1.0f ); Assert( m_flStartTime >= 0.0f );
+ V_wcsncpy( m_wszTitle, pIn->GetWString( "title" ), sizeof( m_wszTitle ) );
+
+ // Read reconstructed filename and infer path
+ const char *pReplaysDir = g_pClientReplayContext->GetReplayManager()->GetReplaysDir();
+ const char *pReconFilename = pIn->GetString( "recon_filename" );
+ if ( pReconFilename[0] != 0 )
+ {
+ m_strReconstructedFilename = Replay_va( "%s%s", pReplaysDir, pReconFilename );
+ }
+
+ // Read screenshots
+ KeyValues *pScreenshots = pIn->FindKey( "screenshots" );
+ if ( pScreenshots )
+ {
+ FOR_EACH_TRUE_SUBKEY( pScreenshots, pScreenshot )
+ {
+ int nWidth = pScreenshot->GetInt( "width" );
+ int nHeight = pScreenshot->GetInt( "height" );
+ const char *pBaseFilename = pScreenshot->GetString( "base_filename" );
+ AddScreenshot( nWidth, nHeight, pBaseFilename );
+ }
+ }
+
+ // Read performances
+ KeyValues *pPerformances = pIn->FindKey( "edits" );
+ if ( pPerformances )
+ {
+ FOR_EACH_TRUE_SUBKEY( pPerformances, pPerformance )
+ {
+ AddPerformance( pPerformance );
+ }
+ }
+
+ // Record time
+ KeyValues *pRecordTimeSubKey = pIn->FindKey( "record_time" );
+ if ( pRecordTimeSubKey )
+ {
+ m_RecordTime.Read( pRecordTimeSubKey );
+ }
+
+ // Mark replay as saved, since it was just loaded from disk
+ m_bSaved = true;
+
+ return true;
+}
+
+void CReplay::Write( KeyValues *pOut )
+{
+ BaseClass::Write( pOut );
+
+ pOut->SetString( "map", m_szMapName );
+ pOut->SetInt( "session", m_hSession );
+ pOut->SetInt( "spawn_tick", m_nSpawnTick );
+ pOut->SetInt( "death_tick", m_nDeathTick );
+ pOut->SetInt( "status", static_cast< int >( m_nStatus ) );
+ pOut->SetInt( "complete", static_cast< int >( m_bComplete ) );
+ pOut->SetFloat( "length", m_flLength );
+ pOut->SetInt( "postdeathrecordtime", m_nPostDeathRecordTime );
+ pOut->SetInt( "rendered", m_bRendered );
+ pOut->SetInt( "player_slot", m_nPlayerSlot );
+ pOut->SetInt( "max_block", m_iMaxSessionBlockRequired );
+ pOut->SetFloat( "start_time", m_flStartTime );
+ pOut->SetWString( "title", m_wszTitle );
+
+ // Store only filename for reconstructed .dem
+ if ( !m_strReconstructedFilename.IsEmpty() )
+ {
+ const char *pReconFilename = V_UnqualifiedFileName( m_strReconstructedFilename.Get() );
+ if ( pReconFilename[0] )
+ {
+ pOut->SetString( "recon_filename", pReconFilename );
+ }
+ }
+
+ // Write screenshots
+ KeyValues *pScreenshots = new KeyValues( "screenshots" );
+ pOut->AddSubKey( pScreenshots );
+ for ( int i = 0; i < m_vecScreenshots.Count(); ++i )
+ {
+ KeyValues *pScreenshotOut = new KeyValues( "screenshot" );
+ CReplayScreenshot *pScreenshot = m_vecScreenshots[ i ];
+ pScreenshotOut->SetInt( "width", pScreenshot->m_nWidth );
+ pScreenshotOut->SetInt( "height", pScreenshot->m_nHeight );
+ pScreenshotOut->SetString( "base_filename", pScreenshot->m_szBaseFilename );
+ pScreenshots->AddSubKey( pScreenshotOut );
+ }
+
+ // Write performances
+ KeyValues *pPerformances = new KeyValues( "edits" );
+ pOut->AddSubKey( pPerformances );
+ for ( int i = 0; i < m_vecPerformances.Count(); ++i )
+ {
+ KeyValues *pPerfOut = new KeyValues( "edit" );
+ CReplayPerformance *pPerformance = m_vecPerformances[ i ];
+ pPerformance->Write( pPerfOut );
+ pPerformances->AddSubKey( pPerfOut );
+ }
+
+ KeyValues *pRecordTime = new KeyValues( "record_time" );
+ pOut->AddSubKey( pRecordTime );
+ m_RecordTime.Write( pRecordTime );
+
+ // Mark as saved
+ m_bSaved = true;
+}
+
+bool CReplay::HasReconstructedReplay() const
+{
+ return !m_strReconstructedFilename.IsEmpty() &&
+ g_pFullFileSystem->FileExists( m_strReconstructedFilename.Get() );
+}
+
+bool CReplay::IsSignificantBlock( int iBlockReconstruction ) const
+{
+ return iBlockReconstruction <= m_iMaxSessionBlockRequired;
+}
+
+void CReplay::OnComplete()
+{
+ AutoNameTitleIfEmpty();
+}
+
+//----------------------------------------------------------------------------------------