997 lines
30 KiB
SourcePawn
997 lines
30 KiB
SourcePawn
#pragma semicolon 1
|
|
#define PLUGIN_AUTHOR "jenz"
|
|
#define PLUGIN_VERSION "1.4"
|
|
#include <sourcemod>
|
|
#include <cstrike>
|
|
#include <PlayerManager>
|
|
#include <AFKManager>
|
|
|
|
Database g_hDatabase;
|
|
//check if autismbot
|
|
bool is_bot_player[MAXPLAYERS + 1];
|
|
Handle g_h_time_activity = null;
|
|
char g_csSID[MAXPLAYERS + 1][65];
|
|
char g_cTimeRecords[1000][128];
|
|
int g_iPlayerTimeServer[MAXPLAYERS + 1];
|
|
int g_iPlayerAFKTime;
|
|
int g_iPlayerRTVCapacity;
|
|
int g_iAvgHour_Contribution_per_player;
|
|
int g_iRtvBoost_tier;
|
|
int g_iPlayerTier[MAXPLAYERS + 1];
|
|
int g_iPlayerNextTierHours[MAXPLAYERS + 1];
|
|
|
|
char g_GroupNames[32][64];
|
|
char g_GroupFlags[32][32];
|
|
int g_GroupNameCount = 0;
|
|
|
|
StringMap g_GroupOverrides; // group name -> comma-separated override list
|
|
|
|
static Handle g_hForwardPlayerHours;
|
|
static Handle g_hForwardPlayerTier;
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = "UNLOZE_player_time",
|
|
author = PLUGIN_AUTHOR,
|
|
description = "checks playtime on servers",
|
|
version = PLUGIN_VERSION,
|
|
url = "www.unloze.com"
|
|
};
|
|
|
|
public Action time_query_activity(Handle timer, any data)
|
|
{
|
|
if (!g_hDatabase)
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
char sServer[64];
|
|
int i_port = GetConVarInt(FindConVar("hostport"));
|
|
if (i_port == 27015 || i_port == 27035) //might as well count play time on ze2. it was not done before but its a bit like why not anyways.
|
|
{
|
|
Format(sServer, sizeof(sServer), "ze_time");
|
|
}
|
|
else if (i_port == 27016)
|
|
{
|
|
Format(sServer, sizeof(sServer), "zr_time");
|
|
}
|
|
else if (i_port == 27017)
|
|
{
|
|
Format(sServer, sizeof(sServer), "mg_time");
|
|
}
|
|
else
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
for (int client = 1; client <= MaxClients; client++)
|
|
{
|
|
if (IsValidClient(client) && !IsFakeClient(client) && IsPlayerAlive(client))
|
|
{
|
|
char sIP[32];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
char sQuery[512];
|
|
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);
|
|
Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.player_time set `%s` = `%s` + 10 where steam_id = '%s' and ipv4 = '%s'", sServer, sServer, g_csSID[client], sIP);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low);
|
|
Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.player_time set player_name = '%s' where steam_id = '%s' and player_name != '%s'", sEscapedName, g_csSID[client], sEscapedName);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low);
|
|
}
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
public void LoadGroupOverrides()
|
|
{
|
|
KeyValues kv = new KeyValues("Groups");
|
|
char path[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, path, sizeof(path), "configs/admin_groups.cfg");
|
|
|
|
if (!kv.ImportFromFile(path))
|
|
{
|
|
delete kv;
|
|
return;
|
|
}
|
|
g_GroupNameCount = 0;
|
|
|
|
if (kv.GotoFirstSubKey())
|
|
{
|
|
do
|
|
{
|
|
char sName[64];
|
|
kv.GetSectionName(sName, sizeof(sName));
|
|
if (StrContains(sName, "tier", false) == 0)
|
|
{
|
|
strcopy(g_GroupNames[g_GroupNameCount], 64, sName);
|
|
kv.GetString("flags", g_GroupFlags[g_GroupNameCount], 32, "");
|
|
g_GroupNameCount++;
|
|
}
|
|
}
|
|
while (kv.GotoNextKey() && g_GroupNameCount < 32);
|
|
}
|
|
|
|
// now for each group, rewind and re-navigate fresh
|
|
for (int i = 0; i < g_GroupNameCount; i++)
|
|
{
|
|
kv.Rewind();
|
|
|
|
if (!kv.JumpToKey(g_GroupNames[i]))
|
|
continue;
|
|
|
|
if (!kv.JumpToKey("Overrides"))
|
|
continue;
|
|
|
|
if (!kv.GotoFirstSubKey(false))
|
|
continue;
|
|
|
|
char overrideList[512];
|
|
overrideList[0] = '\0';
|
|
|
|
do
|
|
{
|
|
char cmd[64];
|
|
kv.GetSectionName(cmd, sizeof(cmd));
|
|
if (overrideList[0] != '\0')
|
|
StrCat(overrideList, sizeof(overrideList), ", ");
|
|
StrCat(overrideList, sizeof(overrideList), cmd);
|
|
}
|
|
while (kv.GotoNextKey(false));
|
|
|
|
g_GroupOverrides.SetString(g_GroupNames[i], overrideList);
|
|
}
|
|
|
|
delete kv;
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
g_GroupOverrides = new StringMap();
|
|
LoadGroupOverrides();
|
|
if (!g_hDatabase)
|
|
{
|
|
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
|
|
}
|
|
RegConsoleCmd("sm_playtime", Command_Time, "retreives total connection time on all connected servers");
|
|
RegConsoleCmd("sm_tier", Command_Tier, "shows what tier features you have");
|
|
RegConsoleCmd("sm_tiers", Command_Tier, "shows what tier features you have");
|
|
RegConsoleCmd("sm_topplaytime", Command_TopTime, "retreives top 1000 playtime highscores on all connected servers");
|
|
|
|
g_h_time_activity = CreateTimer(10.0, time_query_activity, INVALID_HANDLE, TIMER_REPEAT);
|
|
CreateTimer(600.0, UpdateForward, _, TIMER_REPEAT);
|
|
|
|
ConVar cvar;
|
|
HookConVarChange((cvar = CreateConVar("sm_mapchooser_afk_detect_time", "120", "Time in seconds until a player is considered as AFK and therefore excluded from player average time.")), Cvar_playerAFKTime);
|
|
g_iPlayerAFKTime = cvar.IntValue;
|
|
delete cvar;
|
|
|
|
ConVar cvar2;
|
|
HookConVarChange((cvar2 = CreateConVar("sm_rtv_avg_capacity", "5", "The capacity for how many times the average a players rtv can be worth.")), Cvar_playerRTVAverageCap);
|
|
g_iPlayerRTVCapacity = cvar2.IntValue;
|
|
delete cvar2;
|
|
|
|
ConVar cvar3;
|
|
HookConVarChange((cvar3 = CreateConVar("sm_avg_hour_contribution_per_player", "5000", "How many hours maximum each player can contribute to averagehours")), Cvar_AverageHourContribution);
|
|
g_iAvgHour_Contribution_per_player = cvar3.IntValue;
|
|
delete cvar3;
|
|
|
|
ConVar cvar4;
|
|
HookConVarChange((cvar4 = CreateConVar("sv_rtv_boost_tier", "4", "which tier for giving the rtv/mapvote/nominations boost")), Cvar_RTVBoostTier);
|
|
g_iRtvBoost_tier = cvar4.IntValue;
|
|
delete cvar3;
|
|
}
|
|
|
|
public Action UpdateForward(Handle timer)
|
|
{
|
|
for (int i = 0; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !is_bot_player[i])
|
|
{
|
|
select_client_time_server(i);
|
|
}
|
|
}
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void Cvar_playerAFKTime(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
g_iPlayerAFKTime = convar.IntValue;
|
|
}
|
|
|
|
public void Cvar_playerRTVAverageCap(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
g_iPlayerRTVCapacity = convar.IntValue;
|
|
}
|
|
|
|
public void Cvar_AverageHourContribution(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
g_iAvgHour_Contribution_per_player = convar.IntValue;
|
|
}
|
|
|
|
public void Cvar_RTVBoostTier(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
g_iRtvBoost_tier = convar.IntValue;
|
|
}
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char [] error, int err_max)
|
|
{
|
|
CreateNative("GetAveragePlayerTimeOnServer", Native_GetAveragePlayerActiveTimeServer);
|
|
CreateNative("GetPlayerWorthRTV_boost_", Native_GetPlayerWorthRTV_boost);
|
|
CreateNative("GetPlayerTier_native", Native_GetPlayerTier);
|
|
|
|
g_hForwardPlayerHours = CreateGlobalForward("GetPlayerHoursServer", ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
|
|
g_hForwardPlayerTier = CreateGlobalForward("GetPlayerTier", ET_Ignore, Param_Cell, Param_Cell);
|
|
return APLRes_Success;
|
|
}
|
|
|
|
public int GetAveragePlayerActiveTimeServer()
|
|
{
|
|
int total_hours = 0;
|
|
int total_players = 0;
|
|
for (int i = 0; i < MaxClients; i++)
|
|
{
|
|
if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !is_bot_player[i] && GetClientIdleTime(i) < g_iPlayerAFKTime)
|
|
{
|
|
if (GetClientTeam(i) != CS_TEAM_T && GetClientTeam(i) != CS_TEAM_CT)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//re-introducing the hour capacity but putting it here is better than putting it at the mysql query
|
|
//at the time of making this change its only affeting me jenz and nobody else. this is meant to prevent
|
|
//the average hour from being too skewed by high playtime people.
|
|
int added_hours = g_iPlayerTimeServer[i] > g_iAvgHour_Contribution_per_player ? g_iAvgHour_Contribution_per_player : g_iPlayerTimeServer[i];
|
|
total_hours += added_hours;
|
|
total_players++;
|
|
}
|
|
}
|
|
if (total_hours == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return total_hours / total_players;
|
|
}
|
|
|
|
public int Native_GetAveragePlayerActiveTimeServer(Handle plugin, int numParams)
|
|
{
|
|
return GetAveragePlayerActiveTimeServer();
|
|
}
|
|
|
|
public int Native_GetPlayerTier(Handle plugin, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
if(client > MaxClients || client <= 0)
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid.");
|
|
return view_as<int>(-1);
|
|
}
|
|
|
|
if(!IsClientInGame(client))
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game.");
|
|
return view_as<int>(-1);
|
|
}
|
|
return g_iPlayerTier[client];
|
|
}
|
|
|
|
public int Native_GetPlayerWorthRTV_boost(Handle plugin, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
if(client > MaxClients || client <= 0)
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid.");
|
|
return view_as<int>(-1);
|
|
}
|
|
|
|
if(!IsClientInGame(client))
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game.");
|
|
return view_as<int>(-1);
|
|
}
|
|
|
|
int avg = GetAveragePlayerActiveTimeServer();
|
|
|
|
//give vips the rtv/nomination/mapvote boost by default
|
|
AdminId id = GetUserAdmin(client);
|
|
if (id != INVALID_ADMIN_ID && GetAdminFlag(id, Admin_Reservation))
|
|
{
|
|
return g_iPlayerRTVCapacity;
|
|
}
|
|
|
|
//give tier the rtv/nomination/mapvote boost
|
|
if (g_iPlayerTier[client] >= g_iRtvBoost_tier)
|
|
{
|
|
return g_iPlayerRTVCapacity;
|
|
}
|
|
|
|
if (g_iPlayerTimeServer[client] <= avg || avg == 0 || is_bot_player[client] || IsFakeClient(client))
|
|
{
|
|
return 1;
|
|
}
|
|
if ((float(g_iPlayerTimeServer[client]) / float(avg)) > g_iPlayerRTVCapacity)
|
|
{
|
|
return g_iPlayerRTVCapacity; //1.0-5.0 booster probably
|
|
}
|
|
int val = RoundToFloor((g_iPlayerTimeServer[client]) / float(avg));
|
|
if (val < 1)
|
|
{
|
|
val = 1;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
public void OnPluginEnd()
|
|
{
|
|
if (g_h_time_activity != null)
|
|
delete g_h_time_activity;
|
|
CloseHandle(g_hForwardPlayerHours);
|
|
CloseHandle(g_hForwardPlayerTier);
|
|
}
|
|
|
|
public void SQL_OnDatabaseConnect(Database db, const char[] error, any data)
|
|
{
|
|
if(!db || strlen(error))
|
|
{
|
|
LogError("Database error: %s", error);
|
|
return;
|
|
}
|
|
g_hDatabase = db;
|
|
for (int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsValidClient(i) && !IsFakeClient(i))
|
|
{
|
|
OnClientPostAdminCheck(i);
|
|
}
|
|
}
|
|
OnMapStart();
|
|
}
|
|
|
|
public void OnClientPostAdminCheck(int client)
|
|
{
|
|
g_iPlayerNextTierHours[client] = 0;
|
|
GetClientAuthId(client, AuthId_Steam2, g_csSID[client], sizeof(g_csSID[]));
|
|
is_bot_player[client] = false;
|
|
g_iPlayerTier[client] = -1;
|
|
g_iPlayerTimeServer[client] = 0;
|
|
if(!IsValidClient(client) || IsFakeClient(client))
|
|
return;
|
|
if (!g_hDatabase)
|
|
{
|
|
return;
|
|
}
|
|
insert_client(client);
|
|
select_client_time_server(client);
|
|
|
|
if (StrEqual("[U:1:1221121532]", g_csSID[client], false) || StrEqual("STEAM_0:0:610560766", g_csSID[client], false))
|
|
{
|
|
is_bot_player[client] = true;
|
|
}
|
|
if (StrEqual("[U:1:408797742]", g_csSID[client], false) || StrEqual("STEAM_0:0:204398871", g_csSID[client], false))
|
|
{
|
|
is_bot_player[client] = true;
|
|
}
|
|
if (StrEqual("[U:1:1036189204]", g_csSID[client], false) || StrEqual("STEAM_0:0:518094602", g_csSID[client], false))
|
|
{
|
|
is_bot_player[client] = true;
|
|
}
|
|
if (StrEqual("[U:1:120378081]", g_csSID[client], false) || StrEqual("STEAM_0:1:60189040", g_csSID[client], false))
|
|
{
|
|
is_bot_player[client] = true;
|
|
}
|
|
}
|
|
|
|
public void select_client_time_server(int client)
|
|
{
|
|
char sServer[32];
|
|
int i_port = GetConVarInt(FindConVar("hostport"));
|
|
if (i_port == 27015 || i_port == 27019 || i_port == 27035)
|
|
{
|
|
Format(sServer, sizeof(sServer), "ze_time");
|
|
}
|
|
else if (i_port == 27016)
|
|
{
|
|
Format(sServer, sizeof(sServer), "zr_time");
|
|
}
|
|
else if (i_port == 27017)
|
|
{
|
|
Format(sServer, sizeof(sServer), "mg_time");
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "select sum(%s) as %s_total from unloze_playtimestats.player_time pt where pt.steam_id = '%s' GROUP BY steam_id order by %s_total desc", sServer, sServer, g_csSID[client], sServer);
|
|
g_hDatabase.Query(SQL_OnQueryCompletedTimeServer, sQuery, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
|
|
public void SQL_OnQueryCompletedTimeServer(Database db, DBResultSet results, const char[] error, int iSerial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
delete results;
|
|
LogError("Query error 3: %s", error);
|
|
return;
|
|
}
|
|
int client;
|
|
if ((client = GetClientFromSerial(iSerial)) == 0)
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
|
|
int iTime_Server;
|
|
|
|
while (results.RowCount && results.FetchRow())
|
|
{
|
|
iTime_Server += results.FetchInt(0);
|
|
}
|
|
delete results;
|
|
int iHours_Server = (iTime_Server / 60) / 60;
|
|
int iMinutes_Server = (iTime_Server / 60) % 60;
|
|
g_iPlayerTimeServer[client] = iHours_Server;
|
|
|
|
Call_StartForward(g_hForwardPlayerHours);
|
|
Call_PushCell(client);
|
|
Call_PushCell(g_iPlayerTimeServer[client]);
|
|
Call_PushCell(iMinutes_Server);
|
|
Call_Finish();
|
|
|
|
if (g_iPlayerTier[client] == -1)
|
|
{
|
|
SetPlayerTier(client);
|
|
if (g_iPlayerTier[client] > 0)
|
|
{
|
|
WritePlayerTierToFile(client); //checks if all tiers have to be written
|
|
}
|
|
}
|
|
else if (check_if_client_new_tier(client)) //called every 10 minutes to fill new times from DB
|
|
{
|
|
SetPlayerTier(client);
|
|
WritePlayerTierToFile(client); //write only the new tier to the file at the end.
|
|
}
|
|
}
|
|
|
|
public void WritePlayerTierToFile(int client)
|
|
{
|
|
char sPath[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/admins_simple.ini");
|
|
|
|
// --- Read entire file into memory ---
|
|
File f = OpenFile(sPath, "r");
|
|
if (!f)
|
|
{
|
|
LogError("WritePlayerTierToFile: failed to open %s for reading", sPath);
|
|
return;
|
|
}
|
|
|
|
bool foundSeparator = false;
|
|
//always write the steamIDs as steamID 2 format.
|
|
char sSID[64];
|
|
GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
|
|
bool write_all_tiers = true;
|
|
bool write_newest_tier = false;
|
|
|
|
char line[256];
|
|
while (f.ReadLine(line, sizeof(line)))
|
|
{
|
|
int len = strlen(line);
|
|
while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
|
|
line[--len] = '\0';
|
|
|
|
if (StrEqual(line, "//here begins the unloze_play_time plugin tiers", false))
|
|
{
|
|
foundSeparator = true;
|
|
continue;
|
|
}
|
|
if (!foundSeparator)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Each line looks like: "STEAM_0:0:12345" "@tier3"
|
|
// Extract steam ID and tier number
|
|
char steamid[65];
|
|
char group[64];
|
|
|
|
int pos = 1; //skip opening quote
|
|
int sidStart = pos;
|
|
while (line[pos] != '"')
|
|
{
|
|
pos++;
|
|
}
|
|
int sidLen = pos - sidStart;
|
|
strcopy(steamid, sidLen + 1, line[sidStart]);
|
|
if (!StrEqual(steamid, sSID))
|
|
{
|
|
continue;
|
|
}
|
|
//if steam ID does not exist write all tiers
|
|
write_all_tiers = false;
|
|
write_newest_tier = true;
|
|
|
|
pos++; // skip closing quote of steamid
|
|
while (line[pos] == ' ' || line[pos] == '\t') pos++; // skip whitespace
|
|
pos++; // skip opening quote of group
|
|
|
|
int grpStart = pos;
|
|
while (line[pos] != '"') pos++;
|
|
int grpLen = pos - grpStart;
|
|
strcopy(group, grpLen + 1, line[grpStart]);
|
|
|
|
// group is "@tier3", extract tier number
|
|
char tierStr[8];
|
|
strcopy(tierStr, sizeof(tierStr), group[5]); // skip "@tier"
|
|
int tierNum = StringToInt(tierStr);
|
|
if (tierNum == g_iPlayerTier[client])
|
|
{
|
|
write_newest_tier = false;
|
|
break; //we confirmed the most recent tier was already written here.
|
|
}
|
|
}
|
|
delete f;
|
|
|
|
if (write_all_tiers)
|
|
{
|
|
// Open file for appending
|
|
File fAppend = OpenFile(sPath, "a");
|
|
|
|
for (int t = 1; t <= g_iPlayerTier[client]; t++)
|
|
{
|
|
char linewrite[256];
|
|
Format(linewrite, sizeof(linewrite), "\"%s\" \"@tier%i\"\n", sSID, t);
|
|
fAppend.WriteString(linewrite, false);
|
|
}
|
|
delete fAppend;
|
|
SetTierRewards(client);
|
|
|
|
}
|
|
else if (write_newest_tier)
|
|
{
|
|
// Open file for appending
|
|
File fAppend = OpenFile(sPath, "a");
|
|
char linewrite[256];
|
|
Format(linewrite, sizeof(linewrite), "\"%s\" \"@tier%i\"\n", sSID, g_iPlayerTier[client]);
|
|
fAppend.WriteString(linewrite, false);
|
|
delete fAppend;
|
|
SetTierRewards(client);
|
|
}
|
|
}
|
|
|
|
public bool check_if_client_new_tier(int client)
|
|
{
|
|
char sPath[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/unloze_playt_time_tiers.cfg");
|
|
|
|
KeyValues kv = new KeyValues("PlayTimeTiers");
|
|
if (!kv.ImportFromFile(sPath))
|
|
{
|
|
LogError("configs/unloze_playt_time_tiers not found");
|
|
delete kv;
|
|
return false;
|
|
}
|
|
|
|
if (!kv.GotoFirstSubKey(false))
|
|
{
|
|
LogError("configs/unloze_playt_time_tiers.cfg is empty or malformed");
|
|
delete kv;
|
|
return false;
|
|
}
|
|
|
|
bool upgrade_tier = false;
|
|
do
|
|
{
|
|
char sKey[16], sVal[16];
|
|
kv.GetSectionName(sKey, sizeof(sKey));
|
|
kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1");
|
|
|
|
int tier = StringToInt(sVal);
|
|
int hours = StringToInt(sKey);
|
|
if (hours > g_iPlayerTimeServer[client])
|
|
{
|
|
break;
|
|
}
|
|
if (tier > g_iPlayerTier[client])
|
|
{
|
|
PrintToChatAll("%N Leveled up to Tier: %i!", client, tier);
|
|
upgrade_tier = true;
|
|
}
|
|
|
|
} while (kv.GotoNextKey(false));
|
|
delete kv;
|
|
return upgrade_tier;
|
|
}
|
|
|
|
public void SetTierRewards(int client)
|
|
{
|
|
if (g_iPlayerTier[client] < 1)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 1; i <= g_iPlayerTier[client]; i++)
|
|
{
|
|
char groupname[64];
|
|
Format(groupname, sizeof(groupname), "tier%i", i);
|
|
AddClientToGroup(client, groupname);
|
|
}
|
|
}
|
|
|
|
public void AddClientToGroup(int client, const char[] groupName)
|
|
{
|
|
AdminId id = GetUserAdmin(client);
|
|
if (id == INVALID_ADMIN_ID)
|
|
{
|
|
id = CreateAdmin();
|
|
SetUserAdmin(client, id, true);
|
|
}
|
|
|
|
GroupId grp = FindAdmGroup(groupName);
|
|
if (grp == INVALID_GROUP_ID)
|
|
{
|
|
grp = CreateAdmGroup(groupName);
|
|
}
|
|
|
|
AdminInheritGroup(id, grp);
|
|
}
|
|
|
|
public void SetPlayerTier(int client)
|
|
{
|
|
char sPath[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sPath, sizeof(sPath), "configs/unloze_playt_time_tiers.cfg");
|
|
|
|
KeyValues kv = new KeyValues("PlayTimeTiers");
|
|
if (!kv.ImportFromFile(sPath))
|
|
{
|
|
LogError("configs/unloze_playt_time_tiers not found");
|
|
delete kv;
|
|
return;
|
|
}
|
|
|
|
if (!kv.GotoFirstSubKey(false))
|
|
{
|
|
LogError("configs/unloze_playt_time_tiers.cfg is empty or malformed");
|
|
delete kv;
|
|
return;
|
|
}
|
|
|
|
int next_hours = 0;
|
|
do
|
|
{
|
|
char sKey[16], sVal[16];
|
|
kv.GetSectionName(sKey, sizeof(sKey));
|
|
kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1");
|
|
|
|
int tier = StringToInt(sVal);
|
|
int hours = StringToInt(sKey);
|
|
next_hours = hours;
|
|
if (hours > g_iPlayerTimeServer[client])
|
|
{
|
|
break;
|
|
}
|
|
g_iPlayerTier[client] = tier;
|
|
|
|
} while (kv.GotoNextKey(false));
|
|
|
|
if (g_iPlayerTier[client] == -1)
|
|
{
|
|
g_iPlayerTier[client] = 0;
|
|
}
|
|
|
|
Call_StartForward(g_hForwardPlayerTier);
|
|
Call_PushCell(client);
|
|
Call_PushCell(g_iPlayerTier[client]);
|
|
Call_Finish();
|
|
if (g_iPlayerTimeServer[client] < next_hours)
|
|
{
|
|
g_iPlayerNextTierHours[client] = next_hours - g_iPlayerTimeServer[client];
|
|
PrintToChat(client, "You need %i hours to reach next tier. Check your features with !sm_tier", g_iPlayerNextTierHours[client]);
|
|
}
|
|
else
|
|
|
|
delete kv;
|
|
}
|
|
|
|
public void OnClientDisconnect(int client)
|
|
{
|
|
g_iPlayerNextTierHours[client] = 0;
|
|
g_iPlayerTier[client] = -1;
|
|
Format(g_csSID[client], sizeof(g_csSID[]), "");
|
|
is_bot_player[client] = false;
|
|
g_iPlayerTimeServer[client] = 0;
|
|
}
|
|
|
|
public void insert_client(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 sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "INSERT INTO `player_time` (`steam_id`, `ipv4`, `player_name`, `ze_time`, `mg_time`, `zr_time`, `jb_time`) VALUES ('%s', '%s', '%s', 0, 0, 0, 0) ON DUPLICATE KEY UPDATE `player_name` = '%s'", g_csSID[client], sIP, sEscapedName, sEscapedName);
|
|
g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
stock bool IsValidClient(int client)
|
|
{
|
|
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public void OnMapStart()
|
|
{
|
|
if (!g_hDatabase)
|
|
{
|
|
Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats");
|
|
return;
|
|
}
|
|
char sQuery[512];
|
|
char sServer[32];
|
|
|
|
int i_port = GetConVarInt(FindConVar("hostport"));
|
|
if (i_port == 27015 || i_port == 27019 || i_port == 27035)
|
|
{
|
|
Format(sServer, sizeof(sServer), "ze_time");
|
|
}
|
|
else if (i_port == 27016)
|
|
{
|
|
Format(sServer, sizeof(sServer), "zr_time");
|
|
}
|
|
else if (i_port == 27017)
|
|
{
|
|
Format(sServer, sizeof(sServer), "mg_time");
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
Format(sQuery, sizeof(sQuery), "select player_name, sum(%s) as %s_total from unloze_playtimestats.player_time GROUP BY steam_id order by %s_total desc limit 1000", sServer, sServer, sServer);
|
|
g_hDatabase.Query(SQL_OnQueryCompletedTopTime, sQuery);
|
|
}
|
|
|
|
public Action Command_TopTime(int client, int args)
|
|
{
|
|
char sTitle[64];
|
|
char sServer[32];
|
|
int i_port = GetConVarInt(FindConVar("hostport"));
|
|
if (i_port == 27015 || i_port == 27019 || i_port == 27035)
|
|
{
|
|
Format(sServer, sizeof(sServer), "ZE");
|
|
}
|
|
else if (i_port == 27016)
|
|
{
|
|
Format(sServer, sizeof(sServer), "ZR");
|
|
}
|
|
else if (i_port == 27017)
|
|
{
|
|
Format(sServer, sizeof(sServer), "MG");
|
|
}
|
|
else if (i_port == 27023)
|
|
{
|
|
Format(sServer, sizeof(sServer), "JB");
|
|
}
|
|
Format(sTitle, sizeof(sTitle), "[UNLOZE Playtime] Top 1000 Record Holders for %s:", sServer);
|
|
Menu menu = new Menu(MenuHandler1);
|
|
menu.SetTitle(sTitle);
|
|
for (int i = 0; i < sizeof(g_cTimeRecords); i++)
|
|
{
|
|
menu.AddItem("-1", g_cTimeRecords[i], ITEMDRAW_DISABLED);
|
|
}
|
|
menu.ExitButton = true;
|
|
menu.Display(client, 0);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void PrintClientGroupOverrides(int client)
|
|
{
|
|
char sTitle[128];
|
|
Format(sTitle, sizeof(sTitle), "Tier %i | Next tier requires %i hours.", g_iPlayerTier[client], g_iPlayerNextTierHours[client]);
|
|
Menu menu = new Menu(MenuHandler1);
|
|
menu.SetTitle(sTitle);
|
|
|
|
char rtv_boost_tier[32];
|
|
Format(rtv_boost_tier, sizeof(rtv_boost_tier), "tier%i", g_iRtvBoost_tier);
|
|
|
|
char spray_tier[32];
|
|
Format(spray_tier, sizeof(spray_tier), "tier%i", FindConVar("sm_spraymanager_tier_required").IntValue);
|
|
|
|
char entwatch_tier[32];
|
|
Format(entwatch_tier, sizeof(entwatch_tier), "tier%i", FindConVar("sm_entwatch_tier_requirement").IntValue);
|
|
|
|
char multi_nomination_tier[32];
|
|
Format(multi_nomination_tier, sizeof(multi_nomination_tier), "tier%i", FindConVar("mce_multiple_nominations_tier").IntValue);
|
|
|
|
for (int i = 0; i < g_GroupNameCount; i++)
|
|
{
|
|
char entry[128];
|
|
char overrides[512];
|
|
|
|
if (StrEqual(g_GroupNames[i], rtv_boost_tier))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: %ix Mapvote/RTV/Nomination boost", g_GroupNames[i], g_iPlayerRTVCapacity);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
if (StrEqual(g_GroupNames[i], spray_tier))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: Sprays", g_GroupNames[i]);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
if (StrEqual(g_GroupNames[i], entwatch_tier))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: Items", g_GroupNames[i]);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
if (StrEqual(g_GroupNames[i], multi_nomination_tier))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: Multiple nominations", g_GroupNames[i]);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
if (g_GroupFlags[i][0] != '\0' && StrEqual(g_GroupFlags[i], "aop"))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: VIP", g_GroupNames[i]);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
if (g_GroupOverrides.GetString(g_GroupNames[i], overrides, sizeof(overrides)))
|
|
{
|
|
Format(entry, sizeof(entry), "%s: %s", g_GroupNames[i], overrides);
|
|
menu.AddItem("-1", entry, ITEMDRAW_DISABLED);
|
|
}
|
|
}
|
|
|
|
menu.AddItem("-1", "any tier: playermodels in zclass.", ITEMDRAW_DISABLED);
|
|
menu.ExitButton = true;
|
|
menu.Display(client, 0);
|
|
}
|
|
|
|
public Action Command_Tier(int client, int args)
|
|
{
|
|
PrintClientGroupOverrides(client);
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_Time(int client, int args)
|
|
{
|
|
if (!g_hDatabase)
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "select ze_time, mg_time, zr_time, jb_time from unloze_playtimestats.player_time pt where pt.steam_id = '%s'", g_csSID[client]);
|
|
g_hDatabase.Query(SQL_OnQueryCompletedTime, sQuery, GetClientSerial(client));
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void SQL_OnQueryCompletedTopTime(Database db, DBResultSet results, const char[] error, int iSerial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
delete results;
|
|
LogError("Query error 3: %s", error);
|
|
return;
|
|
}
|
|
|
|
int iTime;
|
|
char sName[MAX_NAME_LENGTH];
|
|
int counter = 0;
|
|
while (results.RowCount && results.FetchRow())
|
|
{
|
|
char sBuffer[256];
|
|
results.FetchString(0, sName, sizeof(sName));
|
|
iTime = results.FetchInt(1);
|
|
int iHours = (iTime / 60) / 60;
|
|
Format(sBuffer, sizeof(sBuffer), "%i %s %d Hours", counter + 1, sName, iHours);
|
|
Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), sBuffer);
|
|
counter++;
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2)
|
|
{
|
|
switch(action)
|
|
{
|
|
case MenuAction_End:
|
|
{
|
|
delete menu;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public void SQL_OnQueryCompletedTime(Database db, DBResultSet results, const char[] error, int iSerial)
|
|
{
|
|
if (!db || strlen(error))
|
|
{
|
|
delete results;
|
|
LogError("Query error 3: %s", error);
|
|
return;
|
|
}
|
|
int client;
|
|
if ((client = GetClientFromSerial(iSerial)) == 0)
|
|
{
|
|
delete results;
|
|
return;
|
|
}
|
|
|
|
int iTime_ze;
|
|
int iTime_mg;
|
|
int iTime_zr;
|
|
int iTime_jb;
|
|
|
|
while (results.RowCount && results.FetchRow())
|
|
{
|
|
iTime_ze += results.FetchInt(0);
|
|
iTime_mg += results.FetchInt(1);
|
|
iTime_zr += results.FetchInt(2);
|
|
iTime_jb += results.FetchInt(3);
|
|
}
|
|
delete results;
|
|
int iHours_ze = (iTime_ze / 60) / 60;
|
|
int iMinutes_ze = (iTime_ze / 60) % 60;
|
|
int iSeconds_ze = (iTime_ze % 60);
|
|
|
|
int iHours_mg = (iTime_mg / 60) / 60;
|
|
int iMinutes_mg = (iTime_mg / 60) % 60;
|
|
int iSeconds_mg = (iTime_mg % 60);
|
|
|
|
int iHours_zr = (iTime_zr / 60) / 60;
|
|
int iMinutes_zr = (iTime_zr / 60) % 60;
|
|
int iSeconds_zr = (iTime_zr % 60);
|
|
|
|
int iHours_jb = (iTime_jb / 60) / 60;
|
|
int iMinutes_jb = (iTime_jb / 60) % 60;
|
|
int iSeconds_jb = (iTime_jb % 60);
|
|
|
|
char sTime_ze[64];
|
|
char sTime_mg[64];
|
|
char sTime_zr[64];
|
|
char sTime_jb[64];
|
|
char sTitle[64];
|
|
Format(sTitle, sizeof(sTitle), "[UNLOZE Playtime] Player %N:", client);
|
|
Format(sTime_ze, sizeof(sTime_ze), "Zombie Escape: %d Hours %d Minutes %d Seconds", iHours_ze, iMinutes_ze, iSeconds_ze);
|
|
Format(sTime_mg, sizeof(sTime_mg), "MiniGame: %d Hours %d Minutes %d Seconds", iHours_mg, iMinutes_mg, iSeconds_mg);
|
|
Format(sTime_zr, sizeof(sTime_zr), "Zombie Riot: %d Hours %d Minutes %d Seconds", iHours_zr, iMinutes_zr, iSeconds_zr);
|
|
Format(sTime_jb, sizeof(sTime_jb), "Jail Break: %d Hours %d Minutes %d Seconds", iHours_jb, iMinutes_jb, iSeconds_jb);
|
|
|
|
Panel mSayPanel = new Panel(GetMenuStyleHandle(MenuStyle_Radio));
|
|
|
|
mSayPanel.SetTitle(sTitle);
|
|
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
mSayPanel.DrawText(sTime_ze);
|
|
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
mSayPanel.DrawText(sTime_mg);
|
|
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
mSayPanel.DrawText(sTime_zr);
|
|
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
mSayPanel.DrawText(sTime_jb);
|
|
mSayPanel.DrawItem("", ITEMDRAW_SPACER);
|
|
mSayPanel.DrawItem("1. Got it!", ITEMDRAW_RAWLINE);
|
|
mSayPanel.SetKeys(1023);
|
|
|
|
mSayPanel.Send(client, Handler_Menu, 0);
|
|
delete mSayPanel;
|
|
}
|
|
|
|
public int Handler_Menu(Menu menu, MenuAction action, int param1, int param2)
|
|
{
|
|
switch(action)
|
|
{
|
|
case MenuAction_Select, MenuAction_Cancel:
|
|
delete menu;
|
|
}
|
|
return 0;
|
|
}
|