|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=======================================================================================//
#include "replaysystem.h"
#include "sv_sessionrecorder.h"
#include "utlbuffer.h"
#include "sessioninfoheader.h"
#include "sv_fileservercleanup.h"
#include "sv_publishtest.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//----------------------------------------------------------------------------------------
#define ENSURE_DEDICATED() if ( !g_pEngine->IsDedicated() ) return;
//----------------------------------------------------------------------------------------
CON_COMMAND( replay_record, "Starts Replay demo recording." ) { ENSURE_DEDICATED(); SV_GetSessionRecorder()->StartRecording(); }
//----------------------------------------------------------------------------------------
CON_COMMAND( replay_stoprecord, "Stop Replay demo recording." ) { ENSURE_DEDICATED(); g_pReplay->SV_EndRecordingSession(); }
//----------------------------------------------------------------------------------------
CON_COMMAND( replay_docleanup, "Deletes stale session data from the fileserver. \"replay_docleanup force\" will remove all replay session data." ) { ENSURE_DEDICATED();
bool bForceCleanAll = false; if ( args.ArgC() == 2 ) { if ( !V_stricmp( args[1], "force" ) ) { bForceCleanAll = true; } else { ConMsg( "\n ** ERROR: '%s' is not a valid paramter - use 'force' to force clean all replay session data.\n\n", args[1] ); return; } }
if ( !SV_DoFileserverCleanup( bForceCleanAll, g_pBlockSpewer ) ) { Msg( "No demos were deleted.\n" ); } }
//----------------------------------------------------------------------------------------
CON_COMMAND_F( replay_dopublishtest, "Do a replay publish test using the current setup.", FCVAR_DONTRECORD ) { ENSURE_DEDICATED();
g_pBlockSpewer->PrintBlockStart(); SV_DoTestPublish(); g_pBlockSpewer->PrintBlockEnd(); }
//----------------------------------------------------------------------------------------
void PrintSessionInfo( const char *pFilename ) { CUtlBuffer buf; if ( !g_pFullFileSystem->ReadFile( pFilename, NULL, buf ) ) { Msg( "Failed to read file, \"%s\"\n", pFilename ); return; }
int nFileSize = buf.TellPut();
SessionInfoHeader_t header; if ( !ReadSessionInfoHeader( buf.Base(), nFileSize, header ) ) { Msg( "Failed to read header information.\n" ); return; }
char szDigestStr[33]; V_binarytohex( header.m_aHash, sizeof( header.m_aHash ), szDigestStr, sizeof( szDigestStr ) );
Msg( "\n\theader:\n" ); Msg( "\n" ); Msg( "\t%27s: %u\n", "version", header.m_uVersion ); Msg( "\t%27s: %s\n", "session name", header.m_szSessionName ); Msg( "\t%27s: %s\n", "currently recording?", header.m_bRecording ? "yes" : "no" ); Msg( "\t%27s: %i\n", "# blocks", header.m_nNumBlocks ); Msg( "\t%27s: %s\n", "compressor", GetCompressorNameSafe( header.m_nCompressorType ) ); Msg( "\t%27s: %s\n", "md5 digest", szDigestStr ); Msg( "\t%27s: %u bytes\n", "payload size (compressed)", header.m_uPayloadSize ); Msg( "\t%27s: %u bytes\n", "payload size (uncompressed)", header.m_uPayloadSizeUC ); Msg( "\n" );
const uint8 *pPayload = (uint8 *)buf.Base() + sizeof( SessionInfoHeader_t ); uint32 uUncompressedPayloadSize = header.m_uPayloadSizeUC; if ( !g_pEngine->MD5_HashBuffer( header.m_aHash, (const uint8 *)pPayload, header.m_uPayloadSize, NULL ) ) { Msg( "Data validation failed.\n" ); return; }
const uint8 *pUncompressedPayload; bool bFreeUncompressedPayload = true;
if ( header.m_nCompressorType == COMPRESSORTYPE_INVALID ) { // The payload is already uncompressed - don't free, since this buffer was allocated by the CUtlBuffer "buf"
pUncompressedPayload = pPayload; bFreeUncompressedPayload = false; } else { if ( uUncompressedPayloadSize != header.m_uPayloadSizeUC ) { Msg( "Decompressed to a different size (%u) than specified by header (%u)\n", uUncompressedPayloadSize, header.m_uPayloadSizeUC ); return; }
ICompressor *pCompressor = CreateCompressor( header.m_nCompressorType ); if ( !pCompressor ) { Msg( "Failed to create compressor.\n" ); return; }
pUncompressedPayload = new uint8[ uUncompressedPayloadSize ]; if ( !pUncompressedPayload ) { Msg( "Failed to allocate uncompressed payload.\n" ); delete [] pCompressor; return; }
pCompressor->Decompress( (char *)pUncompressedPayload, &uUncompressedPayloadSize, (const char *)pPayload, header.m_uPayloadSize );
delete pCompressor; }
if ( uUncompressedPayloadSize <= MIN_SESSION_INFO_PAYLOAD_SIZE ) { Msg( "Uncompressed payload not large enough to read a single block.\n" ); } else { RecordingSessionBlockSpec_t DummyBlock; CUtlBuffer bufPayload( pUncompressedPayload, uUncompressedPayloadSize, CUtlBuffer::READ_ONLY );
Msg( "\n\tblocks:\n\n" ); Msg( "\t index status MD5 compressor size (uncompressed) size (compressed)\n" );
bool bBlockReadFailed = false; for ( int i = 0; i < header.m_nNumBlocks; ++i ) { // Attempt to read the current block from the buffer
bufPayload.Get( &DummyBlock, sizeof( DummyBlock ) ); if ( !bufPayload.IsValid() ) { bBlockReadFailed = true; break; }
V_binarytohex( DummyBlock.m_aHash, sizeof( DummyBlock.m_aHash ), szDigestStr, sizeof( szDigestStr ) );
Msg( "\t %5i", DummyBlock.m_iReconstruction ); Msg( "%20s", CBaseRecordingSessionBlock::GetRemoteStatusStringSafe( (CBaseRecordingSessionBlock::RemoteStatus_t)DummyBlock.m_uRemoteStatus ) ); Msg( "%35s", szDigestStr ); Msg( "%8s", GetCompressorNameSafe( (CompressorType_t)DummyBlock.m_nCompressorType ) ); Msg( "%20u", DummyBlock.m_uFileSize ); Msg( "%20u", DummyBlock.m_uUncompressedSize ); Msg( "\n" ); } }
Msg( "\n" );
if ( bFreeUncompressedPayload ) { delete [] pUncompressedPayload; } }
CON_COMMAND_F( replay_printsessioninfo, "Print session info", FCVAR_DONTRECORD ) { ENSURE_DEDICATED();
if ( args.ArgC() != 2 ) { Msg( "Usage: replay_printsessioninfo <full path and filename>\n" ); return; }
PrintSessionInfo( args[1] ); }
//----------------------------------------------------------------------------------------
|