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.
182 lines
5.3 KiB
182 lines
5.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
//=======================================================================================// |
|
|
|
#include "sv_sessioninfopublisher.h" |
|
#include "sv_replaycontext.h" |
|
#include "sv_recordingsessionblock.h" |
|
#include "sv_recordingsession.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//---------------------------------------------------------------------------------------- |
|
|
|
CSessionInfoPublisher::CSessionInfoPublisher( CServerRecordingSession *pSession ) |
|
: m_pSession( pSession ), |
|
m_flSessionInfoPublishTime( 0.0f ), |
|
m_itLastCompletedBlockWrittenToBuffer( ~0 ), |
|
m_pFilePublisher( NULL ), |
|
m_bShouldPublish( false ) |
|
{ |
|
} |
|
|
|
CSessionInfoPublisher::~CSessionInfoPublisher() |
|
{ |
|
} |
|
|
|
void CSessionInfoPublisher::Publish() |
|
{ |
|
m_bShouldPublish = true; |
|
} |
|
|
|
bool CSessionInfoPublisher::IsDone() const |
|
{ |
|
return !m_bShouldPublish && m_pFilePublisher == NULL; |
|
} |
|
|
|
void CSessionInfoPublisher::OnStopRecord( bool bAborting ) |
|
{ |
|
} |
|
|
|
void CSessionInfoPublisher::AbortPublish() |
|
{ |
|
m_bShouldPublish = false; |
|
|
|
if ( m_pFilePublisher && !m_pFilePublisher->IsDone() ) |
|
{ |
|
m_pFilePublisher->AbortAndCleanup(); |
|
} |
|
} |
|
|
|
void CSessionInfoPublisher::RefreshSessionInfoBlockData( CUtlBuffer &buf ) |
|
{ |
|
const CBaseRecordingSession::BlockContainer_t &vecBlocks = m_pSession->GetBlocks(); |
|
|
|
// Start from head if this is the first time we're writing, otherwise start |
|
// from block after the last one written. |
|
const int itStart = m_itLastCompletedBlockWrittenToBuffer == vecBlocks.InvalidIndex() ? |
|
0 : m_itLastCompletedBlockWrittenToBuffer + 1; |
|
|
|
for( int i = itStart; i < vecBlocks.Count(); ++i ) |
|
{ |
|
const CServerRecordingSessionBlock *pBlock = SV_CastBlock( vecBlocks[ i ] ); |
|
|
|
// NOTE: This will SeekPut() on buf, based on the block's reconstruction index. |
|
pBlock->WriteSessionInfoDataToBuffer( buf ); |
|
|
|
// Cache the last block written whose state isn't going to change |
|
if ( pBlock->m_nRemoteStatus == CBaseRecordingSessionBlock::STATUS_READYFORDOWNLOAD && |
|
i > m_itLastCompletedBlockWrittenToBuffer ) |
|
{ |
|
m_itLastCompletedBlockWrittenToBuffer = i; |
|
} |
|
|
|
IF_REPLAY_DBG( Warning( "Writing block w/ recon index %i to session info buffer\n", pBlock->m_iReconstruction ) ); |
|
} |
|
} |
|
|
|
void CSessionInfoPublisher::Think() |
|
{ |
|
// Existing publisher? |
|
if ( m_pFilePublisher ) |
|
{ |
|
// Finished? |
|
if ( m_pFilePublisher->IsDone() ) |
|
{ |
|
// Free/clear |
|
delete m_pFilePublisher; |
|
m_pFilePublisher = NULL; |
|
} |
|
else |
|
{ |
|
// Let the publisher think |
|
m_pFilePublisher->Think(); |
|
} |
|
} |
|
|
|
// Publish needed? |
|
if ( !m_bShouldPublish ) |
|
return; |
|
|
|
// Already publishing? |
|
if ( m_pFilePublisher ) |
|
return; |
|
|
|
DBG( "Publishing session info...\n" ); |
|
|
|
// Write outstanding blocks to the buffer |
|
RefreshSessionInfoBlockData( m_bufSessionInfo ); |
|
|
|
// We now know the uncompressed payload size |
|
const int nPayloadSize = m_bufSessionInfo.TellPut(); |
|
|
|
// Create as much of the header as possible now - the rest will be written in AdjustHeader() |
|
// once the publisher knows the md5 digest and the compression result. |
|
Assert( m_pSession->m_strName.Length() < MAX_SESSIONNAME_LENGTH ); // The only way this name is going to get very long is if |
|
V_strcpy_safe( m_SessionInfoHeader.m_szSessionName, m_pSession->m_strName.Get() ); |
|
m_SessionInfoHeader.m_nNumBlocks = m_pSession->GetNumBlocks(); |
|
m_SessionInfoHeader.m_bRecording = m_pSession->m_bRecording; |
|
m_SessionInfoHeader.m_uPayloadSizeUC = nPayloadSize; |
|
|
|
// Format a path & filename that points to the tmp dir, with <session name>.dmx on the end |
|
CFmtStr fmtTmpSessionInfoFile( "%s%s.%s", SV_GetTmpDir(), m_pSession->m_strName.Get(), GENERIC_FILE_EXTENSION ); |
|
|
|
// Publish the file now (asynchronous) |
|
PublishFileParams_t params; |
|
params.m_pOutFilename = fmtTmpSessionInfoFile.Access(), |
|
params.m_pSrcData = (uint8 *)m_bufSessionInfo.Base(); |
|
params.m_nSrcSize = nPayloadSize; |
|
params.m_pCallbackHandler = this; |
|
params.m_nCompressorType = COMPRESSORTYPE_LZSS; |
|
params.m_bHash = true; |
|
params.m_bFreeSrcData = false; |
|
params.m_bDeleteFile = false; |
|
params.m_pHeaderData = &m_SessionInfoHeader; |
|
params.m_nHeaderSize = sizeof( SessionInfoHeader_t ); |
|
params.m_pUserData = NULL; |
|
m_pFilePublisher = SV_PublishFile( params ); |
|
|
|
// Reset flag |
|
m_bShouldPublish = false; |
|
} |
|
|
|
void CSessionInfoPublisher::OnPublishComplete( const IFilePublisher *pPublisher, void *pUserData ) |
|
{ |
|
Assert( !pUserData ); |
|
|
|
// Handle publish failure |
|
if ( pPublisher->GetStatus() != IFilePublisher::PUBLISHSTATUS_OK ) |
|
{ |
|
g_pServerReplayContext->OnPublishFailed(); |
|
} |
|
} |
|
|
|
void CSessionInfoPublisher::OnPublishAborted( const IFilePublisher *pPublisher ) |
|
{ |
|
Assert( pPublisher == m_pFilePublisher ); |
|
|
|
g_pServerReplayContext->OnPublishFailed(); |
|
} |
|
|
|
void CSessionInfoPublisher::AdjustHeader( const IFilePublisher *pPublisher, void *pHeaderData ) |
|
{ |
|
SessionInfoHeader_t *pHeader = static_cast< SessionInfoHeader_t * >( pHeaderData ); |
|
|
|
// Set compressor type - will return COMPRESSORTYPE_INVALID if compression failed. |
|
pHeader->m_nCompressorType = pPublisher->GetCompressorType(); |
|
pHeader->m_uPayloadSize = pPublisher->GetCompressedSize(); |
|
|
|
// Get MD5 digest |
|
pPublisher->GetHash( pHeader->m_aHash ); |
|
} |
|
|
|
void CSessionInfoPublisher::PublishAllSynchronous() |
|
{ |
|
while ( !IsDone() ) |
|
{ |
|
Think(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------------------
|
|
|