mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
add hl1,portal,dod source code
This commit is contained in:
344
game/client/dod/dod_playerstats.cpp
Normal file
344
game/client/dod/dod_playerstats.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "dod_playerstats.h"
|
||||
#include "hud_macros.h"
|
||||
|
||||
const char *g_pszShortTeamNames[2] =
|
||||
{
|
||||
"US",
|
||||
"Ger"
|
||||
};
|
||||
|
||||
const char *g_pszClassNames[NUM_DOD_PLAYERCLASSES] =
|
||||
{
|
||||
"Rifleman",
|
||||
"Assault",
|
||||
"Support",
|
||||
"Sniper",
|
||||
"MG",
|
||||
"Rocket"
|
||||
};
|
||||
|
||||
const char *g_pszStatNames[DODSTAT_MAX] =
|
||||
{
|
||||
"iPlayTime",
|
||||
"iRoundsWon",
|
||||
"iRoundsLost",
|
||||
"iKills",
|
||||
"iDeaths",
|
||||
"iCaptures",
|
||||
"iBlocks",
|
||||
"iBombsPlanted",
|
||||
"iBombsDefused",
|
||||
"iDominations",
|
||||
"iRevenges",
|
||||
"iShotsHit",
|
||||
"iShotsFired",
|
||||
"iHeadshots"
|
||||
};
|
||||
|
||||
int iValidWeaponStatBitMask = ( (1<<DODSTAT_KILLS ) | (1<<DODSTAT_SHOTS_HIT) | (1<<DODSTAT_SHOTS_FIRED) | (1<<DODSTAT_HEADSHOTS) );
|
||||
int iValidPlayerStatBitMask = 0xFFFF & ~( (1<<DODSTAT_SHOTS_HIT) | (1<<DODSTAT_SHOTS_FIRED) | (1<<DODSTAT_HEADSHOTS) );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &msg -
|
||||
//-----------------------------------------------------------------------------
|
||||
void __MsgFunc_DODPlayerStatsUpdate( bf_read &msg )
|
||||
{
|
||||
g_DODPlayerStats.MsgFunc_DODPlayerStatsUpdate( msg );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CDODPlayerStats::CDODPlayerStats()
|
||||
{
|
||||
m_flTimeNextForceUpload = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called at init time after all systems are init'd. We have to
|
||||
// do this in PostInit because the Steam app ID is not available earlier
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDODPlayerStats::PostInit()
|
||||
{
|
||||
SetNextForceUploadTime();
|
||||
|
||||
ListenForGameEvent( "player_stats_updated" );
|
||||
ListenForGameEvent( "user_data_downloaded" );
|
||||
|
||||
HOOK_MESSAGE( DODPlayerStatsUpdate );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called at level shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDODPlayerStats::LevelShutdownPreEntity()
|
||||
{
|
||||
// upload user stats to Steam on every map change or when we quit
|
||||
UploadStats();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: called when the stats have changed in-game
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDODPlayerStats::FireGameEvent( IGameEvent *event )
|
||||
{
|
||||
const char *pEventName = event->GetName();
|
||||
|
||||
if ( FStrEq( pEventName, "user_data_downloaded" ) )
|
||||
{
|
||||
// Store our stat data
|
||||
|
||||
Assert( steamapicontext->SteamUserStats() );
|
||||
if ( !steamapicontext->SteamUserStats() )
|
||||
return;
|
||||
|
||||
CGameID gameID( engine->GetAppID() );
|
||||
|
||||
// reset everything
|
||||
Q_memset( &m_PlayerStats, 0, sizeof(m_PlayerStats) );
|
||||
Q_memset( &m_WeaponStats, 0, sizeof(m_WeaponStats) );
|
||||
|
||||
// read playerclass stats
|
||||
for ( int iTeam=0;iTeam<2;iTeam++ )
|
||||
{
|
||||
for ( int iClass=0;iClass<NUM_DOD_PLAYERCLASSES;iClass++ )
|
||||
{
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( iValidPlayerStatBitMask & (1<<iStat) )
|
||||
{
|
||||
char szStatName[256];
|
||||
int iData;
|
||||
|
||||
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s.%s", g_pszShortTeamNames[iTeam], g_pszClassNames[iClass], g_pszStatNames[iStat] );
|
||||
|
||||
if ( steamapicontext->SteamUserStats()->GetStat( szStatName, &iData ) )
|
||||
{
|
||||
// use Steam's value
|
||||
m_PlayerStats[iTeam][iClass].m_iStat[iStat] = iData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read weapon stats
|
||||
for ( int iWeapon=WEAPON_NONE+1;iWeapon<WEAPON_MAX;iWeapon++ )
|
||||
{
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( iValidWeaponStatBitMask & (1<<iStat) )
|
||||
{
|
||||
char szStatName[256];
|
||||
int iData;
|
||||
|
||||
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s", s_WeaponAliasInfo[iWeapon], g_pszStatNames[iStat] );
|
||||
|
||||
if ( steamapicontext->SteamUserStats()->GetStat( szStatName, &iData ) )
|
||||
{
|
||||
// use Steam's value
|
||||
m_WeaponStats[iWeapon].m_iStat[iStat] = iData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGameEvent * event = gameeventmanager->CreateEvent( "player_stats_updated" );
|
||||
if ( event )
|
||||
{
|
||||
event->SetBool( "forceupload", false );
|
||||
gameeventmanager->FireEventClientSide( event );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDODPlayerStats::MsgFunc_DODPlayerStatsUpdate( bf_read &msg )
|
||||
{
|
||||
dod_stat_accumulator_t playerStats;
|
||||
Q_memset( &playerStats, 0, sizeof(playerStats) );
|
||||
|
||||
// get the fixed-size information
|
||||
int iClass = msg.ReadByte();
|
||||
int iTeam = msg.ReadByte();
|
||||
|
||||
int iPlayerStatBits = msg.ReadLong();
|
||||
|
||||
Assert( iClass >= 0 && iClass <= 5 );
|
||||
if ( iClass < 0 || iClass > 5 )
|
||||
return;
|
||||
|
||||
// the bitfield indicates which stats are contained in the message. Set the stats appropriately.
|
||||
int iStat = DODSTAT_FIRST;
|
||||
while ( iPlayerStatBits > 0 )
|
||||
{
|
||||
if ( iPlayerStatBits & 1 )
|
||||
{
|
||||
playerStats.m_iStat[iStat] = msg.ReadLong();
|
||||
}
|
||||
iPlayerStatBits >>= 1;
|
||||
iStat++;
|
||||
}
|
||||
|
||||
int iNumWeapons = msg.ReadByte();
|
||||
int i;
|
||||
|
||||
CUtlVector<weapon_stat_t> vecWeaponStats;
|
||||
|
||||
for ( i=0;i<iNumWeapons;i++ )
|
||||
{
|
||||
weapon_stat_t weaponStat;
|
||||
Q_memset( &weaponStat, 0, sizeof(weaponStat) );
|
||||
|
||||
weaponStat.iWeaponID = msg.ReadByte();
|
||||
|
||||
vecWeaponStats.AddToTail( weaponStat );
|
||||
}
|
||||
|
||||
for ( i=0;i<vecWeaponStats.Count();i++ )
|
||||
{
|
||||
int iWeaponStatMask = msg.ReadLong();
|
||||
|
||||
int iStat = DODSTAT_FIRST;
|
||||
while ( iWeaponStatMask > 0 )
|
||||
{
|
||||
if ( iWeaponStatMask & 1 )
|
||||
{
|
||||
vecWeaponStats[i].stats.m_iStat[iStat] = msg.ReadLong();
|
||||
}
|
||||
iWeaponStatMask >>= 1;
|
||||
iStat++;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check: the message should contain exactly the # of bytes we expect based on the bit field
|
||||
Assert( !msg.IsOverflowed() );
|
||||
Assert( 0 == msg.GetNumBytesLeft() );
|
||||
// if byte count isn't correct, bail out and don't use this data, rather than risk polluting player stats with garbage
|
||||
if ( msg.IsOverflowed() || ( 0 != msg.GetNumBytesLeft() ) )
|
||||
return;
|
||||
|
||||
UpdateStats( iClass, iTeam, &playerStats, &vecWeaponStats );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Uploads stats for current Steam user to Steam
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDODPlayerStats::UploadStats()
|
||||
{
|
||||
// only upload if Steam is running
|
||||
if ( !steamapicontext->SteamUserStats() )
|
||||
return;
|
||||
|
||||
CGameID gameID( engine->GetAppID() );
|
||||
char szStatName[256];
|
||||
|
||||
// write playerclass stats
|
||||
for ( int iTeam=0;iTeam<2;iTeam++ )
|
||||
{
|
||||
for ( int iClass=0;iClass<NUM_DOD_PLAYERCLASSES;iClass++ )
|
||||
{
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( iValidPlayerStatBitMask & (1<<iStat) )
|
||||
{
|
||||
if ( m_PlayerStats[iTeam][iClass].m_bDirty[iStat] )
|
||||
{
|
||||
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s.%s", g_pszShortTeamNames[iTeam], g_pszClassNames[iClass], g_pszStatNames[iStat] );
|
||||
|
||||
steamapicontext->SteamUserStats()->SetStat( szStatName, m_PlayerStats[iTeam][iClass].m_iStat[iStat] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write weapon stats
|
||||
for ( int iWeapon=WEAPON_NONE+1;iWeapon<WEAPON_MAX;iWeapon++ )
|
||||
{
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( m_WeaponStats[iWeapon].m_bDirty[iStat] )
|
||||
{
|
||||
if ( iValidWeaponStatBitMask & (1<<iStat) )
|
||||
{
|
||||
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.%s", s_WeaponAliasInfo[iWeapon], g_pszStatNames[iStat] );
|
||||
|
||||
steamapicontext->SteamUserStats()->SetStat( szStatName, m_WeaponStats[iWeapon].m_iStat[iStat] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetNextForceUploadTime();
|
||||
}
|
||||
|
||||
void CDODPlayerStats::UpdateStats( int iPlayerClass, int iTeam, dod_stat_accumulator_t *playerStats, CUtlVector<weapon_stat_t> *vecWeaponStats )
|
||||
{
|
||||
Assert( iPlayerClass >= 0 && iPlayerClass < NUM_DOD_PLAYERCLASSES );
|
||||
if ( iPlayerClass < 0 || iPlayerClass >= NUM_DOD_PLAYERCLASSES )
|
||||
return;
|
||||
|
||||
// translate the team index into [0,1]
|
||||
int iTeamIndex = ( iTeam == TEAM_ALLIES ) ? 0 : 1;
|
||||
|
||||
// upload this class' data
|
||||
|
||||
// add this stat update to our stored stats
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( iValidPlayerStatBitMask & (1<<iStat) )
|
||||
{
|
||||
if ( playerStats->m_iStat[iStat] > 0 )
|
||||
{
|
||||
m_PlayerStats[iTeamIndex][iPlayerClass].m_iStat[iStat] += playerStats->m_iStat[iStat];
|
||||
m_PlayerStats[iTeamIndex][iPlayerClass].m_bDirty[iStat] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int iWeaponStatCount = vecWeaponStats->Count();
|
||||
|
||||
for ( int i=0;i<iWeaponStatCount;i++ )
|
||||
{
|
||||
int iWeaponID = vecWeaponStats->Element(i).iWeaponID;
|
||||
|
||||
for ( int iStat=0;iStat<DODSTAT_MAX;iStat++ )
|
||||
{
|
||||
if ( iValidWeaponStatBitMask & (1<<iStat) )
|
||||
{
|
||||
int iValue = vecWeaponStats->Element(i).stats.m_iStat[iStat];
|
||||
if ( iValue > 0 )
|
||||
{
|
||||
m_WeaponStats[iWeaponID].m_iStat[iStat] += iValue;
|
||||
m_WeaponStats[iWeaponID].m_bDirty[iStat] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't uploaded stats in a long time, upload them
|
||||
if ( ( gpGlobals->curtime >= m_flTimeNextForceUpload ) )
|
||||
{
|
||||
UploadStats();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the next time to force a stats upload at
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDODPlayerStats::SetNextForceUploadTime()
|
||||
{
|
||||
// pick a time a while from now (an hour +/- 15 mins) to upload stats if we haven't gotten a map change by then
|
||||
m_flTimeNextForceUpload = gpGlobals->curtime + ( 60 * RandomInt( 45, 75 ) );
|
||||
}
|
||||
|
||||
CDODPlayerStats g_DODPlayerStats;
|
||||
Reference in New Issue
Block a user