csgo-2018-source/engine/blackbox.cpp
2021-07-24 21:11:47 -07:00

230 lines
4.5 KiB
C++

//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include "blackbox.h"
#include "tier0/basetypes.h"
#include "cmd.h"
#include "tier1/utllinkedlist.h"
#include "tier1/convar.h"
#include "tier1/fmtstr.h"
#include "tier1/interface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// development only, off by default for 360
ConVar blackbox( "blackbox", IsX360() ? "0" : "1" );
#define MAX_MESSAGE_SIZE 1024
#define DEFAULT_RECORD_LIMIT 16
static const char* gTypeMap[] =
{
"VCD",
"WAV",
"BOT",
NULL
};
struct CBlackBoxRecord
{
CBlackBoxRecord(const char *new_message)
{
m_time = Plat_FloatTime();
m_message = new char[strlen(new_message)+1];
strcpy(m_message, new_message);
}
~CBlackBoxRecord() { if (m_message) delete m_message; };
operator const char *() const
{
static CFmtStrN<MAX_MESSAGE_SIZE+16> buf;
double temp = m_time;
int hh = int(temp/(60*60));
int mm = int(temp/60) % 60;
float ss = temp - ((mm + (hh * 60)) * 60);
buf.sprintf( "[%02d:%02d:%02.3f]: %s", hh, mm, ss, m_message );
return buf;
}
double m_time;
char *m_message;
};
class CBlackBox: public IBlackBox
{
public:
CBlackBox();
~CBlackBox();
virtual void Record(int type, const char *msg);
virtual void SetLimit(int type, unsigned int count);
virtual const char *Get(int type, unsigned int index);
virtual int Count(int type);
virtual void Flush(int type);
virtual const char *GetTypeName(int type);
virtual int GetTypeCount();
enum Types {
VCD,
WAV,
BOT,
TYPE_COUNT
};
private:
bool ValidType(int type) { return (type >= 0 && type < TYPE_COUNT); };
CUtlVector<CBlackBoxRecord *> m_records[TYPE_COUNT];
uint m_record_limits[TYPE_COUNT];
};
CBlackBox gCBlackBox;
IBlackBox *gBlackBox = &gCBlackBox;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CBlackBox, IBlackBox, BLACKBOX_INTERFACE_VERSION, gCBlackBox );
CBlackBox::CBlackBox()
{
for ( int i = 0; i < TYPE_COUNT; i++ )
{
m_record_limits[i] = DEFAULT_RECORD_LIMIT;
}
}
CBlackBox::~CBlackBox()
{
for (int i = 0; i < TYPE_COUNT; i++)
{
Flush(i);
}
}
void CBlackBox::Record( int type, const char *msg )
{
if ( IsX360() || !blackbox.GetBool() )
return;
if ( !ValidType(type) )
return;
CBlackBoxRecord *new_record = new CBlackBoxRecord( msg );
m_records[type].AddToTail( new_record );
if ( (uint)m_records[type].Count() > m_record_limits[type] )
{
CBlackBoxRecord *old_record = m_records[type].Head();
m_records[type].Remove( 0 );
delete old_record;
}
}
void CBlackBox::SetLimit(int type, unsigned int count)
{
if ( !ValidType( type ))
return;
m_record_limits[type] = count;
}
const char *CBlackBox::Get( int type, unsigned int index )
{
if ( !ValidType( type ))
return NULL;
return (*m_records[type][index]);
}
const char *CBlackBox::GetTypeName( int type )
{
if ( !ValidType( type ))
return NULL;
return gTypeMap[type];
}
int CBlackBox::GetTypeCount()
{
return TYPE_COUNT;
}
int CBlackBox::Count( int type )
{
if ( !ValidType( type ))
return -1;
return m_records[type].Count();
}
void CBlackBox::Flush( int type )
{
if ( !ValidType( type ))
return;
m_records[type].PurgeAndDeleteElements();
}
CON_COMMAND_F( blackbox_record, "Record an entry into the blackbox", FCVAR_DONTRECORD )
{
if ( IsX360() || !blackbox.GetBool() )
return;
if ( args.ArgC() < 2 )
{
Msg( "Insufficient arguments to blackbox_record. Usage: blackbox_record <type> <message>\n" );
return;
}
BlackBox_Record( args[1], args[2] );
}
CON_COMMAND_F( blackbox_dump, "Dump the contents of the blackbox", FCVAR_DONTRECORD )
{
if ( IsX360() )
return;
for ( int type = 0; type < gBlackBox->GetTypeCount(); type++ )
{
for ( int i = 0; i < gBlackBox->Count(type); i++ )
{
Msg( "%s[%d]: %s\n", gBlackBox->GetTypeName( type ), i+1, gBlackBox->Get( type, i ) );
}
}
}
void BlackBox_Record( const char *type, const char *pFormat, ... )
{
if ( IsGameConsole() || !blackbox.GetBool() )
return;
int type_num;
for ( type_num = 0; type_num < gBlackBox->GetTypeCount(); type_num++ )
{
if ( !V_strcasecmp( gBlackBox->GetTypeName( type_num ), type ) )
break;
}
if ( type_num >= gBlackBox->GetTypeCount() )
{
Msg( "Invalid blackbox type: %s\n", type );
return;
}
char szMessage[1024];
va_list marker;
va_start( marker, pFormat);
Q_vsnprintf( szMessage, sizeof( szMessage ), pFormat, marker);
va_end( marker );
//Msg( "Record: %s: %s\n", type, szMessage );
gBlackBox->Record( type_num, szMessage );
}