mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-15 05:06:57 +00:00
1
This commit is contained in:
@@ -0,0 +1,456 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GAMESTATS_H
|
||||
#define GAMESTATS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utldict.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "igamesystem.h"
|
||||
//#include "steamworks_gamestats.h"
|
||||
|
||||
const int GAMESTATS_VERSION = 1;
|
||||
|
||||
enum StatSendType_t
|
||||
{
|
||||
STATSEND_LEVELSHUTDOWN,
|
||||
STATSEND_APPSHUTDOWN,
|
||||
STATSEND_NOTENOUGHPLAYERS,
|
||||
};
|
||||
|
||||
struct StatsBufferRecord_t
|
||||
{
|
||||
float m_flFrameRate; // fps
|
||||
float m_flServerPing; // client ping to server
|
||||
|
||||
};
|
||||
|
||||
#define STATS_WINDOW_SIZE ( 60 * 10 ) // # of records to hold
|
||||
#define STATS_RECORD_INTERVAL 1 // # of seconds between data grabs. 2 * 300 = every 10 minutes
|
||||
|
||||
class CGameStats;
|
||||
|
||||
void UpdatePerfStats( void );
|
||||
void SetGameStatsHandler( CGameStats *pGameStats );
|
||||
|
||||
class CBasePlayer;
|
||||
class CPropVehicleDriveable;
|
||||
class CTakeDamageInfo;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
#define GAMESTATS_STANDARD_NOT_SAVED 0xFEEDBEEF
|
||||
|
||||
enum GameStatsVersions_t
|
||||
{
|
||||
GAMESTATS_FILE_VERSION_OLD = 001,
|
||||
GAMESTATS_FILE_VERSION_OLD2,
|
||||
GAMESTATS_FILE_VERSION_OLD3,
|
||||
GAMESTATS_FILE_VERSION_OLD4,
|
||||
GAMESTATS_FILE_VERSION_OLD5,
|
||||
GAMESTATS_FILE_VERSION
|
||||
};
|
||||
|
||||
struct BasicGameStatsRecord_t
|
||||
{
|
||||
public:
|
||||
BasicGameStatsRecord_t() :
|
||||
m_nCount( 0 ),
|
||||
m_nSeconds( 0 ),
|
||||
m_nCommentary( 0 ),
|
||||
m_nHDR( 0 ),
|
||||
m_nCaptions( 0 ),
|
||||
m_bSteam( true ),
|
||||
m_bCyberCafe( false ),
|
||||
m_nDeaths( 0 )
|
||||
{
|
||||
Q_memset( m_nSkill, 0, sizeof( m_nSkill ) );
|
||||
}
|
||||
|
||||
void Clear();
|
||||
|
||||
void SaveToBuffer( CUtlBuffer& buf );
|
||||
bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion );
|
||||
|
||||
// Data
|
||||
public:
|
||||
int m_nCount;
|
||||
int m_nSeconds;
|
||||
|
||||
int m_nCommentary;
|
||||
int m_nHDR;
|
||||
int m_nCaptions;
|
||||
int m_nSkill[ 3 ];
|
||||
bool m_bSteam;
|
||||
bool m_bCyberCafe;
|
||||
int m_nDeaths;
|
||||
};
|
||||
|
||||
struct BasicGameStats_t
|
||||
{
|
||||
public:
|
||||
BasicGameStats_t() :
|
||||
m_nSecondsToCompleteGame( 0 ),
|
||||
m_nHL2ChaptureUnlocked( 0 ),
|
||||
m_bSteam( true ),
|
||||
m_bCyberCafe( false ),
|
||||
m_nDXLevel( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void Clear();
|
||||
|
||||
void SaveToBuffer( CUtlBuffer& buf );
|
||||
bool ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion );
|
||||
|
||||
BasicGameStatsRecord_t *FindOrAddRecordForMap( char const *mapname );
|
||||
|
||||
// Data
|
||||
public:
|
||||
int m_nSecondsToCompleteGame; // 0 means they haven't finished playing yet
|
||||
|
||||
BasicGameStatsRecord_t m_Summary; // Summary record
|
||||
CUtlDict< BasicGameStatsRecord_t, unsigned short > m_MapTotals;
|
||||
bool m_bSteam;
|
||||
bool m_bCyberCafe;
|
||||
int m_nHL2ChaptureUnlocked;
|
||||
int m_nDXLevel;
|
||||
};
|
||||
#endif // GAME_DLL
|
||||
|
||||
class CBaseGameStats
|
||||
{
|
||||
public:
|
||||
CBaseGameStats();
|
||||
|
||||
// override this to declare what format you want to send. New products should use new format.
|
||||
virtual bool UseOldFormat()
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
return true; // servers by default send old format for backward compat
|
||||
#else
|
||||
return false; // clients never used old format so no backward compat issues, they use new format by default
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implement this if you support new format gamestats.
|
||||
// Return true if you added data to KeyValues, false if you have no data to report
|
||||
virtual bool AddDataForSend( KeyValues *pKV, StatSendType_t sendType ) { return false; }
|
||||
|
||||
// These methods used for new format gamestats only and control when data gets sent.
|
||||
virtual bool ShouldSendDataOnLevelShutdown()
|
||||
{
|
||||
// by default, servers send data at every level change and clients don't
|
||||
#ifdef GAME_DLL
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
virtual bool ShouldSendDataOnAppShutdown()
|
||||
{
|
||||
// by default, clients send data at app shutdown and servers don't
|
||||
#ifdef GAME_DLL
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Event_Init( void );
|
||||
virtual void Event_Shutdown( void );
|
||||
virtual void Event_MapChange( const char *szOldMapName, const char *szNewMapName );
|
||||
virtual void Event_LevelInit( void );
|
||||
virtual void Event_LevelShutdown( float flElapsed );
|
||||
virtual void Event_SaveGame( void );
|
||||
virtual void Event_LoadGame( void );
|
||||
|
||||
void CollectData( StatSendType_t sendType );
|
||||
void SendData();
|
||||
|
||||
void StatsLog( PRINTF_FORMAT_STRING char const *fmt, ... );
|
||||
|
||||
// This is the first call made, so that we can "subclass" the CBaseGameStats based on gamedir as needed (e.g., ep2 vs. episodic)
|
||||
virtual CBaseGameStats *OnInit( CBaseGameStats *pCurrentGameStats, char const *gamedir ) { return pCurrentGameStats; }
|
||||
|
||||
// Frees up data from gamestats and resets it to a clean state.
|
||||
virtual void Clear( void );
|
||||
|
||||
virtual bool StatTrackingEnabledForMod( void ) { return false; } //Override this to turn on the system. Stat tracking is disabled by default and will always be disabled at the user's request
|
||||
static bool StatTrackingAllowed( void ); //query whether stat tracking is possible and warranted by the user
|
||||
virtual bool HaveValidData( void ) { return true; } // whether we currently have an interesting enough data set to upload. Called at upload time; if false, data is not uploaded.
|
||||
|
||||
virtual bool ShouldTrackStandardStats( void ) { return true; } //exactly what was tracked for EP1 release
|
||||
|
||||
//Get mod specific strings used for tracking, defaults should work fine for most cases
|
||||
virtual const char *GetStatSaveFileName( void );
|
||||
virtual const char *GetStatUploadRegistryKeyName( void );
|
||||
const char *GetUserPseudoUniqueID( void );
|
||||
|
||||
virtual bool UserPlayedAllTheMaps( void ) { return false; } //be sure to override this to determine user completion time
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual void Event_AchievementProgress( int achievementID, const char* achievementName ) {}
|
||||
#endif
|
||||
|
||||
#ifdef GAME_DLL
|
||||
virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info );
|
||||
virtual void Event_PlayerConnected( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerDisconnected( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info );
|
||||
virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info );
|
||||
virtual void Event_PlayerSuicide( CBasePlayer* pPlayer ) {}
|
||||
virtual void Event_Credits();
|
||||
virtual void Event_Commentary();
|
||||
virtual void Event_CrateSmashed();
|
||||
virtual void Event_Punted( CBaseEntity *pObject );
|
||||
virtual void Event_PlayerTraveled( CBasePlayer *pBasePlayer, float distanceInInches, bool bInVehicle, bool bSprinting );
|
||||
virtual void Event_WeaponFired( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName );
|
||||
virtual void Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info );
|
||||
virtual void Event_FlippedVehicle( CBasePlayer *pDriver, CPropVehicleDriveable *pVehicle );
|
||||
virtual void Event_PreSaveGameLoaded( char const *pSaveName, bool bInGame );
|
||||
virtual void Event_PlayerEnteredGodMode( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_PlayerEnteredNoClip( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_DecrementPlayerEnteredNoClip( CBasePlayer *pBasePlayer );
|
||||
virtual void Event_IncrementCountedStatistic( const Vector& vecAbsOrigin, char const *pchStatisticName, float flIncrementAmount );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN
|
||||
// [dwenger] Functions necessary for cs-specific stats
|
||||
//=============================================================================
|
||||
virtual void Event_WindowShattered( CBasePlayer *pPlayer );
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
//custom data to tack onto existing stats if you're not doing a complete overhaul
|
||||
virtual void AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer ) { } //custom data you want thrown into the default save and upload path
|
||||
virtual void LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer ) { }; //when loading the saved stats file, this will point to where you started saving data to the save buffer
|
||||
|
||||
virtual void LoadingEvent_PlayerIDDifferentThanLoadedStats( void ); //Only called if you use the base SaveToFileNOW() and LoadFromFile() functions. Used in case you want to keep/invalidate data that was just loaded.
|
||||
|
||||
virtual bool LoadFromFile( void ); //called just before Event_Init()
|
||||
virtual bool SaveToFileNOW( bool bForceSyncWrite = false ); //saves buffers to their respective files now, returns success or failure
|
||||
virtual bool UploadStatsFileNOW( void ); //uploads data to the CSER now, returns success or failure
|
||||
|
||||
static bool AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData );
|
||||
static bool GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive = false );
|
||||
static void LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData );
|
||||
|
||||
//default save behavior is to save on level shutdown, and game shutdown
|
||||
virtual bool AutoSave_OnInit( void ) { return false; }
|
||||
virtual bool AutoSave_OnShutdown( void ) { return true; }
|
||||
virtual bool AutoSave_OnMapChange( void ) { return false; }
|
||||
virtual bool AutoSave_OnLevelInit( void ) { return false; }
|
||||
virtual bool AutoSave_OnLevelShutdown( void ) { return true; }
|
||||
|
||||
//default upload behavior is to upload on game shutdown
|
||||
virtual bool AutoUpload_OnInit( void ) { return false; }
|
||||
virtual bool AutoUpload_OnShutdown( void ) { return true; }
|
||||
virtual bool AutoUpload_OnMapChange( void ) { return false; }
|
||||
virtual bool AutoUpload_OnLevelInit( void ) { return false; }
|
||||
virtual bool AutoUpload_OnLevelShutdown( void ) { return false; }
|
||||
|
||||
// Helper for builtin stuff
|
||||
void SetSteamStatistic( bool bUsingSteam );
|
||||
void SetCyberCafeStatistic( bool bIsCyberCafeUser );
|
||||
void SetHDRStatistic( bool bHDREnabled );
|
||||
void SetCaptionsStatistic( bool bClosedCaptionsEnabled );
|
||||
void SetSkillStatistic( int iSkillSetting );
|
||||
void SetDXLevelStatistic( int iDXLevel );
|
||||
void SetHL2UnlockedChapterStatistic( void );
|
||||
#endif // GAMEDLL
|
||||
public:
|
||||
#ifdef GAME_DLL
|
||||
BasicGameStats_t m_BasicStats; //exposed in case you do a complete overhaul and still want to save it
|
||||
#endif
|
||||
bool m_bLogging : 1;
|
||||
bool m_bLoggingToFile : 1;
|
||||
};
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &SaveBuffer -
|
||||
// iLump -
|
||||
// iLumpCount -
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CBaseGameStats::AppendLump( int nMaxLumpCount, CUtlBuffer &SaveBuffer, unsigned short iLump, unsigned short iLumpCount, size_t nSize, void *pData )
|
||||
{
|
||||
// Verify the lump index.
|
||||
Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) );
|
||||
|
||||
if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) )
|
||||
return false;
|
||||
|
||||
// Check to see if we have any elements to save.
|
||||
if ( iLumpCount <= 0 )
|
||||
return false;
|
||||
|
||||
// Write the lump id and element count.
|
||||
SaveBuffer.PutUnsignedShort( iLump );
|
||||
SaveBuffer.PutUnsignedShort( iLumpCount );
|
||||
|
||||
size_t nTotalSize = iLumpCount * nSize;
|
||||
SaveBuffer.Put( pData, nTotalSize );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &LoadBuffer -
|
||||
// &iLump -
|
||||
// &iLumpCount -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool CBaseGameStats::GetLumpHeader( int nMaxLumpCount, CUtlBuffer &LoadBuffer, unsigned short &iLump, unsigned short &iLumpCount, bool bPermissive /*= false*/ )
|
||||
{
|
||||
// Get the lump id and element count.
|
||||
iLump = LoadBuffer.GetUnsignedShort();
|
||||
if ( !LoadBuffer.IsValid() )
|
||||
{
|
||||
// check for EOF
|
||||
return false;
|
||||
}
|
||||
iLumpCount = LoadBuffer.GetUnsignedShort();
|
||||
|
||||
if ( bPermissive )
|
||||
return true;
|
||||
|
||||
// Verify the lump index.
|
||||
Assert( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) );
|
||||
if ( !( ( iLump > 0 ) && ( iLump < nMaxLumpCount ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if we have any elements to save.
|
||||
if ( iLumpCount <= 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads 1 or more lumps of raw data
|
||||
// Input : &LoadBuffer - buffer to be read from
|
||||
// iLumpCount - # of lumps to read
|
||||
// nSize - size of each lump
|
||||
// pData - where to store the data
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CBaseGameStats::LoadLump( CUtlBuffer &LoadBuffer, unsigned short iLumpCount, size_t nSize, void *pData )
|
||||
{
|
||||
LoadBuffer.Get( pData, iLumpCount * nSize );
|
||||
}
|
||||
|
||||
#endif // GAME_DLL
|
||||
|
||||
// Moving the extern out of the GAME_DLL block so that the client can access it
|
||||
extern CBaseGameStats *gamestats; //starts out pointing at a singleton of the class above, overriding this in any constructor should work for replacing it
|
||||
|
||||
//used to drive most of the game stat event handlers as well as track basic stats under the hood of CBaseGameStats
|
||||
class CBaseGameStats_Driver : public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
CBaseGameStats_Driver( void );
|
||||
|
||||
typedef CAutoGameSystemPerFrame BaseClass;
|
||||
|
||||
// IGameSystem overloads
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
// Level init, shutdown
|
||||
virtual void LevelInitPreEntity();
|
||||
virtual void LevelShutdownPreEntity();
|
||||
virtual void LevelShutdownPreClearSteamAPIContext();
|
||||
virtual void LevelShutdown();
|
||||
// Called during game save
|
||||
virtual void OnSave();
|
||||
// Called during game restore, after the local player has connected and entities have been fully restored
|
||||
virtual void OnRestore();
|
||||
|
||||
virtual void FrameUpdatePostEntityThink();
|
||||
|
||||
void PossibleMapChange( void );
|
||||
|
||||
void CollectData( StatSendType_t sendType );
|
||||
void SendData();
|
||||
void ResetData();
|
||||
bool AddBaseDataForSend( KeyValues *pKV, StatSendType_t sendType );
|
||||
|
||||
StatsBufferRecord_t m_StatsBuffer[STATS_WINDOW_SIZE];
|
||||
bool m_bBufferFull;
|
||||
int m_nWriteIndex;
|
||||
float m_flLastRealTime;
|
||||
float m_flLastSampleTime;
|
||||
float m_flTotalTimeInLevels;
|
||||
int m_iNumLevels;
|
||||
bool m_bDidVoiceChat; // Did the player use voice chat at ALL this map?
|
||||
|
||||
template<class T> T AverageStat( T StatsBufferRecord_t::*field ) const
|
||||
{
|
||||
T sum = 0;
|
||||
for( int i = 0; i < STATS_WINDOW_SIZE; i++ )
|
||||
sum += m_StatsBuffer[i].*field;
|
||||
return sum / STATS_WINDOW_SIZE;
|
||||
}
|
||||
|
||||
template<class T> T MaxStat( T StatsBufferRecord_t::*field ) const
|
||||
{
|
||||
T maxsofar = -16000000;
|
||||
for( int i = 0; i < STATS_WINDOW_SIZE; i++ )
|
||||
maxsofar = MAX( maxsofar, m_StatsBuffer[i].*field );
|
||||
return maxsofar;
|
||||
}
|
||||
|
||||
template<class T> T MinStat( T StatsBufferRecord_t::*field ) const
|
||||
{
|
||||
T minsofar = 16000000;
|
||||
for( int i = 0; i < STATS_WINDOW_SIZE; i++ )
|
||||
minsofar = MIN( minsofar, m_StatsBuffer[i].*field );
|
||||
return minsofar;
|
||||
}
|
||||
|
||||
inline void AdvanceIndex( void )
|
||||
{
|
||||
m_nWriteIndex++;
|
||||
if ( m_nWriteIndex == STATS_WINDOW_SIZE )
|
||||
{
|
||||
m_nWriteIndex = 0;
|
||||
m_bBufferFull = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePerfStats( void );
|
||||
|
||||
CUtlString m_PrevMapName; //used to track "OnMapChange" events
|
||||
int m_iLoadedVersion;
|
||||
char m_szLoadedUserID[ 17 ]; // GUID
|
||||
|
||||
bool m_bEnabled; //false if incapable of uploading or the user doesn't want to enable stat tracking
|
||||
bool m_bShuttingDown;
|
||||
bool m_bInLevel;
|
||||
bool m_bFirstLevel;
|
||||
time_t m_tLastUpload;
|
||||
|
||||
float m_flLevelStartTime;
|
||||
|
||||
bool m_bStationary;
|
||||
float m_flLastMovementTime;
|
||||
CUserCmd m_LastUserCmd;
|
||||
bool m_bGamePaused;
|
||||
float m_flPauseStartTime;
|
||||
|
||||
CGamestatsData *m_pGamestatsData;
|
||||
};
|
||||
|
||||
#endif // GAMESTATS_H
|
||||
Reference in New Issue
Block a user