source-engine/game/client/tf2base/tf_steamstats.cpp
2022-08-13 03:20:41 +03:00

237 lines
8.6 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_steamstats.h"
#include "tf_hud_statpanel.h"
#include "achievementmgr.h"
#include "engine/imatchmaking.h"
#include "ipresence.h"
#include "../game/shared/tf2base/tf_shareddefs.h"
#include "../game/shared/tf2base/tf_gamestats_shared.h"
struct StatMap_t
{
const char *pszName;
int iStat;
int iLiveStat;
};
// subset of stats which we store in Steam
StatMap_t g_SteamStats[] = {
{ "iNumberOfKills", TFSTAT_KILLS, PROPERTY_KILLS },
{ "iDamageDealt", TFSTAT_DAMAGE, PROPERTY_DAMAGE_DEALT },
{ "iPlayTime", TFSTAT_PLAYTIME, PROPERTY_PLAY_TIME },
{ "iPointCaptures", TFSTAT_CAPTURES, PROPERTY_POINT_CAPTURES },
{ "iPointDefenses", TFSTAT_DEFENSES, PROPERTY_POINT_DEFENSES },
{ "iDominations", TFSTAT_DOMINATIONS, PROPERTY_DOMINATIONS },
{ "iRevenge", TFSTAT_REVENGE, PROPERTY_REVENGE },
{ "iPointsScored", TFSTAT_POINTSSCORED, PROPERTY_POINTS_SCORED },
{ "iBuildingsDestroyed", TFSTAT_BUILDINGSDESTROYED, PROPERTY_BUILDINGS_DESTROYED },
{ "iHeadshots", TFSTAT_HEADSHOTS, PROPERTY_HEADSHOTS },
{ "iHealthPointsHealed", TFSTAT_HEALING, PROPERTY_HEALTH_POINTS_HEALED },
{ "iNumInvulnerable", TFSTAT_INVULNS, PROPERTY_INVULNS },
{ "iKillAssists", TFSTAT_KILLASSISTS, PROPERTY_KILL_ASSISTS },
{ "iBackstabs", TFSTAT_BACKSTABS, PROPERTY_BACKSTABS },
{ "iHealthPointsLeached", TFSTAT_HEALTHLEACHED, PROPERTY_HEALTH_POINTS_LEACHED },
{ "iBuildingsBuilt", TFSTAT_BUILDINGSBUILT, PROPERTY_BUILDINGS_BUILT },
{ "iSentryKills", TFSTAT_MAXSENTRYKILLS, PROPERTY_SENTRY_KILLS },
{ "iNumTeleports", TFSTAT_TELEPORTS, PROPERTY_TELEPORTS } };
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTFSteamStats::CTFSteamStats()
{
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 CTFSteamStats::PostInit()
{
SetNextForceUploadTime();
ListenForGameEvent( "player_stats_updated" );
ListenForGameEvent( "user_data_downloaded" );
}
//-----------------------------------------------------------------------------
// Purpose: called at level shutdown
//-----------------------------------------------------------------------------
void CTFSteamStats::LevelShutdownPreEntity()
{
// upload user stats to Steam on every map change
UploadStats();
}
//-----------------------------------------------------------------------------
// Purpose: called when the stats have changed in-game
//-----------------------------------------------------------------------------
void CTFSteamStats::FireGameEvent( IGameEvent *event )
{
const char *pEventName = event->GetName();
if ( 0 == Q_strcmp( pEventName, "player_stats_updated" ) )
{
bool bForceUpload = event->GetBool( "forceupload" );
// if we haven't uploaded stats in a long time, upload them
if ( ( gpGlobals->curtime >= m_flTimeNextForceUpload ) || bForceUpload )
{
UploadStats();
}
}
else if ( 0 == Q_strcmp( pEventName, "user_data_downloaded" ) )
{
/*
Assert( SteamUserStats() );
if ( !SteamUserStats() )
return;
CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel );
Assert( pStatPanel );
CGameID gameID( engine->GetAppID() );
for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass <= TF_LAST_NORMAL_CLASS; iClass++ )
{
ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass );
for ( int iStat = 0; iStat < ARRAYSIZE( g_SteamStats ); iStat++ )
{
char szStatName[256];
int iData;
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.accum.%s", g_aPlayerClassNames_NonLocalized[iClass], g_SteamStats[iStat].pszName );
if ( SteamUserStats()->GetStat( gameID, szStatName, &iData ) )
{
if ( pStatPanel->IsLocalFileTrusted() )
{
// if local stats file is trusted, then use the higher of the current value (from local file) or Steam. Handles case where we previously failed to write latest data to Steam.
classStats.accumulated.m_iStat[g_SteamStats[iStat].iStat] = max( iData, classStats.accumulated.m_iStat[g_SteamStats[iStat].iStat] );
}
else
{
// local file is not trusted, just use Steam's value
classStats.accumulated.m_iStat[g_SteamStats[iStat].iStat] = iData;
}
}
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.max.%s", g_aPlayerClassNames_NonLocalized[iClass], g_SteamStats[iStat].pszName );
if ( SteamUserStats()->GetStat( gameID, szStatName, &iData ) )
{
if ( pStatPanel->IsLocalFileTrusted() )
{
// if local stats file is trusted, then use the higher of the current value (from local file) or Steam. Handles case where we previously failed to write latest data to Steam.
classStats.max.m_iStat[g_SteamStats[iStat].iStat] = max( iData, classStats.max.m_iStat[g_SteamStats[iStat].iStat] );
}
else
{
// local file is not trusted, just use Steam's value
classStats.max.m_iStat[g_SteamStats[iStat].iStat] = iData;
}
}
}
}
*/
IGameEvent * event = gameeventmanager->CreateEvent( "player_stats_updated" );
if ( event )
{
event->SetBool( "forceupload", false );
gameeventmanager->FireEventClientSide( event );
}
// pStatPanel->SetStatsChanged( true );
// pStatPanel->UpdateStatSummaryPanel();
}
}
//-----------------------------------------------------------------------------
// Purpose: Uploads stats for current Steam user to Steam
//-----------------------------------------------------------------------------
void CTFSteamStats::UploadStats()
{
/*
if ( IsX360() )
{
ReportLiveStats();
return;
}
// only upload if Steam is running
if ( !SteamUserStats() )
return;
CGameID gameID( engine->GetAppID() );
for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass <= TF_LAST_NORMAL_CLASS; iClass++ )
{
ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass );
for ( int iStat = 0; iStat < ARRAYSIZE( g_SteamStats ); iStat++ )
{
char szStatName[256];
// set the stats locally in Steam client
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.accum.%s", g_aPlayerClassNames_NonLocalized[iClass], g_SteamStats[iStat].pszName );
SteamUserStats()->SetStat( gameID, szStatName, classStats.accumulated.m_iStat[g_SteamStats[iStat].iStat] );
Q_snprintf( szStatName, ARRAYSIZE( szStatName ), "%s.max.%s", g_aPlayerClassNames_NonLocalized[iClass], g_SteamStats[iStat].pszName );
SteamUserStats()->SetStat( gameID, szStatName, classStats.max.m_iStat[g_SteamStats[iStat].iStat] );
}
}
CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr *>( engine->GetAchievementMgr() );
if ( pAchievementMgr )
{
pAchievementMgr->UploadUserData();
}
SetNextForceUploadTime();*/
}
//-----------------------------------------------------------------------------
// Purpose: Accumulate player stats and send them to matchmaking for reporting to Live
//-----------------------------------------------------------------------------
void CTFSteamStats::ReportLiveStats()
{
int statsTotals[ARRAYSIZE( g_SteamStats )];
Q_memset( &statsTotals, 0, sizeof( statsTotals ) );
for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass <= TF_LAST_NORMAL_CLASS; iClass++ )
{
ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass );
for ( int iStat = 0; iStat < ARRAYSIZE( g_SteamStats ); iStat++ )
{
statsTotals[iStat] = max( statsTotals[iStat], classStats.max.m_iStat[g_SteamStats[iStat].iStat] );
}
}
// send the stats to matchmaking
for ( int i = 0; i < ARRAYSIZE( g_SteamStats ); ++i )
{
// Points scored is looked up by the stats reporting function
if ( g_SteamStats[i].iLiveStat == PROPERTY_POINTS_SCORED )
continue;
presence->SetStat( g_SteamStats[i].iLiveStat, statsTotals[i], XUSER_DATA_TYPE_INT32 );
}
presence->UploadStats();
}
//-----------------------------------------------------------------------------
// Purpose: sets the next time to force a stats upload at
//-----------------------------------------------------------------------------
void CTFSteamStats::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 ) );
}
CTFSteamStats g_TFSteamStats;