Skip to content

Instantly share code, notes, and snippets.

@alanedwardes
Created October 6, 2012 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanedwardes/3845759 to your computer and use it in GitHub Desktop.
Save alanedwardes/3845759 to your computer and use it in GitHub Desktop.
Simple entity for the Source Engine to log and send gameplay statistics.
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ========
//
// Purpose: Simple entity to log and send gameplay statistics
//
//=============================================================================
#include "cbase.h"
#include "vstdlib/jobthread.h"
#include "curl/curl.h"
#include "steam\steam_api.h"
#include "view_shared.h"
#include <time.h>
#include "GameEventListener.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define ENDPOINT "http://example.com/collector.php?collect"
ConVar stats_enabled( "stats_enabled", "-1", FCVAR_ARCHIVE);
class CStatisticsCollector : public CLogicalEntity, public CGameEventListener
{
public:
DECLARE_CLASS( CStatisticsCollector, CLogicalEntity );
DECLARE_DATADESC();
CStatisticsCollector()
{
ListenForGameEvent("player_hurt");
}
void FireGameEvent( IGameEvent* e );
void Init();
void GameEvent();
void SendStatistic( const tchar *m_event );
void InputSendStatistic( inputdata_t &inputData );
void cURLThread(const tchar *m_event);
};
LINK_ENTITY_TO_CLASS( statistics_collector, CStatisticsCollector );
BEGIN_DATADESC( CStatisticsCollector )
DEFINE_INPUTFUNC( FIELD_STRING, "Event", InputSendStatistic )
END_DATADESC()
void CStatisticsCollector::FireGameEvent( IGameEvent* e )
{
CBasePlayer *player = UTIL_GetLocalPlayer();
if ( Q_strcmp( "player_hurt", e->GetName() ) && player->GetHealth() == 0 )
{
// The player has unfortunately passed away
this->SendStatistic("player_death");
}
}
void CStatisticsCollector::cURLThread(const char *m_event)
{
DevMsg("Statistics Collectior: Sending event '%s'\n", m_event);
CBasePlayer *player = UTIL_GetLocalPlayer();
const Vector player_pos = player->GetAbsOrigin();
uint32 steam_id;
ISteamUser* steam_user = steamapicontext->SteamUser();
if(steam_user->BLoggedOn())
{
steam_id = steam_user->GetSteamID().GetAccountID();
}
else
{
// Just in case someone isn't logged in. Yarr, pirate Steam
steam_id = 0;
}
time_t aclock;
time( &aclock );
struct tm *newtime = localtime( &aclock );
char timeString[128];
Q_strncpy( timeString, asctime( newtime ), sizeof( timeString ) );
// Get rid of the \n.
char *pEnd = strstr( timeString, "\n" );
if ( pEnd )
{
*pEnd = 0;
}
char full_url[512];
Q_snprintf(full_url, 512, "%s&e=%s&s=%i&p=%.2f,%.2f,%.2f&h=%i&d=%s&m=%s",
ENDPOINT, m_event, steam_id, player_pos.x, player_pos.y, player_pos.z, player->GetHealth(), timeString, gpGlobals->mapname.ToCStr()
);
CBaseCombatWeapon *weapon = player->GetActiveWeapon();
if(weapon)
{
Q_snprintf(full_url, 512, "%s&w=%s", full_url, weapon->GetClassname());
}
DevMsg("Statistics Collectior: GET %s\n", full_url);
CURL *curl;
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, full_url);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
DevMsg("Statistics Collectior: Event sent.\n");
}
void CStatisticsCollector::SendStatistic( const char *m_event )
{
if(stats_enabled.GetInt() > 0)
{
DevMsg("Statistics Collectior: cURL thread queued.\n");
ThreadExecute(this, &CStatisticsCollector::cURLThread, m_event);
}
else
{
DevMsg("Statistics Collectior: Events disabled, ignoring.\n");
}
}
void CStatisticsCollector::InputSendStatistic( inputdata_t &inputData )
{
this->SendStatistic(inputData.value.String());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment