PHP Code:
#include <amxmodx>
#include <cstrike>
#include <sqlx>
// Uncomment the below to enable real-time stats which will be less efficient because 2 SQL transactions
// will occur for each kill. Leaving this commented will make kills and deaths save to the database when
// the player disconnects or at map change.
//#define REALTIMESTATS
new const Version[] = "0.1";
const MAXPLAYERS = 32;
new const SQLSTATS_DATABASE[] = "sqlstats";
new const SQLSTATS_TABLE[] = "tblStats";
enum PlayerInfo
{
PlayerName[ 33 ],
PlayerSteamID[ 34 ],
PlayerKills,
PlayerDeaths,
bool:IsBot
}
new g_piPlayerInfo[ MAXPLAYERS + 1 ][ PlayerInfo ];
enum QueryTypes
{
QryLoad = 5,
QryStats,
QryTop15
}
new Handle:g_SQLTuple , g_szQueryCache[ 512 ] , g_QryData[ 2 ];
public plugin_init()
{
register_plugin( "SQL Stats" , Version , "bugsy" );
register_event( "DeathMsg" , "DeathMsg" , "a" , "1>0" );
register_clcmd( "say /top15" , "GetTop15" );
register_clcmd( "say /stats" , "GetStats" );
SQL_SetAffinity( "sqlite" );
g_SQLTuple = SQL_MakeDbTuple( "" , "" , "" , SQLSTATS_DATABASE );
formatex( g_szQueryCache, charsmax( g_szQueryCache ) , "CREATE TABLE IF NOT EXISTS %s (SteamID VARCHAR(34) NOT NULL, PlayerName VARCHAR(32), Kills INT(7), Deaths INT(7), PRIMARY KEY (SteamID));" , SQLSTATS_TABLE );
SQL_ThreadQuery( g_SQLTuple , "CreateTableHandle" , g_szQueryCache );
}
public plugin_end()
{
SQL_FreeHandle( g_SQLTuple );
}
public client_authorized( id )
{
if ( ( g_piPlayerInfo[ id ][ IsBot ] = bool:!!is_user_bot( id ) ) == false )
{
get_user_authid( id , g_piPlayerInfo[ id ][ PlayerSteamID ] , charsmax( g_piPlayerInfo[][ PlayerSteamID ] ) );
get_user_name( id , g_piPlayerInfo[ id ][ PlayerName ] , charsmax( g_piPlayerInfo[][ PlayerName ] ) );
g_QryData[ 0 ] = _:QryLoad;
g_QryData[ 1 ] = id;
g_piPlayerInfo[ id ][ PlayerKills ] = 0;
g_piPlayerInfo[ id ][ PlayerDeaths ] = 0;
formatex( g_szQueryCache, charsmax( g_szQueryCache ) , "SELECT Kills,Deaths FROM %s WHERE SteamID=^"%s^";" , SQLSTATS_TABLE , g_piPlayerInfo[ id ][ PlayerSteamID ] );
SQL_ThreadQuery( g_SQLTuple , "QueryHandle" , g_szQueryCache , g_QryData , sizeof( g_QryData ) );
}
}
#if !defined SQLSTATS_REALTIME
public client_disconnect( id )
{
if ( !g_piPlayerInfo[ id ][ IsBot ] )
{
formatex( g_szQueryCache, charsmax( g_szQueryCache ) , "REPLACE INTO %s (SteamID,PlayerName,Kills,Deaths) VALUES (^"%s^",^"%s^",%d,%d);" ,
SQLSTATS_TABLE ,
g_piPlayerInfo[ id ][ PlayerSteamID ] ,
g_piPlayerInfo[ id ][ PlayerName ] ,
g_piPlayerInfo[ id ][ PlayerKills ] ,
g_piPlayerInfo[ id ][ PlayerDeaths ] );
SQL_ThreadQuery( g_SQLTuple , "SetHandle" , g_szQueryCache );
}
}
#endif
public DeathMsg()
{
new iKiller , iVictim , CsTeams:iVictimTeam;
iKiller = read_data( 1 );
iVictim = read_data( 2 );
if ( cs_get_user_team( iKiller ) != ( iVictimTeam = cs_get_user_team( iVictim ) ) )
{
g_piPlayerInfo[ iKiller ][ PlayerKills ]++;
if ( iVictimTeam != CS_TEAM_T )
g_piPlayerInfo[ iVictim ][ PlayerDeaths ]++;
#if defined REALTIMESTATS
new iPlayer[ 2 ];
iPlayer[ 0 ] = iKiller;
iPlayer[ 1 ] = iVictim;
for ( new i = 0 ; i < 2 ; i++ )
{
if ( !g_piPlayerInfo[ i ][ IsBot ] )
{
formatex( g_szQueryCache, charsmax( g_szQueryCache ) , "REPLACE INTO %s (SteamID,PlayerName,Kills,Deaths) VALUES (^"%s^",^"%s^",%d,%d);" ,
SQLSTATS_TABLE ,
g_piPlayerInfo[ iPlayer[ i ] ][ PlayerSteamID ] ,
g_piPlayerInfo[ iPlayer[ i ] ][ PlayerName ] ,
g_piPlayerInfo[ iPlayer[ i ] ][ PlayerKills ] ,
g_piPlayerInfo[ iPlayer[ i ] ][ PlayerDeaths ] );
SQL_ThreadQuery( g_SQLTuple , "SetHandle" , g_szQueryCache );
}
}
#endif
}
}
public GetTop15( id )
{
g_QryData[ 0 ] = _:QryTop15;
g_QryData[ 1 ] = id;
formatex( g_szQueryCache , charsmax( g_szQueryCache ) , "SELECT PlayerName, (Kills-Deaths) As NetKills FROM %s ORDER BY NetKills DESC LIMIT 15;" , SQLSTATS_TABLE );
SQL_ThreadQuery( g_SQLTuple , "QueryHandle" , g_szQueryCache , g_QryData , sizeof( g_QryData ) );
}
public GetStats( id )
{
g_QryData[ 0 ] = _:QryStats;
g_QryData[ 1 ] = id;
formatex( g_szQueryCache , charsmax( g_szQueryCache ) , "SELECT p1.Kills,p1.Deaths,(SELECT Count(*) FROM %s) AS TotalCount,(SELECT Count(*) FROM %s AS p2 WHERE (p2.Kills-p2.Deaths) > (p1.Kills-p1.Deaths)) AS KillRank \
FROM %s AS p1 \
WHERE SteamID=^"%s^";" , SQLSTATS_TABLE , SQLSTATS_TABLE , SQLSTATS_TABLE , g_piPlayerInfo[ id ][ PlayerSteamID ] );
SQL_ThreadQuery( g_SQLTuple , "QueryHandle" , g_szQueryCache , g_QryData , sizeof( g_QryData ) );
}
public CreateTableHandle( FailState , Handle:Query , Error[] , Errcode , Data[] , DataSize )
{
if( FailState == TQUERY_CONNECT_FAILED )
return set_fail_state( "Could not connect to SQL database." );
else if( FailState == TQUERY_QUERY_FAILED )
return set_fail_state( "Query failed." );
if( Errcode )
return log_amx("Error on query: %s",Error);
return PLUGIN_CONTINUE;
}
public SetHandle( FailState , Handle:Query , Error[] , Errcode , Data[] , DataSize )
{
if( FailState == TQUERY_CONNECT_FAILED )
return set_fail_state( "Could not connect to SQL database." );
else if( FailState == TQUERY_QUERY_FAILED )
return set_fail_state( "Query failed." );
if( Errcode )
return log_amx( "Error on query: %s" , Error );
return PLUGIN_CONTINUE;
}
public QueryHandle( FailState , Handle:Query , Error[] , Errcode , Data[] , DataSize )
{
if( FailState == TQUERY_CONNECT_FAILED )
return set_fail_state("Could not connect to SQL database." );
else if( FailState == TQUERY_QUERY_FAILED )
return set_fail_state( "Query failed." );
if( Errcode )
return log_amx("Error on query: %s",Error);
new iRank , iKills , iDeaths , szName[ 33 ] , szHTML[ 1000 ] , iHTMLPos;
switch ( Data[ 0 ] )
{
case QryLoad:
{
if ( SQL_NumResults( Query ) )
{
g_piPlayerInfo[ Data[ 1 ] ][ PlayerKills ] = SQL_ReadResult( Query , 0 );
g_piPlayerInfo[ Data[ 1 ] ][ PlayerDeaths ] = SQL_ReadResult( Query , 1 );
}
}
case QryStats:
{
if ( SQL_NumResults( Query ) )
{
client_print( Data[ 1 ] , print_chat , "* Rank %d of %d - %d Kills and %d Deaths" , SQL_ReadResult( Query , 3 ) + 1 , SQL_ReadResult( Query , 2 ) , SQL_ReadResult( Query , 0 ) , SQL_ReadResult( Query , 1 ) )
}
}
case QryTop15:
{
if ( SQL_NumResults( Query ) )
{
iHTMLPos = copy( szHTML[ iHTMLPos ] , charsmax( szHTML ) , "<html><body bgcolor=^"black^"><table style=^"color:white^">><th><b>Rank</b></th><th><b>Name</b></th><th><b>Net Kills</b></th>" );
while ( SQL_MoreResults( Query ) )
{
SQL_ReadResult( Query , 0 , szName , charsmax( szName ) );
iKills = SQL_ReadResult( Query , 1 );
iHTMLPos += formatex( szHTML[ iHTMLPos ] , charsmax( szHTML ) - iHTMLPos , "<tr><td><center>%d</center></td><td><center>%s</center></td><td><center>%d</center></td></tr>" , ++iRank , szName , iKills , iDeaths );
SQL_NextRow( Query );
}
copy( szHTML[ iHTMLPos ] , charsmax( szHTML ) - iHTMLPos , "</tr></table></body></html>" );
show_motd( Data[ 1 ] , szHTML );
}
}
}
return PLUGIN_CONTINUE;
}