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.
208 lines
6.2 KiB
208 lines
6.2 KiB
//========= 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] ); |
|
} |
|
|
|
//----------------------------------------------------------------------------------------
|
|
|