339 lines
10 KiB
SourcePawn
339 lines
10 KiB
SourcePawn
#pragma semicolon 1
|
|
#define PLUGIN_AUTHOR "jenz"
|
|
#define PLUGIN_VERSION "1.1"
|
|
#include <sourcemod>
|
|
#include <geoip>
|
|
#include <unloze_playtime>
|
|
#include <mapchooser_extended>
|
|
#include <cstrike>
|
|
|
|
Database g_hDatabase;
|
|
bool g_bCorrectServer = false;
|
|
|
|
int g_iClientHours[MAXPLAYERS + 1];
|
|
int g_iClientMinutes[MAXPLAYERS + 1];
|
|
|
|
ArrayList g_hPendingVoteChoices;
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = "UNLOZE_playtime_display",
|
|
author = PLUGIN_AUTHOR,
|
|
description = "collects all info for playtime display",
|
|
version = PLUGIN_VERSION,
|
|
url = "www.unloze.com"
|
|
};
|
|
|
|
enum struct VoteChoiceRecord
|
|
{
|
|
char SteamId[64];
|
|
char VoteChoice[64];
|
|
int VoteWeight;
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
if (!g_hDatabase)
|
|
{
|
|
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
|
|
}
|
|
g_hPendingVoteChoices = new ArrayList(sizeof(VoteChoiceRecord));
|
|
g_bCorrectServer = GetConVarInt(FindConVar("hostport")) == 27015 ? true : false;
|
|
}
|
|
|
|
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
|
|
{
|
|
if(!db || strlen(error))
|
|
{
|
|
LogError("Database error: %s", error);
|
|
return;
|
|
}
|
|
g_hDatabase = db;
|
|
OnMapStart();
|
|
}
|
|
|
|
public void OnMapStart()
|
|
{
|
|
if (!g_bCorrectServer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!g_hDatabase)
|
|
{
|
|
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
|
|
return;
|
|
}
|
|
|
|
char sMapname[64];
|
|
GetCurrentMap(sMapname, sizeof(sMapname));
|
|
insert_map(sMapname);
|
|
}
|
|
|
|
public void insert_map(char sMapname[64])
|
|
{
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_map_history` (map_name) VALUES('%s')", sMapname);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
|
|
}
|
|
|
|
//forward is called from OnClientAuthorized but also from timer every 1 minute.
|
|
public void GetPlayerHoursServer(int client, int hours, int minutes)
|
|
{
|
|
if (!g_bCorrectServer)
|
|
{
|
|
return;
|
|
}
|
|
g_iClientHours[client] = hours;
|
|
g_iClientMinutes[client] = minutes;
|
|
|
|
select_user_session(client);
|
|
}
|
|
|
|
public void select_user_session(int client)
|
|
{
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "select 1 from `playtime_display_sessions` where steamid = '%s' and session_end_dt > NOW() - INTERVAL 10 MINUTE limit 1", sSID);
|
|
g_hDatabase.Query(SQL_FinishedQuerySelectUserSession, sQuery, GetClientSerial(client), DBPrio_Normal);
|
|
}
|
|
|
|
public void SQL_FinishedQuerySelectUserSession(Database db, DBResultSet results, const char[] error, int Serial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
LogError("Query error 3: %s", error);
|
|
delete results;
|
|
return;
|
|
}
|
|
int client;
|
|
if ((client = GetClientFromSerial(Serial)) == 0)
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
if (!IsValidClient(client))
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
if (results.RowCount && results.FetchRow())
|
|
{
|
|
//active session that we keep updating
|
|
update_play_session(client, g_iClientHours[client], g_iClientMinutes[client]);
|
|
}
|
|
else
|
|
{
|
|
//new session that we insert
|
|
//chaining the calls
|
|
insert_player(client);
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
public void update_play_session(int client, int client_hours, int client_minutes)
|
|
{
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
|
|
//we only update the latest session row if it actually was updated inside the last 10 minutes. otherwise its an old session that should not be updated.
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "UPDATE `playtime_display_sessions` SET session_end_playtime_minutes='%i', session_end_dt=NOW() WHERE steamid = '%s' and session_end_dt > NOW() - INTERVAL 10 MINUTE order by session_id desc limit 1", (client_hours * 60) + client_minutes, sSID);
|
|
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
|
|
}
|
|
|
|
public void insert_player(int client)
|
|
{
|
|
char sName[MAX_NAME_LENGTH];
|
|
GetClientName(client, sName, sizeof(sName));
|
|
int size2 = 2 * strlen(sName) + 1;
|
|
char[] sEscapedName = new char[size2 + 1];
|
|
g_hDatabase.Escape(sName, sEscapedName, size2 + 1);
|
|
|
|
char sIP[32];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
|
|
char countryCode[3];
|
|
GeoipCode2(sIP, countryCode);
|
|
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
|
|
int client_tier = GetPlayerTier_native(client);
|
|
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_players` (`steamid`, `current_name`, `current_country`, `player_tier`) VALUES('%s', '%s', '%s', '%i') ON DUPLICATE KEY UPDATE `current_name` = '%s', `current_country` = '%s', `last_seen` = CURRENT_TIMESTAMP, `player_tier` = '%i'", sSID, sEscapedName, countryCode, client_tier, sEscapedName, countryCode, client_tier);
|
|
g_hDatabase.Query(SQL_FinishedQueryUpsertPlayerCallback, sQuery, GetClientSerial(client), DBPrio_Normal);
|
|
}
|
|
|
|
public void SQL_FinishedQueryUpsertPlayerCallback(Database db, DBResultSet results, const char[] error, int Serial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
LogError("Query error 3: %s", error);
|
|
delete results;
|
|
return;
|
|
}
|
|
int client;
|
|
if ((client = GetClientFromSerial(Serial)) == 0)
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
if (!IsValidClient(client))
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
delete results;
|
|
upsert_name_history(client);
|
|
}
|
|
|
|
public void upsert_name_history(int client)
|
|
{
|
|
char sName[MAX_NAME_LENGTH];
|
|
GetClientName(client, sName, sizeof(sName));
|
|
int size2 = 2 * strlen(sName) + 1;
|
|
char[] sEscapedName = new char[size2 + 1];
|
|
g_hDatabase.Escape(sName, sEscapedName, size2 + 1);
|
|
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_name_history` (`steamid`, `player_name`) VALUES('%s', '%s') ON DUPLICATE KEY UPDATE `player_name` = '%s', `last_seen` = CURRENT_TIMESTAMP", sSID, sEscapedName, sEscapedName);
|
|
g_hDatabase.Query(SQL_FinishedQueryUpsertNameHistoryCallback, sQuery, GetClientSerial(client), DBPrio_Normal);
|
|
}
|
|
|
|
public void SQL_FinishedQueryUpsertNameHistoryCallback(Database db, DBResultSet results, const char[] error, int Serial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
LogError("Query error 3: %s", error);
|
|
delete results;
|
|
return;
|
|
}
|
|
int client;
|
|
if ((client = GetClientFromSerial(Serial)) == 0)
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
if (!IsValidClient(client))
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
delete results;
|
|
insert_play_session(client, g_iClientHours[client], g_iClientMinutes[client]);
|
|
}
|
|
|
|
public void insert_play_session(int client, int hours, int minutes)
|
|
{
|
|
char sName[MAX_NAME_LENGTH];
|
|
GetClientName(client, sName, sizeof(sName));
|
|
int size2 = 2 * strlen(sName) + 1;
|
|
char[] sEscapedName = new char[size2 + 1];
|
|
g_hDatabase.Escape(sName, sEscapedName, size2 + 1);
|
|
|
|
char sIP[32];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
|
|
char countryCode[3];
|
|
GeoipCode2(sIP, countryCode);
|
|
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_sessions` (`steamid`, `country_code`, `player_name`, `session_start_playtime_minutes`, `session_end_dt`) VALUES('%s', '%s','%s','%i', CURRENT_TIMESTAMP)", sSID, countryCode, sEscapedName, (hours * 60) + minutes);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
|
|
}
|
|
|
|
public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
LogError("Query error 3: %s", error);
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
public void OnClientDisconnect(int client)
|
|
{
|
|
if (g_iClientHours[client] == 0 && g_iClientMinutes[client] == 0)
|
|
{
|
|
return;
|
|
}
|
|
update_play_session(client, g_iClientHours[client], g_iClientMinutes[client]);
|
|
g_iClientHours[client] = 0;
|
|
g_iClientMinutes[client] = 0;
|
|
}
|
|
|
|
public void OnMapVoteRunnoffWarningStart()
|
|
{
|
|
if (!g_bCorrectServer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char sMapname[64];
|
|
GetCurrentMap(sMapname, sizeof(sMapname));
|
|
|
|
char sQuery[512]; //picking max() is usually considered haram
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_map_vote_events` (`map_id`, `current_map`, `result`) VALUES((select max(map_id) from `playtime_display_map_history`), '%s','Revote needed!')", sMapname);
|
|
g_hDatabase.Query(SQL_FinishedQueryMapVoteEndCallback, sQuery, _, DBPrio_Normal);
|
|
}
|
|
|
|
public void OnMapVoteEnd(const char[] map)
|
|
{
|
|
if (!g_bCorrectServer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char sMapname[64];
|
|
GetCurrentMap(sMapname, sizeof(sMapname));
|
|
|
|
char sQuery[512]; //picking max() is usually considered haram
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_map_vote_events` (`map_id`, `current_map`, `result`) VALUES((select max(map_id) from `playtime_display_map_history`), '%s','%s')", sMapname, map);
|
|
g_hDatabase.Query(SQL_FinishedQueryMapVoteEndCallback, sQuery, _, DBPrio_Normal);
|
|
}
|
|
|
|
public void SQL_FinishedQueryMapVoteEndCallback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
LogError("Query error 3: %s", error);
|
|
}
|
|
delete results;
|
|
|
|
for (int j = 0; j < GetArraySize(g_hPendingVoteChoices); j++)
|
|
{
|
|
VoteChoiceRecord entry;
|
|
GetArrayArray(g_hPendingVoteChoices, j, entry);
|
|
|
|
char sQuery[512]; //again, selecting with max() is generally not very good but should be reliable given the context here.
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `playtime_display_map_vote_choices` (`vote_id`, `steamid`, `vote_choice`, `vote_weight`) VALUES ((select max(vote_id) from `playtime_display_map_vote_events`), '%s', '%s','%i')", entry.SteamId, entry.VoteChoice, entry.VoteWeight);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Normal);
|
|
}
|
|
g_hPendingVoteChoices.Clear();
|
|
}
|
|
|
|
public void OnMapVoteClientResult(char[] steamID, char[] vote_choice, int voteweight)
|
|
{
|
|
VoteChoiceRecord entry;
|
|
strcopy(entry.SteamId, sizeof(entry.SteamId), steamID);
|
|
strcopy(entry.VoteChoice, sizeof(entry.VoteChoice), vote_choice);
|
|
entry.VoteWeight = voteweight;
|
|
g_hPendingVoteChoices.PushArray(entry);
|
|
}
|
|
|
|
stock bool IsValidClient(int client)
|
|
{
|
|
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
|
|
return true;
|
|
return false;
|
|
}
|