mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 14:16:50 +00:00
825 lines
22 KiB
C++
825 lines
22 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================
|
|
#ifndef CS_GAMESTATS_SHARED_H
|
|
#define CS_GAMESTATS_SHARED_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
#include "cbase.h"
|
|
// #include "tier1/utlvector.h"
|
|
// #include "tier1/utldict.h"
|
|
#include "shareddefs.h"
|
|
#include "cs_shareddefs.h"
|
|
#include "cs_weapon_parse.h"
|
|
#include "fmtstr.h"
|
|
|
|
|
|
#define CS_NUM_LEVELS 18
|
|
|
|
//=============================================================================
|
|
// Helper class for simple manipulation of bit arrays.
|
|
// Used for server->client packets containing delta stats
|
|
//=============================================================================
|
|
|
|
template <int BitLength>
|
|
class BitArray
|
|
{
|
|
enum { ByteLength = (BitLength + 7) / 8 };
|
|
public:
|
|
BitArray() { ClearAll(); }
|
|
|
|
void SetBit(int n) { m_bytes[n / 8] |= 1 << (n & 7); }
|
|
void ClearBit(int n) { m_bytes[n / 8] &= (~(1 << (n & 7))); }
|
|
bool IsBitSet(int n) const { return (m_bytes[n / 8] & (1 << (n & 7))) != 0;}
|
|
|
|
void ClearAll() { V_memset(m_bytes, 0, sizeof(m_bytes)); }
|
|
int NumBits() { return BitLength; }
|
|
int NumBytes() { return ByteLength; }
|
|
|
|
byte* RawPointer() { return m_bytes; }
|
|
|
|
private:
|
|
byte m_bytes[ByteLength];
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// CS Game Stats Enums
|
|
//
|
|
// WARNING! ANY CHANGE TO THE ORDERING OR NUMBER OF STATS WILL REQUIRE
|
|
// SYNCHRONOUS UPDATE OF CLIENT AND SERVER DLLS. If you change these enums
|
|
// (including adding new stats) without forcing an update of both the client
|
|
// and server, stats will become corrupted on the game client and these
|
|
// corrupted values will be uploaded to steam, which is very very bad.
|
|
//
|
|
// If you add new stats, if will be safest to add them at the end of the enum
|
|
// (although this will still require a server update); make sure you also add
|
|
// the stats to the CSStatProperty_Table in cs_gamestats_shared.cpp at the
|
|
// appropriate location.
|
|
|
|
enum CSStatType_t
|
|
{
|
|
CSSTAT_UNDEFINED = -1,
|
|
CSSTAT_SHOTS_HIT,
|
|
CSSTAT_SHOTS_FIRED,
|
|
CSSTAT_KILLS,
|
|
CSSTAT_DEATHS,
|
|
CSSTAT_DAMAGE,
|
|
CSSTAT_NUM_BOMBS_PLANTED,
|
|
CSSTAT_NUM_BOMBS_DEFUSED,
|
|
CSSTAT_PLAYTIME,
|
|
CSSTAT_ROUNDS_WON,
|
|
CSSTAT_T_ROUNDS_WON,
|
|
CSSTAT_CT_ROUNDS_WON,
|
|
CSSTAT_ROUNDS_PLAYED,
|
|
CSSTAT_PISTOLROUNDS_WON,
|
|
CSSTAT_MONEY_EARNED,
|
|
CSSTAT_OBJECTIVES_COMPLETED,
|
|
CSSTAT_BOMBS_DEFUSED_WITHKIT,
|
|
|
|
CSSTAT_KILLS_DEAGLE,
|
|
CSSTAT_KILLS_USP,
|
|
CSSTAT_KILLS_GLOCK,
|
|
CSSTAT_KILLS_P228,
|
|
CSSTAT_KILLS_ELITE,
|
|
CSSTAT_KILLS_FIVESEVEN,
|
|
CSSTAT_KILLS_AWP,
|
|
CSSTAT_KILLS_AK47,
|
|
CSSTAT_KILLS_M4A1,
|
|
CSSTAT_KILLS_AUG,
|
|
CSSTAT_KILLS_SG552,
|
|
CSSTAT_KILLS_SG550,
|
|
CSSTAT_KILLS_GALIL,
|
|
CSSTAT_KILLS_FAMAS,
|
|
CSSTAT_KILLS_SCOUT,
|
|
CSSTAT_KILLS_G3SG1,
|
|
CSSTAT_KILLS_P90,
|
|
CSSTAT_KILLS_MP5NAVY,
|
|
CSSTAT_KILLS_TMP,
|
|
CSSTAT_KILLS_MAC10,
|
|
CSSTAT_KILLS_UMP45,
|
|
CSSTAT_KILLS_M3,
|
|
CSSTAT_KILLS_XM1014,
|
|
CSSTAT_KILLS_M249,
|
|
CSSTAT_KILLS_KNIFE,
|
|
CSSTAT_KILLS_HEGRENADE,
|
|
|
|
CSSTAT_SHOTS_DEAGLE,
|
|
CSSTAT_SHOTS_USP,
|
|
CSSTAT_SHOTS_GLOCK,
|
|
CSSTAT_SHOTS_P228,
|
|
CSSTAT_SHOTS_ELITE,
|
|
CSSTAT_SHOTS_FIVESEVEN,
|
|
CSSTAT_SHOTS_AWP,
|
|
CSSTAT_SHOTS_AK47,
|
|
CSSTAT_SHOTS_M4A1,
|
|
CSSTAT_SHOTS_AUG,
|
|
CSSTAT_SHOTS_SG552,
|
|
CSSTAT_SHOTS_SG550,
|
|
CSSTAT_SHOTS_GALIL,
|
|
CSSTAT_SHOTS_FAMAS,
|
|
CSSTAT_SHOTS_SCOUT,
|
|
CSSTAT_SHOTS_G3SG1,
|
|
CSSTAT_SHOTS_P90,
|
|
CSSTAT_SHOTS_MP5NAVY,
|
|
CSSTAT_SHOTS_TMP,
|
|
CSSTAT_SHOTS_MAC10,
|
|
CSSTAT_SHOTS_UMP45,
|
|
CSSTAT_SHOTS_M3,
|
|
CSSTAT_SHOTS_XM1014,
|
|
CSSTAT_SHOTS_M249,
|
|
CSSTAT_SHOTS_KNIFE,
|
|
CSSTAT_SHOTS_HEGRENADE,
|
|
|
|
CSSTAT_HITS_DEAGLE,
|
|
CSSTAT_HITS_USP,
|
|
CSSTAT_HITS_GLOCK,
|
|
CSSTAT_HITS_P228,
|
|
CSSTAT_HITS_ELITE,
|
|
CSSTAT_HITS_FIVESEVEN,
|
|
CSSTAT_HITS_AWP,
|
|
CSSTAT_HITS_AK47,
|
|
CSSTAT_HITS_M4A1,
|
|
CSSTAT_HITS_AUG,
|
|
CSSTAT_HITS_SG552,
|
|
CSSTAT_HITS_SG550,
|
|
CSSTAT_HITS_GALIL,
|
|
CSSTAT_HITS_FAMAS,
|
|
CSSTAT_HITS_SCOUT,
|
|
CSSTAT_HITS_G3SG1,
|
|
CSSTAT_HITS_P90,
|
|
CSSTAT_HITS_MP5NAVY,
|
|
CSSTAT_HITS_TMP,
|
|
CSSTAT_HITS_MAC10,
|
|
CSSTAT_HITS_UMP45,
|
|
CSSTAT_HITS_M3,
|
|
CSSTAT_HITS_XM1014,
|
|
CSSTAT_HITS_M249,
|
|
CSSTAT_HITS_KNIFE,
|
|
CSSTAT_HITS_HEGRENADE,
|
|
|
|
CSSTAT_DAMAGE_DEAGLE,
|
|
CSSTAT_DAMAGE_USP,
|
|
CSSTAT_DAMAGE_GLOCK,
|
|
CSSTAT_DAMAGE_P228,
|
|
CSSTAT_DAMAGE_ELITE,
|
|
CSSTAT_DAMAGE_FIVESEVEN,
|
|
CSSTAT_DAMAGE_AWP,
|
|
CSSTAT_DAMAGE_AK47,
|
|
CSSTAT_DAMAGE_M4A1,
|
|
CSSTAT_DAMAGE_AUG,
|
|
CSSTAT_DAMAGE_SG552,
|
|
CSSTAT_DAMAGE_SG550,
|
|
CSSTAT_DAMAGE_GALIL,
|
|
CSSTAT_DAMAGE_FAMAS,
|
|
CSSTAT_DAMAGE_SCOUT,
|
|
CSSTAT_DAMAGE_G3SG1,
|
|
CSSTAT_DAMAGE_P90,
|
|
CSSTAT_DAMAGE_MP5NAVY,
|
|
CSSTAT_DAMAGE_TMP,
|
|
CSSTAT_DAMAGE_MAC10,
|
|
CSSTAT_DAMAGE_UMP45,
|
|
CSSTAT_DAMAGE_M3,
|
|
CSSTAT_DAMAGE_XM1014,
|
|
CSSTAT_DAMAGE_M249,
|
|
CSSTAT_DAMAGE_KNIFE,
|
|
CSSTAT_DAMAGE_HEGRENADE,
|
|
|
|
CSSTAT_KILLS_HEADSHOT,
|
|
CSSTAT_KILLS_ENEMY_BLINDED,
|
|
CSSTAT_KILLS_WHILE_BLINDED,
|
|
CSSTAT_KILLS_WITH_LAST_ROUND,
|
|
CSSTAT_KILLS_ENEMY_WEAPON,
|
|
CSSTAT_KILLS_KNIFE_FIGHT,
|
|
CSSTAT_KILLS_WHILE_DEFENDING_BOMB,
|
|
|
|
CSSTAT_DECAL_SPRAYS,
|
|
CSSTAT_TOTAL_JUMPS,
|
|
CSSTAT_NIGHTVISION_DAMAGE,
|
|
CSSTAT_KILLS_WHILE_LAST_PLAYER_ALIVE,
|
|
CSSTAT_KILLS_ENEMY_WOUNDED,
|
|
CSSTAT_FALL_DAMAGE,
|
|
|
|
CSSTAT_NUM_HOSTAGES_RESCUED,
|
|
|
|
CSSTAT_NUM_BROKEN_WINDOWS,
|
|
CSSTAT_PROPSBROKEN_ALL,
|
|
CSSTAT_PROPSBROKEN_MELON,
|
|
CSSTAT_PROPSBROKEN_OFFICEELECTRONICS,
|
|
CSSTAT_PROPSBROKEN_OFFICERADIO,
|
|
CSSTAT_PROPSBROKEN_OFFICEJUNK,
|
|
CSSTAT_PROPSBROKEN_ITALY_MELON,
|
|
|
|
CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER,
|
|
|
|
CSSTAT_WEAPONS_DONATED,
|
|
|
|
CSSTAT_ITEMS_PURCHASED,
|
|
CSSTAT_MONEY_SPENT,
|
|
|
|
CSSTAT_DOMINATIONS,
|
|
CSSTAT_DOMINATION_OVERKILLS,
|
|
CSSTAT_REVENGES,
|
|
|
|
CSSTAT_MVPS,
|
|
|
|
CSSTAT_GRENADE_DAMAGE,
|
|
CSSTAT_GRENADE_POSTHUMOUSKILLS,
|
|
CSSTAT_GRENADES_THROWN,
|
|
|
|
CSTAT_ITEMS_DROPPED_VALUE,
|
|
|
|
//Map win stats
|
|
CSSTAT_MAP_WINS_CS_ASSAULT,
|
|
CSSTAT_MAP_WINS_CS_COMPOUND,
|
|
CSSTAT_MAP_WINS_CS_HAVANA,
|
|
CSSTAT_MAP_WINS_CS_ITALY,
|
|
CSSTAT_MAP_WINS_CS_MILITIA,
|
|
CSSTAT_MAP_WINS_CS_OFFICE,
|
|
CSSTAT_MAP_WINS_DE_AZTEC,
|
|
CSSTAT_MAP_WINS_DE_CBBLE,
|
|
CSSTAT_MAP_WINS_DE_CHATEAU,
|
|
CSSTAT_MAP_WINS_DE_DUST2,
|
|
CSSTAT_MAP_WINS_DE_DUST,
|
|
CSSTAT_MAP_WINS_DE_INFERNO,
|
|
CSSTAT_MAP_WINS_DE_NUKE,
|
|
CSSTAT_MAP_WINS_DE_PIRANESI,
|
|
CSSTAT_MAP_WINS_DE_PORT,
|
|
CSSTAT_MAP_WINS_DE_PRODIGY,
|
|
CSSTAT_MAP_WINS_DE_TIDES,
|
|
CSSTAT_MAP_WINS_DE_TRAIN,
|
|
|
|
CSSTAT_MAP_ROUNDS_CS_ASSAULT,
|
|
CSSTAT_MAP_ROUNDS_CS_COMPOUND,
|
|
CSSTAT_MAP_ROUNDS_CS_HAVANA,
|
|
CSSTAT_MAP_ROUNDS_CS_ITALY,
|
|
CSSTAT_MAP_ROUNDS_CS_MILITIA,
|
|
CSSTAT_MAP_ROUNDS_CS_OFFICE,
|
|
CSSTAT_MAP_ROUNDS_DE_AZTEC,
|
|
CSSTAT_MAP_ROUNDS_DE_CBBLE,
|
|
CSSTAT_MAP_ROUNDS_DE_CHATEAU,
|
|
CSSTAT_MAP_ROUNDS_DE_DUST2,
|
|
CSSTAT_MAP_ROUNDS_DE_DUST,
|
|
CSSTAT_MAP_ROUNDS_DE_INFERNO,
|
|
CSSTAT_MAP_ROUNDS_DE_NUKE,
|
|
CSSTAT_MAP_ROUNDS_DE_PIRANESI,
|
|
CSSTAT_MAP_ROUNDS_DE_PORT,
|
|
CSSTAT_MAP_ROUNDS_DE_PRODIGY,
|
|
CSSTAT_MAP_ROUNDS_DE_TIDES,
|
|
CSSTAT_MAP_ROUNDS_DE_TRAIN,
|
|
|
|
CSSTAT_LASTMATCH_T_ROUNDS_WON,
|
|
CSSTAT_LASTMATCH_CT_ROUNDS_WON,
|
|
CSSTAT_LASTMATCH_ROUNDS_WON,
|
|
CSSTAT_LASTMATCH_KILLS,
|
|
CSSTAT_LASTMATCH_DEATHS,
|
|
CSSTAT_LASTMATCH_MVPS,
|
|
CSSTAT_LASTMATCH_DAMAGE,
|
|
CSSTAT_LASTMATCH_MONEYSPENT,
|
|
CSSTAT_LASTMATCH_DOMINATIONS,
|
|
CSSTAT_LASTMATCH_REVENGES,
|
|
CSSTAT_LASTMATCH_MAX_PLAYERS,
|
|
CSSTAT_LASTMATCH_FAVWEAPON_ID,
|
|
CSSTAT_LASTMATCH_FAVWEAPON_SHOTS,
|
|
CSSTAT_LASTMATCH_FAVWEAPON_HITS,
|
|
CSSTAT_LASTMATCH_FAVWEAPON_KILLS,
|
|
|
|
CSSTAT_MAX //Must be last entry.
|
|
};
|
|
|
|
|
|
#define CSSTAT_FIRST (CSSTAT_UNDEFINED+1)
|
|
#define CSSTAT_LAST (CSSTAT_MAX-1)
|
|
|
|
//
|
|
// CS Game Stats Flags
|
|
//
|
|
#define CSSTAT_PRIORITY_MASK 0x000F
|
|
#define CSSTAT_PRIORITY_NEVER 0x0000 // not sent to client
|
|
#define CSSTAT_PRIORITY_ENDROUND 0x0001 // sent at end of round
|
|
#define CSSTAT_PRIORITY_LOW 0x0002 // sent every 2500ms
|
|
#define CSSTAT_PRIORITY_HIGH 0x0003 // sent every 250ms
|
|
|
|
struct CSStatProperty
|
|
{
|
|
int statId; // verify that table ordering is correct
|
|
const char* szSteamName; // name of the stat on steam
|
|
const char* szLocalizationToken; // localization token for the stat
|
|
uint flags; // priority flags for sending to client
|
|
};
|
|
|
|
extern CSStatProperty CSStatProperty_Table[];
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// CS Player Round Stats
|
|
//
|
|
struct StatsCollection_t
|
|
{
|
|
StatsCollection_t() { Reset(); }
|
|
|
|
inline int Get( int i ) const
|
|
{
|
|
AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
|
|
if ( i >= 0 )
|
|
return m_iValue[ i ];
|
|
return 0;
|
|
}
|
|
|
|
inline void Set( int i, int nValue )
|
|
{
|
|
AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
|
|
if ( i >= 0 )
|
|
m_iValue[ i ] = nValue;
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_iValue ); i++ )
|
|
{
|
|
m_iValue[i] = 0;
|
|
}
|
|
}
|
|
|
|
int operator[] ( int index ) const
|
|
{
|
|
Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
|
|
return m_iValue[index];
|
|
}
|
|
|
|
int& operator[] ( int index )
|
|
{
|
|
Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
|
|
return m_iValue[index];
|
|
}
|
|
|
|
void Aggregate( const StatsCollection_t& other );
|
|
|
|
private:
|
|
int m_iValue[CSSTAT_MAX];
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
// HPE_BEGIN:
|
|
// [tj] A couple variations on the RoundStats structure to handle extra operations
|
|
// for averaging and accumulating
|
|
//=============================================================================
|
|
struct RoundStatsDirectAverage_t
|
|
{
|
|
float m_fStat[CSSTAT_MAX];
|
|
|
|
|
|
RoundStatsDirectAverage_t()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] = 0;
|
|
}
|
|
}
|
|
|
|
RoundStatsDirectAverage_t& operator +=( const StatsCollection_t &other )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] += other[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RoundStatsDirectAverage_t& operator /=( const float &divisor)
|
|
{
|
|
if (divisor > 0)
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] /= divisor;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RoundStatsDirectAverage_t& operator *=( const float &divisor)
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] *= divisor;
|
|
}
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
struct RoundStatsRollingAverage_t
|
|
{
|
|
float m_fStat[CSSTAT_MAX];
|
|
int m_numberOfDataSets;
|
|
|
|
RoundStatsRollingAverage_t()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] = 0;
|
|
}
|
|
m_numberOfDataSets = 0;
|
|
}
|
|
|
|
RoundStatsRollingAverage_t& operator +=( const RoundStatsRollingAverage_t &other )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] += other.m_fStat[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RoundStatsRollingAverage_t& operator +=( const StatsCollection_t &other )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] += other[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RoundStatsRollingAverage_t& operator /=( const float &divisor)
|
|
{
|
|
if (divisor > 0)
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] /= divisor;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void RollDataSetIntoAverage ( const RoundStatsRollingAverage_t &other )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
|
|
{
|
|
m_fStat[i] *= m_numberOfDataSets;
|
|
m_fStat[i] += other.m_fStat[i];
|
|
m_fStat[i] /= (m_numberOfDataSets + 1);
|
|
}
|
|
m_numberOfDataSets++;
|
|
}
|
|
};
|
|
//=============================================================================
|
|
// HPE_END
|
|
//=============================================================================
|
|
|
|
enum CSGameStatsVersions_t
|
|
{
|
|
CS_GAMESTATS_FILE_VERSION = 006,
|
|
CS_GAMESTATS_MAGIC = 0xDEADBEEF
|
|
};
|
|
|
|
struct CS_Gamestats_Version_t
|
|
{
|
|
int m_iMagic; // always CS_GAMESTATS_MAGIC
|
|
int m_iVersion;
|
|
};
|
|
|
|
|
|
struct KillStats_t
|
|
{
|
|
KillStats_t() { Reset(); }
|
|
|
|
void Reset()
|
|
{
|
|
Q_memset( iNumKilled, 0, sizeof( iNumKilled ) );
|
|
Q_memset( iNumKilledBy, 0, sizeof( iNumKilledBy ) );
|
|
Q_memset( iNumKilledByUnanswered, 0, sizeof( iNumKilledByUnanswered ) );
|
|
}
|
|
|
|
int iNumKilled[MAX_PLAYERS+1]; // how many times this player has killed each other player
|
|
int iNumKilledBy[MAX_PLAYERS+1]; // how many times this player has been killed by each other player
|
|
int iNumKilledByUnanswered[MAX_PLAYERS+1]; // how many unanswered kills this player has been dealt by each other player
|
|
};
|
|
|
|
//=============================================================================
|
|
//
|
|
// CS Player Stats
|
|
//
|
|
struct PlayerStats_t
|
|
{
|
|
PlayerStats_t()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
statsDelta.Reset();
|
|
statsCurrentRound.Reset();
|
|
statsCurrentMatch.Reset();
|
|
statsKills.Reset();
|
|
}
|
|
|
|
PlayerStats_t( const PlayerStats_t &other )
|
|
{
|
|
statsDelta = other.statsDelta;
|
|
statsCurrentRound = other.statsCurrentRound;
|
|
statsCurrentMatch = other.statsCurrentMatch;
|
|
}
|
|
|
|
StatsCollection_t statsDelta;
|
|
StatsCollection_t statsCurrentRound;
|
|
StatsCollection_t statsCurrentMatch;
|
|
KillStats_t statsKills;
|
|
};
|
|
|
|
|
|
struct WeaponName_StatId
|
|
{
|
|
CSWeaponID weaponId;
|
|
CSStatType_t killStatId;
|
|
CSStatType_t shotStatId;
|
|
CSStatType_t hitStatId;
|
|
CSStatType_t damageStatId;
|
|
};
|
|
|
|
struct MapName_MapStatId
|
|
{
|
|
const char* szMapName;
|
|
CSStatType_t statWinsId;
|
|
CSStatType_t statRoundsId;
|
|
};
|
|
|
|
extern const MapName_MapStatId MapName_StatId_Table[];
|
|
|
|
//A mapping from weapon names to weapon stat IDs
|
|
extern const WeaponName_StatId WeaponName_StatId_Table[];
|
|
|
|
//Used to look up the appropriate entry by the ID of the actual weapon
|
|
const WeaponName_StatId& GetWeaponTableEntryFromWeaponId(CSWeaponID id);
|
|
|
|
#include "steamworks_gamestats.h"
|
|
|
|
//=============================================================================
|
|
//
|
|
// Helper functions for creating key values
|
|
//
|
|
void AddDataToKV( KeyValues* pKV, const char* name, int data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, uint64 data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, float data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, bool data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, const char* data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, const Color& data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, short data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, unsigned data );
|
|
void AddDataToKV( KeyValues* pKV, const char* name, const Vector& data );
|
|
void AddPositionDataToKV( KeyValues* pKV, const char* name, const Vector &data );
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
//
|
|
// Helper functions for creating key values from arrays
|
|
//
|
|
void AddArrayDataToKV( KeyValues* pKV, const char* name, const short *data, unsigned size );
|
|
void AddArrayDataToKV( KeyValues* pKV, const char* name, const byte *data, unsigned size );
|
|
void AddArrayDataToKV( KeyValues* pKV, const char* name, const unsigned *data, unsigned size );
|
|
void AddStringDataToKV( KeyValues* pKV, const char* name, const char *data );
|
|
|
|
//=============================================================================
|
|
|
|
// Macros to ease the creation of SendData method for stats structs/classes
|
|
#define BEGIN_STAT_TABLE( tableName ) \
|
|
static const char* GetStatTableName( void ) { return tableName; } \
|
|
void BuildGamestatDataTable( KeyValues* pKV ) \
|
|
{ \
|
|
pKV->SetName( GetStatTableName() );
|
|
|
|
#define REGISTER_STAT( varName ) \
|
|
AddDataToKV(pKV, #varName, varName);
|
|
|
|
#define REGISTER_STAT_NAMED( varName, dbName ) \
|
|
AddDataToKV(pKV, dbName, varName);
|
|
|
|
#define REGISTER_STAT_POSITION( varName ) \
|
|
AddPositionDataToKV(pKV, #varName, varName);
|
|
|
|
#define REGISTER_STAT_POSITION_NAMED( varName, dbName ) \
|
|
AddPositionDataToKV(pKV, dbName, varName);
|
|
|
|
#define REGISTER_STAT_ARRAY( varName ) \
|
|
AddArrayDataToKV( pKV, #varName, varName, ARRAYSIZE( varName ) );
|
|
|
|
#define REGISTER_STAT_ARRAY_NAMED( varName, dbName ) \
|
|
AddArrayDataToKV( pKV, dbName, varName, ARRAYSIZE( varName ) );
|
|
|
|
#define REGISTER_STAT_STRING( varName ) \
|
|
AddStringDataToKV( pKV, #varName, varName );
|
|
|
|
#define REGISTER_STAT_STRING_NAMED( varName, dbName ) \
|
|
AddStringDataToKV( pKV, dbName, varName );
|
|
|
|
#define AUTO_STAT_TABLE_KEY() \
|
|
pKV->SetInt( "TimeSubmitted", GetUniqueIDForStatTable( *this ) );
|
|
|
|
#define END_STAT_TABLE() \
|
|
pKV->SetUint64( ::BaseStatData::m_bUseGlobalData ? "TimeSubmitted" : "SessionTime", ::BaseStatData::TimeSubmitted ); \
|
|
GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKV ); \
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Templatized class for getting unique ID's for stat tables that need
|
|
// to be submitted multiple times per-session.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template < typename T >
|
|
class UniqueStatID_t
|
|
{
|
|
public:
|
|
static unsigned GetNext( void )
|
|
{
|
|
return ++s_nLastID;
|
|
}
|
|
|
|
static void Reset( void )
|
|
{
|
|
s_nLastID = 0;
|
|
}
|
|
|
|
private:
|
|
static unsigned s_nLastID;
|
|
};
|
|
|
|
template < typename T >
|
|
unsigned UniqueStatID_t< T >::s_nLastID = 0;
|
|
|
|
template < typename T >
|
|
unsigned GetUniqueIDForStatTable( const T &table )
|
|
{
|
|
return UniqueStatID_t< T >::GetNext();
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// An interface for tracking gamestats.
|
|
//
|
|
class IGameStatTracker
|
|
{
|
|
public:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Templatized methods to track a per-mission stat.
|
|
// The stat is copied, then deleted after it's sent to the SQL server.
|
|
//-----------------------------------------------------------------------------
|
|
template < typename T >
|
|
void SubmitStat( T& stat )
|
|
{
|
|
// Make a copy of the stat. All of the stat lists require pointers,
|
|
// so we need to protect against a stat allocated on the stack
|
|
T* pT = new T();
|
|
if( !pT )
|
|
return;
|
|
|
|
*pT = stat;
|
|
SubmitStat( pT );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Templatized methods to track a per-mission stat (by pointer)
|
|
// The stat is deleted after it's sent to the SQL server
|
|
//-----------------------------------------------------------------------------
|
|
template < typename T >
|
|
void SubmitStat( T* pStat )
|
|
{
|
|
// Get the static stat table for this type and add the stat to it
|
|
GetStatTable<T>()->AddToTail( pStat );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Add all stats to an existing key value file for submit.
|
|
//-----------------------------------------------------------------------------
|
|
virtual void SubmitGameStats( KeyValues *pKV ) = 0;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Prints the memory usage of all of the stats being tracked
|
|
//-----------------------------------------------------------------------------
|
|
void PrintGamestatMemoryUsage( void );
|
|
|
|
protected:
|
|
//=============================================================================
|
|
//
|
|
// Used as a base interface to store a list of all templatized stat containers
|
|
//
|
|
class IStatContainer
|
|
{
|
|
public:
|
|
virtual void SendData( KeyValues *pKV ) = 0;
|
|
virtual void Clear( void ) = 0;
|
|
virtual void PrintMemoryUsage( void ) = 0;
|
|
};
|
|
|
|
// Defines a list of stat containers.
|
|
typedef CUtlVector< IStatContainer* > StatContainerList_t;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Used to get a list of all stats containers being tracked by the deriving class
|
|
//-----------------------------------------------------------------------------
|
|
virtual StatContainerList_t* GetStatContainerList( void ) = 0;
|
|
|
|
private:
|
|
|
|
//=============================================================================
|
|
//
|
|
// Templatized list of stats submitted
|
|
//
|
|
template < typename T >
|
|
class CGameStatList : public IStatContainer, public CUtlVector< T* >
|
|
{
|
|
public:
|
|
//-----------------------------------------------------------------------------
|
|
// Get data ready to send to the SQL server
|
|
//-----------------------------------------------------------------------------
|
|
virtual void SendData( KeyValues *pKV )
|
|
{
|
|
//ASSERT( pKV != NULL );
|
|
|
|
// Duplicate the master KeyValue for each stat instance
|
|
for( int i=0; i < this->m_Size; ++i )
|
|
{
|
|
// Make a copy of the master key value and build the stat table
|
|
KeyValues *pKVCopy = this->operator [](i)->m_bUseGlobalData ? pKV->MakeCopy() : new KeyValues( "" );
|
|
this->operator [](i)->BuildGamestatDataTable( pKVCopy );
|
|
}
|
|
|
|
// Reset unique ID counter for the stat type
|
|
UniqueStatID_t< T >::Reset();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Clear and delete every stat in this list
|
|
//-----------------------------------------------------------------------------
|
|
virtual void Clear( void )
|
|
{
|
|
this->PurgeAndDeleteElements();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Print out details about this lists memory usage
|
|
//-----------------------------------------------------------------------------
|
|
virtual void PrintMemoryUsage( void )
|
|
{
|
|
if( this->m_Size == 0 )
|
|
return;
|
|
|
|
// Compute the memory used as the size of type times the list count
|
|
unsigned uMemoryUsed = this->m_Size * ( sizeof( T ) );
|
|
|
|
Msg( " %d\tbytes used by %s table\n", uMemoryUsed, T::GetStatTableName() );
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Templatized method to get a single instance of a stat list per data type.
|
|
//-----------------------------------------------------------------------------
|
|
template < typename T >
|
|
CGameStatList< T >* GetStatTable( void )
|
|
{
|
|
static CGameStatList< T > *s_vecOfType = 0;
|
|
if( s_vecOfType == 0 )
|
|
{
|
|
s_vecOfType = new CGameStatList< T >();
|
|
GetStatContainerList()->AddToTail( s_vecOfType );
|
|
}
|
|
return s_vecOfType;
|
|
}
|
|
|
|
};
|
|
|
|
struct BaseStatData
|
|
{
|
|
BaseStatData( bool bUseGlobalData = true ) : m_bUseGlobalData( bUseGlobalData )
|
|
{
|
|
TimeSubmitted = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
|
|
}
|
|
|
|
bool m_bUseGlobalData;
|
|
uint64 TimeSubmitted;
|
|
|
|
};
|
|
|
|
extern ConVar sv_noroundstats;
|
|
|
|
#endif // CS_GAMESTATS_SHARED_H
|