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/common | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'replay/common')
| -rw-r--r-- | replay/common/basereplayserializeable.cpp | 87 | ||||
| -rw-r--r-- | replay/common/headers.vpc | 15 | ||||
| -rw-r--r-- | replay/common/performance.cpp | 96 | ||||
| -rw-r--r-- | replay/common/replay.cpp | 374 | ||||
| -rw-r--r-- | replay/common/replay_common.vpc | 36 | ||||
| -rw-r--r-- | replay/common/replaylib.cpp | 27 | ||||
| -rw-r--r-- | replay/common/replaytime.cpp | 274 | ||||
| -rw-r--r-- | replay/common/replayutils.cpp | 130 | ||||
| -rw-r--r-- | replay/common/screenshot.cpp | 42 |
9 files changed, 1081 insertions, 0 deletions
diff --git a/replay/common/basereplayserializeable.cpp b/replay/common/basereplayserializeable.cpp new file mode 100644 index 0000000..a0a7bd4 --- /dev/null +++ b/replay/common/basereplayserializeable.cpp @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/basereplayserializeable.h" +#include "replay/replayutils.h" +#include "KeyValues.h" +#include "tier1/strtools.h" +#include "replay/shared_defs.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +CBaseReplaySerializeable::CBaseReplaySerializeable() +: m_hThis( REPLAY_HANDLE_INVALID ), + m_bLocked( false ) +{ +} + +void CBaseReplaySerializeable::SetHandle( ReplayHandle_t h ) +{ + m_hThis = h; +} + +ReplayHandle_t CBaseReplaySerializeable::GetHandle() const +{ + return m_hThis; +} + +bool CBaseReplaySerializeable::Read( KeyValues *pIn ) +{ + m_hThis = (ReplayHandle_t)pIn->GetInt( "handle" ); + + return true; +} + +void CBaseReplaySerializeable::Write( KeyValues *pOut ) +{ + pOut->SetInt( "handle", (int)m_hThis ); +} + +const char *CBaseReplaySerializeable::GetFullFilename() const +{ + const char *pPath = GetPath(); + const char *pFilename = GetFilename(); + + if ( !pPath || !pPath[0] || !pFilename || !pFilename[0] ) + return NULL; + + return Replay_va( "%s%s", pPath, pFilename ); +} + +const char *CBaseReplaySerializeable::GetFilename() const +{ + return Replay_va( "%s.%s", GetSubKeyTitle(), GENERIC_FILE_EXTENSION ); +} + +const char *CBaseReplaySerializeable::GetDebugName() const +{ + return GetSubKeyTitle(); +} + +void CBaseReplaySerializeable::SetLocked( bool bLocked ) +{ + m_bLocked = bLocked; +} + +bool CBaseReplaySerializeable::IsLocked() const +{ + return m_bLocked; +} + +void CBaseReplaySerializeable::OnDelete() +{ +} + +void CBaseReplaySerializeable::OnUnload() +{ +} + +void CBaseReplaySerializeable::OnAddedToDirtyList() +{ +} + +//----------------------------------------------------------------------------------------
\ No newline at end of file diff --git a/replay/common/headers.vpc b/replay/common/headers.vpc new file mode 100644 index 0000000..5979400 --- /dev/null +++ b/replay/common/headers.vpc @@ -0,0 +1,15 @@ +//----------------------------------------------------------------------------- +// HEADERS.VPC - Allows for sync'd inclusion of headers for replay_common.lib +// other vpc's. +//----------------------------------------------------------------------------- + +$Folder $REPLAY_COMMON_HEADERS_TITLE +{ + $File "$SRCDIR\common\replay\replay.h" + $File "$SRCDIR\common\replay\replaylib.h" + $File "$SRCDIR\common\replay\performance.h" + $File "$SRCDIR\common\replay\replaytime.h" + $File "$SRCDIR\common\replay\replayutils.h" + $File "$SRCDIR\common\replay\screenshot.h" + $File "$SRCDIR\common\replay\shared_defs.h" +}
\ No newline at end of file diff --git a/replay/common/performance.cpp b/replay/common/performance.cpp new file mode 100644 index 0000000..1888071 --- /dev/null +++ b/replay/common/performance.cpp @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/performance.h" +#include "replay/iclientreplaycontext.h" +#include "replay/ireplayperformancemanager.h" +#include "replay/replayutils.h" +#include "KeyValues.h" +#include "fmtstr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +extern IClientReplayContext *g_pClientReplayContext; + +//---------------------------------------------------------------------------------------- + +CReplayPerformance::CReplayPerformance( CReplay *pReplay ) +: m_pReplay( pReplay ), + m_nTickIn( -1 ), + m_nTickOut( -1 ) +{ + Assert( pReplay ); + m_szBaseFilename[ 0 ] = '\0'; + m_wszTitle[0] = L'\0'; +} + +CReplayPerformance::CReplayPerformance( const CReplayPerformance *pPerformance ) +{ + Copy( pPerformance ); +} + +void CReplayPerformance::Read( KeyValues *pIn ) +{ + SetFilename( pIn->GetString( "filename" ) ); + m_nTickIn = pIn->GetInt( "tick_in", -1 ); + m_nTickOut = pIn->GetInt( "tick_out", -1 ); + V_wcsncpy( m_wszTitle, pIn->GetWString( "title" ), sizeof( m_wszTitle ) ); +} + +void CReplayPerformance::Write( KeyValues *pOut ) +{ + pOut->SetString( "filename", m_szBaseFilename ); + pOut->SetInt( "tick_in", m_nTickIn ); + pOut->SetInt( "tick_out", m_nTickOut ); + pOut->SetWString( "title", m_wszTitle ); +} + +void CReplayPerformance::Copy( const CReplayPerformance *pSrc ) +{ + V_wcsncpy( m_wszTitle, pSrc->m_wszTitle, sizeof( m_wszTitle ) ); + V_strcpy( m_szBaseFilename, pSrc->m_szBaseFilename ); + + m_pReplay = pSrc->m_pReplay; + + CopyTicks( pSrc ); +} + +void CReplayPerformance::CopyTicks( const CReplayPerformance *pSrc ) +{ + m_nTickIn = pSrc->m_nTickIn; + m_nTickOut = pSrc->m_nTickOut; +} + +void CReplayPerformance::SetFilename( const char *pFilename ) +{ + V_strcpy( m_szBaseFilename, pFilename ); +} + +const char *CReplayPerformance::GetFullPerformanceFilename() +{ + return Replay_va( "%s%s", g_pClientReplayContext->GetPerformanceManager()->GetFullPath(), m_szBaseFilename ); +} + +void CReplayPerformance::AutoNameIfHasNoTitle( const char *pMapName ) +{ + if ( !m_wszTitle[ 0 ] ) + { + Replay_GetAutoName( m_wszTitle, sizeof( m_wszTitle ), pMapName ); + } +} + +void CReplayPerformance::SetTitle( const wchar_t *pTitle ) +{ + V_wcsncpy( m_wszTitle, pTitle, sizeof( m_wszTitle ) ); +} + +CReplayPerformance *CReplayPerformance::MakeCopy() const +{ + return new CReplayPerformance( this ); +} + +//---------------------------------------------------------------------------------------- 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(); +} + +//---------------------------------------------------------------------------------------- diff --git a/replay/common/replay_common.vpc b/replay/common/replay_common.vpc new file mode 100644 index 0000000..16b5b3f --- /dev/null +++ b/replay/common/replay_common.vpc @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// REPLAY_COMMON.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro REPLAY_COMMON_HEADERS_TITLE "Headers" +$Macro OUTLIBDIR "$LIBCOMMON" + +$include "$SRCDIR\vpc_scripts\source_lib_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\dx9sdk\include" [$WINDOWS] + $AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005" [$WINDOWS] + } +} + +$Project "replay_common" +{ + $Folder "Source Files" + { + $File "replay.cpp" + $File "replaylib.cpp" + $File "basereplayserializeable.cpp" + $File "performance.cpp" + $File "replaytime.cpp" + $File "replayutils.cpp" + $File "screenshot.cpp" + } + + $Include "$SRCDIR\replay\common\headers.vpc" +} diff --git a/replay/common/replaylib.cpp b/replay/common/replaylib.cpp new file mode 100644 index 0000000..87a87b0 --- /dev/null +++ b/replay/common/replaylib.cpp @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/replaylib.h" +#include "replay/replayutils.h" +#include "replay/iclientreplaycontext.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +IClientReplayContext *g_pClientReplayContext = NULL; + +//---------------------------------------------------------------------------------------- + +bool ReplayLib_Init( const char *pGameDir, IClientReplayContext *pClientReplayContext ) +{ + Replay_SetGameDir( pGameDir ); + + g_pClientReplayContext = pClientReplayContext; + + return true; +} + +//---------------------------------------------------------------------------------------- diff --git a/replay/common/replaytime.cpp b/replay/common/replaytime.cpp new file mode 100644 index 0000000..feb2405 --- /dev/null +++ b/replay/common/replaytime.cpp @@ -0,0 +1,274 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/replaytime.h" +#include "KeyValues.h" +#include <time.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +CReplayTime::CReplayTime() +: m_fDate( 0 ), + m_fTime( 0 ) +{ +} + +void CReplayTime::InitDateAndTimeToNow() +{ + tm now; + VCRHook_LocalTime( &now ); + SetDate( now.tm_mday, now.tm_mon + 1, now.tm_year + 1900 ); + SetTime( now.tm_hour, now.tm_min, now.tm_sec ); +} + +void CReplayTime::SetDate( int nDay, int nMonth, int nYear ) +{ + Assert( nDay >= 1 && nDay <= 31 ); + Assert( nMonth >= 1 && nMonth <= 12 ); + Assert( nYear >= 2009 && nYear <= 2136 ); + + m_fDate = nDay - 1; + m_fDate |= ( ( nMonth - 1 ) << 5 ); + m_fDate |= ( ( nYear - 2009 ) << 9 ); + +#ifdef _DEBUG + int nDbgDay, nDbgMonth, nDbgYear; + GetDate( nDbgDay, nDbgMonth, nDbgYear ); + Assert( nDay == nDbgDay ); + Assert( nMonth == nDbgMonth ); + Assert( nYear == nDbgYear ); +#endif +} + +void CReplayTime::GetDate( int &nDay, int &nMonth, int &nYear ) const +{ + nDay = 1 + ( m_fDate & 0x1F ); // Bits 0-4 for day + nMonth = 1 + ( ( m_fDate >> 5 ) & 0x0F ); // Bits 5-8 for month + nYear = 2009 + ( ( m_fDate >> 9 ) & 0x7F ); // Bits 9-15 for year + + Assert( nDay >= 1 && nDay <= 31 ); + Assert( nMonth >= 1 && nMonth <= 12 ); + Assert( nYear >= 2009 && nYear <= 2136 ); +} + +void CReplayTime::SetTime( int nHour, int nMin, int nSec ) +{ + Assert( nHour >= 0 && nHour <= 23 ); + Assert( nMin >= 0 && nMin <= 59 ); + Assert( nSec >= 0 && nSec <= 59 ); + + m_fTime = nHour; + m_fTime |= ( ( nMin ) << 5 ); + m_fTime |= ( ( nSec ) << 11 ); + +#ifdef _DEBUG + int nDbgHour, nDbgMin, nDbgSec; + GetTime( nDbgHour, nDbgMin, nDbgSec ); + Assert( nHour == nDbgHour ); + Assert( nMin == nDbgMin ); + Assert( nSec == nDbgSec ); +#endif +} + +void CReplayTime::GetTime( int &nHour, int &nMin, int &nSec ) const +{ + nHour = m_fTime & 0x1F; // Bits 0-4 for hour + nMin = ( m_fTime >> 5 ) & 0x3F; // Bits 5-10 for min + nSec = ( m_fTime >> 11 ) & 0x3F; // Bits 11-16 for sec + + Assert( nHour >= 0 && nHour <= 23 ); + Assert( nMin >= 0 && nMin <= 59 ); + Assert( nSec >= 0 && nSec <= 59 ); +} + +void CReplayTime::Read( KeyValues *pIn ) +{ + m_fDate = pIn->GetInt( "date" ); + m_fTime = pIn->GetInt( "time" ); +} + +void CReplayTime::Write( KeyValues *pOut ) +{ + pOut->SetInt( "date", m_fDate ); + pOut->SetInt( "time", m_fTime ); +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedMonth( vgui::ILocalize *pLocalize, int nMonth ) +{ + char szMonthKey[32]; // Get localized month + + V_snprintf( szMonthKey, sizeof( szMonthKey ), "#Month_%i", nMonth ); + wchar_t *pResult = pLocalize->Find( szMonthKey ); + + return pResult ? pResult : L""; +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedDay( vgui::ILocalize *pLocalize, int nDay ) +{ + char szDay[8]; // Convert day to wide + static wchar_t s_wDay[8]; + + V_snprintf( szDay, sizeof( szDay ), "%i", nDay ); + pLocalize->ConvertANSIToUnicode( szDay, s_wDay, sizeof( s_wDay ) ); + + return s_wDay; +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedYear( vgui::ILocalize *pLocalize, int nYear ) +{ + char szYear[8]; // Convert year to wide + static wchar_t s_wYear[8]; + + V_snprintf( szYear, sizeof( szYear ), "%i", nYear ); + pLocalize->ConvertANSIToUnicode( szYear, s_wYear, sizeof( s_wYear ) ); + + return s_wYear; +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedTime( vgui::ILocalize *pLocalize, int nHour, int nMin, int nSec ) +{ + char szTime[16]; // Convert time to wide + static wchar_t s_wTime[16]; + V_snprintf( szTime, sizeof( szTime ), "%i:%02i %s", nHour % 12, nMin, nHour < 12 ? "AM" : "PM" ); + pLocalize->ConvertANSIToUnicode( szTime, s_wTime, sizeof( s_wTime ) ); + + return s_wTime; +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedDate( vgui::ILocalize *pLocalize, const CReplayTime &t, + bool bForceFullFormat/*=false*/ ) +{ + int nHour, nMin, nSec; + int nDay, nMonth, nYear; + t.GetTime( nHour, nMin, nSec ); + t.GetDate( nDay, nMonth, nYear ); + return GetLocalizedDate( pLocalize, nDay, nMonth, nYear, &nHour, &nMin, &nSec, bForceFullFormat ); +} + +/*static*/ const wchar_t *CReplayTime::GetLocalizedDate( vgui::ILocalize *pLocalize, int nDay, int nMonth, int nYear, + int *pHour/*=NULL*/, int *pMin/*=NULL*/, int *pSec/*=NULL*/, + bool bForceFullFormat/*=false*/ ) +{ + static wchar_t s_wBuf[256]; + + // Is this collection for replays from today? + time_t today; + time( &today ); + tm *pNowTime = localtime( &today ); + bool bToday = ( pNowTime->tm_mday == nDay ) && ( pNowTime->tm_mon + 1 == nMonth ) && ( 1900 + pNowTime->tm_year == nYear ); + + // Yesterday? + time_t yesterday = today - time_t( 86400 ); + tm *pYesterdayTime = localtime( &yesterday ); + bool bYesterday = ( pYesterdayTime->tm_mday == nDay ) && ( pYesterdayTime->tm_mon + 1 == nMonth ) && ( 1900 + pYesterdayTime->tm_year == nYear ); + + const wchar_t *pMonth = GetLocalizedMonth( pLocalize, nMonth ); + const wchar_t *pDay = GetLocalizedDay( pLocalize, nDay ); + const wchar_t *pYear = GetLocalizedYear( pLocalize, nYear ); + const wchar_t *pToday = pLocalize->Find( "#Replay_Today" ); + const wchar_t *pYesterday = pLocalize->Find( "#Replay_Yesterday" ); + + bool bTime = pHour && pMin && pSec; + + // Include time in formatted string? + if ( bTime ) + { + const wchar_t *pTime = GetLocalizedTime( pLocalize, *pHour, *pMin, *pSec ); + + if ( bForceFullFormat || ( !bToday && !bYesterday ) ) + { + pLocalize->ConstructString( + s_wBuf, + sizeof( s_wBuf ), + pLocalize->Find( "#Replay_DateAndTime" ), + 4, + pMonth, pDay, pYear, pTime + ); + } + else + { + pLocalize->ConstructString( + s_wBuf, + sizeof( s_wBuf ), + pLocalize->Find( "#Replay_SingleWordDateAndTime" ), + 2, + bToday ? pToday : pYesterday, + pTime + ); + } + } + else + { + if ( !bToday && !bYesterday ) + { + pLocalize->ConstructString( + s_wBuf, + sizeof( s_wBuf ), + pLocalize->Find( "#Replay_Date" ), + 3, + pMonth, pDay, pYear + ); + } + else + { + V_wcsncpy( s_wBuf, bToday ? pToday : pYesterday, sizeof( s_wBuf ) ); + } + } + + return s_wBuf; +} + +/*static*/ const char *CReplayTime::FormatTimeString( int nSecs ) +{ + static int nWhichStr = 0; + static const int nNumStrings = 2; + static const int nStrLen = 32; + static char s_szResult[nNumStrings][nStrLen]; + + char *pResult = s_szResult[ nWhichStr ]; + + int nSeconds = nSecs % 60; + int nMins = nSecs / 60; + int nHours = nMins / 60; + nMins %= 60; + + if ( nHours > 0 ) + { + V_snprintf( pResult, nStrLen, "%i:%02i:%02i", nHours, nMins, nSeconds ); + } + else + { + V_snprintf( pResult, nStrLen, "%02i:%02i", nMins, nSeconds ); + } + + nWhichStr = ( nWhichStr + 1 ) % nNumStrings; + + return pResult; +} + +/*static*/ const char *CReplayTime::FormatPreciseTimeString( float flSecs ) +{ + static int nWhichStr = 0; + static const int nNumStrings = 2; + static const int nStrLen = 32; + static char s_szResult[nNumStrings][nStrLen]; + + char *pResult = s_szResult[ nWhichStr ]; + + int nSecs = (int)flSecs; + int nMins = ( nSecs % 3600 ) / 60; + int nSeconds = nSecs % 60; + int nMilliseconds = (flSecs - (float)nSecs) * 10.0f; + + V_snprintf( pResult, nStrLen, "%02i:%02i:%02i", nMins, nSeconds, nMilliseconds ); + + nWhichStr = ( nWhichStr + 1 ) % nNumStrings; + + return pResult; +} + +//---------------------------------------------------------------------------------------- diff --git a/replay/common/replayutils.cpp b/replay/common/replayutils.cpp new file mode 100644 index 0000000..e8d63d5 --- /dev/null +++ b/replay/common/replayutils.cpp @@ -0,0 +1,130 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/replayutils.h" +#include "dbg.h" +#include "strtools.h" +#include "qlimits.h" +#include "filesystem.h" +#include "replay/replaytime.h" +#include "fmtstr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +static char gs_szGameDir[MAX_OSPATH]; + +//---------------------------------------------------------------------------------------- + +void Replay_GetFirstAvailableFilename( char *pDst, int nDstLen, const char *pIdealFilename, const char *pExt, + const char *pFilePath, int nStartIndex ) +{ + // Strip extension from ideal filename + char szIdealFilename[ MAX_OSPATH ]; + V_StripExtension( pIdealFilename, szIdealFilename, sizeof( szIdealFilename ) ); + + int i = nStartIndex; + while ( 1 ) + { + V_strncpy( pDst, szIdealFilename, nDstLen ); + V_strcat( pDst, Replay_va( "_%i%s", i, pExt ), nDstLen ); + + // Get a potential working path/filename + CFmtStr fmtTestFilename( + "%s%c%s", + pFilePath, + CORRECT_PATH_SEPARATOR, + pDst + ); + + // Make sure slashes are correct for platform + V_FixSlashes( fmtTestFilename.Access() ); + + // Fix up double slashes + V_FixDoubleSlashes( fmtTestFilename.Access() ); + + if ( !g_pFullFileSystem->FileExists( fmtTestFilename ) ) + break; + + ++i; + } +} + +//---------------------------------------------------------------------------------------- + +void Replay_ConstructReplayFilenameString( CUtlString &strOut, const char *pReplaySubDir, const char *pFilename, const char *pGameDir ) +{ + // Construct full filename + strOut.Format( "%s%creplays%c%s%c%s", pGameDir, + CORRECT_PATH_SEPARATOR, CORRECT_PATH_SEPARATOR, pReplaySubDir, + CORRECT_PATH_SEPARATOR, pFilename + ); +} + +//---------------------------------------------------------------------------------------- + +char *Replay_va( const char *format, ... ) +{ + va_list argptr; + static char string[8][512]; + static int curstring = 0; + + curstring = ( curstring + 1 ) % 8; + + va_start (argptr, format); + Q_vsnprintf( string[curstring], sizeof( string[curstring] ), format, argptr ); + va_end (argptr); + + return string[curstring]; +} + +//---------------------------------------------------------------------------------------- + +void Replay_SetGameDir( const char *pGameDir ) +{ + V_strcpy( gs_szGameDir, pGameDir ); +} + +//---------------------------------------------------------------------------------------- + +const char *Replay_GetGameDir() +{ + return gs_szGameDir; +} + +//---------------------------------------------------------------------------------------- + +const char *Replay_GetBaseDir() +{ + return Replay_va( + "%s%creplays%c", + Replay_GetGameDir(), + CORRECT_PATH_SEPARATOR, + CORRECT_PATH_SEPARATOR + ); +} + +//---------------------------------------------------------------------------------------- + +void Replay_GetAutoName( wchar_t *pDest, int nDestSize, const char *pMapName ) +{ + // Get date/time + CReplayTime now; + now.InitDateAndTimeToNow(); + + // Convert map name to unicode + wchar_t wszMapName[256]; + extern vgui::ILocalize *g_pVGuiLocalize; + g_pVGuiLocalize->ConvertANSIToUnicode( pMapName, wszMapName, sizeof( wszMapName ) ); + + // Get localized date as string + const wchar_t *pLocalizedDate = CReplayTime::GetLocalizedDate( g_pVGuiLocalize, now, true ); + + // Create title + g_pVGuiLocalize->ConstructString( pDest, nDestSize, L"%s1: %s2", 2, wszMapName, pLocalizedDate ); +} + +//---------------------------------------------------------------------------------------- diff --git a/replay/common/screenshot.cpp b/replay/common/screenshot.cpp new file mode 100644 index 0000000..8a0004b --- /dev/null +++ b/replay/common/screenshot.cpp @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +//=======================================================================================// + +#include "replay/screenshot.h" +#include "replay/replayutils.h" +#include "replay/iclientreplaycontext.h" +#include "KeyValues.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//---------------------------------------------------------------------------------------- + +bool CReplayScreenshot::Read( KeyValues *pIn ) +{ + m_nWidth = pIn->GetInt( "w" ); + m_nHeight = pIn->GetInt( "h" ); + V_strcpy_safe( m_szBaseFilename, pIn->GetString( "file", "" ) ); + + return true; +} + +void CReplayScreenshot::Write( KeyValues *pOut ) +{ + pOut->SetInt( "w", m_nWidth ); + pOut->SetInt( "h", m_nHeight ); + pOut->SetString( "file", m_szBaseFilename ); +} + +const char *CReplayScreenshot::GetSubKeyTitle() const +{ + return m_szBaseFilename; +} + +const char *CReplayScreenshot::GetPath() const +{ + extern IClientReplayContext *g_pClientReplayContext; + return Replay_va( "%s%s%c", g_pClientReplayContext->GetBaseDir(), SUBDIR_SCREENSHOTS, CORRECT_PATH_SEPARATOR ); +} + +//----------------------------------------------------------------------------------------
\ No newline at end of file |